@webstudio-is/react-sdk 0.94.0 → 0.96.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/lib/css/normalize.js +127 -53
  2. package/lib/index.js +1843 -32
  3. package/lib/types/index.d.ts +0 -1
  4. package/package.json +10 -9
  5. package/lib/app/index.js +0 -2
  6. package/lib/app/root.js +0 -18
  7. package/lib/component-renderer.js +0 -130
  8. package/lib/components/component-meta.js +0 -62
  9. package/lib/components/components-utils.js +0 -2
  10. package/lib/context.js +0 -21
  11. package/lib/css/css.js +0 -59
  12. package/lib/css/global-rules.js +0 -15
  13. package/lib/css/index.js +0 -4
  14. package/lib/css/normalize-type-check.js +0 -4
  15. package/lib/css/presets.js +0 -25
  16. package/lib/css/style-rules.js +0 -63
  17. package/lib/css/style-rules.test.js +0 -149
  18. package/lib/embed-template.js +0 -341
  19. package/lib/embed-template.test.js +0 -648
  20. package/lib/expression.js +0 -330
  21. package/lib/expression.test.js +0 -281
  22. package/lib/generator.js +0 -112
  23. package/lib/generator.test.js +0 -166
  24. package/lib/hook.js +0 -12
  25. package/lib/hook.test.js +0 -15
  26. package/lib/instance-utils.js +0 -43
  27. package/lib/instance-utils.test.js +0 -65
  28. package/lib/prop-meta.js +0 -150
  29. package/lib/props.js +0 -176
  30. package/lib/props.test.js +0 -159
  31. package/lib/pubsub/create.js +0 -56
  32. package/lib/pubsub/index.js +0 -2
  33. package/lib/pubsub/raf-queue.js +0 -20
  34. package/lib/tree/create-elements-tree.js +0 -134
  35. package/lib/tree/index.js +0 -4
  36. package/lib/tree/root.js +0 -85
  37. package/lib/tree/webstudio-component.js +0 -61
  38. package/lib/types/pubsub/create.d.ts +0 -28
  39. package/lib/types/pubsub/index.d.ts +0 -1
  40. package/lib/types/pubsub/raf-queue.d.ts +0 -1
@@ -1,6 +1,5 @@
1
1
  export * from "./css";
2
2
  export * from "./tree";
3
- export * from "./pubsub";
4
3
  export * from "./app";
5
4
  export * from "./components/components-utils";
6
5
  export { PropMeta } from "./prop-meta";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webstudio-is/react-sdk",
3
- "version": "0.94.0",
3
+ "version": "0.96.0",
4
4
  "description": "Webstudio JavaScript / TypeScript API",
5
5
  "author": "Webstudio <github@webstudio.is>",
6
6
  "homepage": "https://webstudio.is",
@@ -30,25 +30,26 @@
30
30
  "@nanostores/react": "^0.7.1",
31
31
  "html-tags": "^3.3.1",
32
32
  "jsep": "^1.3.8",
33
- "nanoevents": "^8.0.0",
34
33
  "nanoid": "^4.0.2",
35
34
  "nanostores": "^0.9.3",
36
35
  "no-case": "^3.0.4",
37
36
  "title-case": "^3.0.3",
38
- "@webstudio-is/css-engine": "^0.94.0",
39
- "@webstudio-is/fonts": "^0.94.0",
40
- "@webstudio-is/sdk": "^0.94.0"
37
+ "@webstudio-is/css-engine": "^0.96.0",
38
+ "@webstudio-is/fonts": "^0.96.0",
39
+ "@webstudio-is/sdk": "^0.96.0"
41
40
  },
42
41
  "exports": {
43
42
  ".": {
44
43
  "source": "./src/index.ts",
45
44
  "types": "./lib/types/index.d.ts",
46
- "import": "./lib/index.js"
45
+ "import": "./lib/index.js",
46
+ "require": "./lib/index.js"
47
47
  },
48
48
  "./css-normalize": {
49
49
  "source": "./src/css/normalize.ts",
50
50
  "types": "./lib/types/css/normalize.d.ts",
51
- "import": "./lib/css/normalize.js"
51
+ "import": "./lib/css/normalize.js",
52
+ "require": "./lib/css/normalize.js"
52
53
  }
53
54
  },
54
55
  "files": [
@@ -59,8 +60,8 @@
59
60
  "private": false,
60
61
  "sideEffects": false,
61
62
  "scripts": {
62
- "dev": "pnpm build --watch",
63
- "build": "rm -rf lib && esbuild 'src/**/*.ts' 'src/**/*.tsx' --outdir=lib",
63
+ "dev": "rm -rf lib && esbuild 'src/**/*.ts' 'src/**/*.tsx' --outdir=lib --watch",
64
+ "build": "rm -rf lib && esbuild src/index.ts ./src/css/normalize.ts --outdir=lib --bundle --format=esm --packages=external",
64
65
  "dts": "tsc --project tsconfig.dts.json",
65
66
  "typecheck": "tsc",
66
67
  "test": "NODE_OPTIONS=--experimental-vm-modules jest --passWithNoTests",
package/lib/app/index.js DELETED
@@ -1,2 +0,0 @@
1
- "use strict";
2
- export * from "./root";
package/lib/app/root.js DELETED
@@ -1,18 +0,0 @@
1
- "use strict";
2
- import { jsx, jsxs } from "react/jsx-runtime";
3
- import { Links, Meta, Outlet as DefaultOutlet } from "@remix-run/react";
4
- export const Root = ({
5
- Outlet = DefaultOutlet
6
- }) => {
7
- return /* @__PURE__ */ jsxs("html", { lang: "en", children: [
8
- /* @__PURE__ */ jsxs("head", { children: [
9
- /* @__PURE__ */ jsx("meta", { charSet: "utf-8" }),
10
- /* @__PURE__ */ jsx("meta", { name: "viewport", content: "width=device-width,initial-scale=1" }),
11
- /* @__PURE__ */ jsx("link", { rel: "icon", href: "/favicon.ico", type: "image/x-icon" }),
12
- /* @__PURE__ */ jsx("link", { rel: "shortcut icon", href: "/favicon.ico", type: "image/x-icon" }),
13
- /* @__PURE__ */ jsx(Meta, {}),
14
- /* @__PURE__ */ jsx(Links, {})
15
- ] }),
16
- /* @__PURE__ */ jsx(Outlet, {})
17
- ] });
18
- };
@@ -1,130 +0,0 @@
1
- "use strict";
2
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
- import { getStyleDeclKey } from "@webstudio-is/sdk";
4
- import {
5
- WsEmbedTemplate,
6
- generateDataFromEmbedTemplate
7
- } from "./embed-template";
8
- import { generateCssText } from "./css";
9
- import { InstanceRoot, WebstudioComponent } from "./tree";
10
- import {
11
- decodeVariablesMap,
12
- encodeDataSourceVariable,
13
- encodeVariablesMap,
14
- executeComputingExpressions,
15
- executeEffectfulExpression
16
- } from "./expression";
17
- import { getIndexesWithinAncestors } from "./instance-utils";
18
- export const renderComponentTemplate = ({
19
- name,
20
- metas: metasRecord,
21
- components,
22
- props
23
- }) => {
24
- const metas = new Map(Object.entries(metasRecord));
25
- const template = metas.get(name)?.template ?? [
26
- {
27
- type: "instance",
28
- component: name,
29
- children: []
30
- }
31
- ];
32
- if (template[0].type === "instance" && props !== void 0) {
33
- template[0].props = Object.entries(props).map(([prop, value]) => {
34
- if (typeof value === "string") {
35
- return { type: "string", name: prop, value };
36
- }
37
- if (typeof value === "number") {
38
- return { type: "number", name: prop, value };
39
- }
40
- if (typeof value === "boolean") {
41
- return { type: "boolean", name: prop, value };
42
- }
43
- throw new Error(`Unsupported prop ${props} with value ${value}`);
44
- });
45
- }
46
- const data = generateDataFromEmbedTemplate(template, metas, "base");
47
- const instances = [
48
- [
49
- "root",
50
- {
51
- type: "instance",
52
- id: "root",
53
- component: "Box",
54
- children: data.children
55
- }
56
- ],
57
- ...data.instances.map(
58
- (instance) => [instance.id, instance]
59
- )
60
- ];
61
- return /* @__PURE__ */ jsxs(Fragment, { children: [
62
- /* @__PURE__ */ jsx("style", { children: generateCssText(
63
- {
64
- assets: [],
65
- breakpoints: [["base", { id: "base", label: "base" }]],
66
- styles: data.styles.map((item) => [getStyleDeclKey(item), item]),
67
- styleSourceSelections: data.styleSourceSelections.map((item) => [
68
- item.instanceId,
69
- item
70
- ]),
71
- componentMetas: metas
72
- },
73
- { assetBaseUrl: "/" }
74
- ) }),
75
- /* @__PURE__ */ jsx(
76
- InstanceRoot,
77
- {
78
- data: {
79
- page: {
80
- path: "",
81
- id: "",
82
- name: "",
83
- title: "",
84
- meta: {},
85
- rootInstanceId: "root"
86
- },
87
- pages: [],
88
- assets: [],
89
- build: {
90
- instances,
91
- props: data.props.map((prop) => [prop.id, prop]),
92
- dataSources: data.dataSources.map((dataSource) => [
93
- dataSource.id,
94
- dataSource
95
- ])
96
- }
97
- },
98
- utils: {
99
- indexesWithinAncestors: getIndexesWithinAncestors(
100
- metas,
101
- new Map(instances),
102
- ["root"]
103
- ),
104
- executeComputingExpressions: (values) => {
105
- const expressions = /* @__PURE__ */ new Map();
106
- for (const dataSource of data.dataSources) {
107
- const name2 = encodeDataSourceVariable(dataSource.id);
108
- if (dataSource.type === "expression") {
109
- expressions.set(name2, dataSource.code);
110
- }
111
- }
112
- return decodeVariablesMap(
113
- executeComputingExpressions(
114
- expressions,
115
- encodeVariablesMap(values)
116
- )
117
- );
118
- },
119
- executeEffectfulExpression: (code, args, values) => {
120
- return decodeVariablesMap(
121
- executeEffectfulExpression(code, args, encodeVariablesMap(values))
122
- );
123
- }
124
- },
125
- Component: WebstudioComponent,
126
- components: new Map(Object.entries(components))
127
- }
128
- )
129
- ] });
130
- };
@@ -1,62 +0,0 @@
1
- "use strict";
2
- import { z } from "zod";
3
- import { PropMeta } from "../prop-meta";
4
- import { EmbedTemplateStyleDecl, WsEmbedTemplate } from "../embed-template";
5
- const WsComponentPropsMeta = z.object({
6
- props: z.record(PropMeta),
7
- // Props that will be always visible in properties panel.
8
- initialProps: z.array(z.string()).optional()
9
- });
10
- export const componentCategories = [
11
- "general",
12
- "text",
13
- "media",
14
- "forms",
15
- "radix",
16
- "hidden"
17
- ];
18
- export const stateCategories = ["states", "component-states"];
19
- export const ComponentState = z.object({
20
- category: z.enum(stateCategories).optional(),
21
- selector: z.string(),
22
- label: z.string()
23
- });
24
- const ComponentToken = z.object({
25
- variant: z.optional(z.string()),
26
- styles: z.array(EmbedTemplateStyleDecl)
27
- });
28
- export const defaultStates = [
29
- { selector: ":hover", label: "Hover" },
30
- { selector: ":active", label: "Active" },
31
- { selector: ":focus", label: "Focus" },
32
- { selector: ":focus-visible", label: "Focus Visible" },
33
- { selector: ":focus-within", label: "Focus Within" }
34
- ];
35
- const WsComponentMeta = z.object({
36
- category: z.enum(componentCategories).optional(),
37
- // container - can accept other components with dnd or be edited as text
38
- // control - usually form controls like inputs, without children
39
- // embed - images, videos or other embeddable components, without children
40
- // rich-text-child - formatted text fragment, not listed in components list
41
- type: z.enum(["container", "control", "embed", "rich-text-child"]),
42
- requiredAncestors: z.optional(z.array(z.string())),
43
- invalidAncestors: z.optional(z.array(z.string())),
44
- // when this field is specified component receives
45
- // prop with index of same components withiin specified ancestor
46
- // important to automatically enumerate collections without
47
- // naming every item manually
48
- indexWithinAncestor: z.optional(z.string()),
49
- stylable: z.optional(z.boolean()),
50
- // specifies whether the instance can be deleted,
51
- // copied or dragged out of its parent instance
52
- // true by default
53
- detachable: z.optional(z.boolean()),
54
- label: z.optional(z.string()),
55
- description: z.string().optional(),
56
- icon: z.string(),
57
- presetStyle: z.optional(z.record(z.string(), EmbedTemplateStyleDecl)),
58
- presetTokens: z.optional(z.record(z.string(), ComponentToken)),
59
- states: z.optional(z.array(ComponentState)),
60
- template: z.optional(WsEmbedTemplate),
61
- order: z.number().optional()
62
- });
@@ -1,2 +0,0 @@
1
- "use strict";
2
- import { componentAttribute, idAttribute } from "../tree";
package/lib/context.js DELETED
@@ -1,21 +0,0 @@
1
- "use strict";
2
- import { atom } from "nanostores";
3
- import { createContext } from "react";
4
- export const ReactSdkContext = createContext({
5
- imageBaseUrl: "/",
6
- assetBaseUrl: "/",
7
- propsByInstanceIdStore: atom(/* @__PURE__ */ new Map()),
8
- assetsStore: atom(/* @__PURE__ */ new Map()),
9
- pagesStore: atom(/* @__PURE__ */ new Map()),
10
- dataSourceValuesStore: atom(/* @__PURE__ */ new Map()),
11
- executeEffectfulExpression: () => {
12
- throw Error("React SDK executeEffectfulExpression is not implemented");
13
- },
14
- setDataSourceValues: () => {
15
- throw Error("React SDK setBoundDataSourceValue is not implemented");
16
- },
17
- setBoundDataSourceValue: () => {
18
- throw Error("React SDK setBoundDataSourceValue is not implemented");
19
- },
20
- indexesWithinAncestors: /* @__PURE__ */ new Map()
21
- });
package/lib/css/css.js DELETED
@@ -1,59 +0,0 @@
1
- "use strict";
2
- import { createCssEngine } from "@webstudio-is/css-engine";
3
- import { idAttribute } from "../tree";
4
- import { addGlobalRules } from "./global-rules";
5
- import { getPresetStyleRules, getStyleRules } from "./style-rules";
6
- export const createImageValueTransformer = (assets, options) => (styleValue) => {
7
- if (styleValue.type === "image" && styleValue.value.type === "asset") {
8
- const asset = assets.get(styleValue.value.value);
9
- if (asset === void 0) {
10
- return { type: "keyword", value: "none" };
11
- }
12
- const { assetBaseUrl } = options;
13
- const url = `${assetBaseUrl}${asset.name}`;
14
- return {
15
- type: "image",
16
- value: {
17
- type: "url",
18
- url
19
- },
20
- hidden: styleValue.hidden
21
- };
22
- }
23
- };
24
- export const generateCssText = (data, options) => {
25
- const assets = new Map(data.assets.map((asset) => [asset.id, asset]));
26
- const breakpoints = new Map(data.breakpoints);
27
- const styles = new Map(data.styles);
28
- const styleSourceSelections = new Map(data.styleSourceSelections);
29
- const engine = createCssEngine({ name: "ssr" });
30
- addGlobalRules(engine, {
31
- assets,
32
- assetBaseUrl: options.assetBaseUrl
33
- });
34
- for (const breakpoint of breakpoints.values()) {
35
- engine.addMediaRule(breakpoint.id, breakpoint);
36
- }
37
- for (const [component, meta] of data.componentMetas) {
38
- const presetStyle = meta.presetStyle;
39
- if (presetStyle === void 0) {
40
- continue;
41
- }
42
- const rules = getPresetStyleRules(component, presetStyle);
43
- for (const [selector, style] of rules) {
44
- engine.addStyleRule(selector, { style });
45
- }
46
- }
47
- const styleRules = getStyleRules(styles, styleSourceSelections);
48
- for (const { breakpointId, instanceId, state, style } of styleRules) {
49
- engine.addStyleRule(
50
- `[${idAttribute}="${instanceId}"]${state ?? ""}`,
51
- {
52
- breakpoint: breakpointId,
53
- style
54
- },
55
- createImageValueTransformer(assets, options)
56
- );
57
- }
58
- return engine.cssText;
59
- };
@@ -1,15 +0,0 @@
1
- "use strict";
2
- import { getFontFaces } from "@webstudio-is/fonts";
3
- export const addGlobalRules = (engine, { assets, assetBaseUrl }) => {
4
- engine.addPlaintextRule("html {margin: 0; display: grid; min-height: 100%}");
5
- const fontAssets = [];
6
- for (const asset of assets.values()) {
7
- if (asset.type === "font") {
8
- fontAssets.push(asset);
9
- }
10
- }
11
- const fontFaces = getFontFaces(fontAssets, { assetBaseUrl });
12
- for (const fontFace of fontFaces) {
13
- engine.addFontFaceRule(fontFace);
14
- }
15
- };
package/lib/css/index.js DELETED
@@ -1,4 +0,0 @@
1
- "use strict";
2
- export * from "./global-rules";
3
- export * from "./style-rules";
4
- export * from "./css";
@@ -1,4 +0,0 @@
1
- "use strict";
2
- import * as normalize from "./normalize";
3
- const normalizeWithKeyof = { ...normalize };
4
- normalizeWithKeyof;
@@ -1,25 +0,0 @@
1
- "use strict";
2
- export const borders = [
3
- {
4
- property: "borderTopWidth",
5
- value: { type: "unit", value: 1, unit: "px" }
6
- },
7
- {
8
- property: "borderRightWidth",
9
- value: { type: "unit", value: 1, unit: "px" }
10
- },
11
- {
12
- property: "borderBottomWidth",
13
- value: { type: "unit", value: 1, unit: "px" }
14
- },
15
- {
16
- property: "borderLeftWidth",
17
- value: { type: "unit", value: 1, unit: "px" }
18
- }
19
- ];
20
- export const outline = [
21
- {
22
- property: "outlineWidth",
23
- value: { type: "unit", value: 1, unit: "px" }
24
- }
25
- ];
@@ -1,63 +0,0 @@
1
- "use strict";
2
- import { componentAttribute } from "../tree";
3
- export const getStyleRules = (styles, styleSourceSelections) => {
4
- if (styles === void 0 || styleSourceSelections === void 0) {
5
- return [];
6
- }
7
- const stylesByStyleSourceId = /* @__PURE__ */ new Map();
8
- for (const styleDecl of styles.values()) {
9
- const { styleSourceId } = styleDecl;
10
- let styleSourceStyles = stylesByStyleSourceId.get(styleSourceId);
11
- if (styleSourceStyles === void 0) {
12
- styleSourceStyles = [];
13
- stylesByStyleSourceId.set(styleSourceId, styleSourceStyles);
14
- }
15
- styleSourceStyles.push(styleDecl);
16
- }
17
- const styleRules = [];
18
- for (const { instanceId, values } of styleSourceSelections.values()) {
19
- const styleRuleByBreakpointId = /* @__PURE__ */ new Map();
20
- for (const styleSourceId of values) {
21
- const styleSourceStyles = stylesByStyleSourceId.get(styleSourceId);
22
- if (styleSourceStyles === void 0) {
23
- continue;
24
- }
25
- for (const {
26
- breakpointId,
27
- state,
28
- property,
29
- value
30
- } of styleSourceStyles) {
31
- const key = `${breakpointId}:${state ?? ""}`;
32
- let styleRule = styleRuleByBreakpointId.get(key);
33
- if (styleRule === void 0) {
34
- styleRule = {
35
- instanceId,
36
- breakpointId,
37
- state,
38
- style: {}
39
- };
40
- styleRuleByBreakpointId.set(key, styleRule);
41
- }
42
- styleRule.style[property] = value;
43
- }
44
- }
45
- styleRules.push(...styleRuleByBreakpointId.values());
46
- }
47
- return styleRules;
48
- };
49
- export const getPresetStyleRules = (component, presetStyle) => {
50
- const presetStyleRules = /* @__PURE__ */ new Map();
51
- for (const [tag, styles] of Object.entries(presetStyle)) {
52
- for (const styleDecl of styles) {
53
- const selector = `${tag}:where([${componentAttribute}="${component}"])${styleDecl.state ?? ""}`;
54
- let rule = presetStyleRules.get(selector);
55
- if (rule === void 0) {
56
- rule = {};
57
- presetStyleRules.set(selector, rule);
58
- }
59
- rule[styleDecl.property] = styleDecl.value;
60
- }
61
- }
62
- return presetStyleRules;
63
- };
@@ -1,149 +0,0 @@
1
- "use strict";
2
- import { test, expect } from "@jest/globals";
3
- import {
4
- getStyleDeclKey
5
- } from "@webstudio-is/sdk";
6
- import { getStyleRules } from "./style-rules";
7
- const createStyleDeclPair = (styleDecl) => {
8
- return [getStyleDeclKey(styleDecl), styleDecl];
9
- };
10
- test("compute styles from different style sources", () => {
11
- const styles = new Map([
12
- createStyleDeclPair({
13
- breakpointId: "a",
14
- styleSourceId: "styleSource1",
15
- property: "width",
16
- value: { type: "unit", value: 10, unit: "px" }
17
- }),
18
- createStyleDeclPair({
19
- breakpointId: "a",
20
- styleSourceId: "styleSource2",
21
- property: "display",
22
- value: { type: "keyword", value: "block" }
23
- }),
24
- createStyleDeclPair({
25
- breakpointId: "a",
26
- styleSourceId: "styleSource4",
27
- property: "color",
28
- value: { type: "keyword", value: "green" }
29
- }),
30
- createStyleDeclPair({
31
- breakpointId: "a",
32
- styleSourceId: "styleSource4",
33
- property: "width",
34
- value: { type: "keyword", value: "min-content" }
35
- }),
36
- createStyleDeclPair({
37
- breakpointId: "a",
38
- styleSourceId: "styleSource3",
39
- property: "color",
40
- value: { type: "keyword", value: "red" }
41
- }),
42
- createStyleDeclPair({
43
- breakpointId: "b",
44
- styleSourceId: "styleSource5",
45
- property: "color",
46
- value: { type: "keyword", value: "orange" }
47
- }),
48
- createStyleDeclPair({
49
- breakpointId: "a",
50
- styleSourceId: "styleSource6",
51
- property: "color",
52
- value: { type: "keyword", value: "blue" }
53
- }),
54
- createStyleDeclPair({
55
- breakpointId: "a",
56
- styleSourceId: "styleSource6",
57
- state: ":hover",
58
- property: "color",
59
- value: { type: "keyword", value: "blue" }
60
- })
61
- ]);
62
- const styleSourceSelections = /* @__PURE__ */ new Map([
63
- [
64
- "instance1",
65
- {
66
- instanceId: "instance1",
67
- values: ["styleSource1"]
68
- }
69
- ],
70
- [
71
- "instance2",
72
- {
73
- instanceId: "instance2",
74
- values: ["styleSource4", "styleSource5", "styleSource3"]
75
- }
76
- ],
77
- [
78
- "instance3",
79
- {
80
- instanceId: "instance3",
81
- values: ["styleSource6"]
82
- }
83
- ]
84
- ]);
85
- expect(getStyleRules(styles, styleSourceSelections)).toMatchInlineSnapshot(`
86
- [
87
- {
88
- "breakpointId": "a",
89
- "instanceId": "instance1",
90
- "state": undefined,
91
- "style": {
92
- "width": {
93
- "type": "unit",
94
- "unit": "px",
95
- "value": 10,
96
- },
97
- },
98
- },
99
- {
100
- "breakpointId": "a",
101
- "instanceId": "instance2",
102
- "state": undefined,
103
- "style": {
104
- "color": {
105
- "type": "keyword",
106
- "value": "red",
107
- },
108
- "width": {
109
- "type": "keyword",
110
- "value": "min-content",
111
- },
112
- },
113
- },
114
- {
115
- "breakpointId": "b",
116
- "instanceId": "instance2",
117
- "state": undefined,
118
- "style": {
119
- "color": {
120
- "type": "keyword",
121
- "value": "orange",
122
- },
123
- },
124
- },
125
- {
126
- "breakpointId": "a",
127
- "instanceId": "instance3",
128
- "state": undefined,
129
- "style": {
130
- "color": {
131
- "type": "keyword",
132
- "value": "blue",
133
- },
134
- },
135
- },
136
- {
137
- "breakpointId": "a",
138
- "instanceId": "instance3",
139
- "state": ":hover",
140
- "style": {
141
- "color": {
142
- "type": "keyword",
143
- "value": "blue",
144
- },
145
- },
146
- },
147
- ]
148
- `);
149
- });