@webstudio-is/react-sdk 0.53.0 → 0.55.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.
@@ -19,7 +19,7 @@ const Image = forwardRef(
19
19
  if (asset.location === "REMOTE") {
20
20
  return loaders.cloudflareImageLoader(params);
21
21
  }
22
- return loaders.localImageLoader();
22
+ return loaders.localImageLoader(params);
23
23
  }, [asset, params]);
24
24
  let src = props.src;
25
25
  if (asset != null) {
@@ -39,7 +39,7 @@ const Image = (0, import_react.forwardRef)(
39
39
  if (asset.location === "REMOTE") {
40
40
  return import_image.loaders.cloudflareImageLoader(params);
41
41
  }
42
- return import_image.loaders.localImageLoader();
42
+ return import_image.loaders.localImageLoader(params);
43
43
  }, [asset, params]);
44
44
  let src = props.src;
45
45
  if (asset != null) {
@@ -93,6 +93,5 @@ const meta = {
93
93
  children: ["Blockquote you can edit"]
94
94
  };
95
95
  const propsMeta = {
96
- props: import_blockquote.props,
97
- initialProps: ["tag"]
96
+ props: import_blockquote.props
98
97
  };
@@ -54,7 +54,7 @@ const propsMeta = {
54
54
  ...import_image.props,
55
55
  src: {
56
56
  type: "string",
57
- control: "file-image",
57
+ control: "file",
58
58
  label: "Source",
59
59
  required: false
60
60
  }
@@ -18,6 +18,7 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var css_exports = {};
20
20
  __export(css_exports, {
21
+ createImageValueTransformer: () => createImageValueTransformer,
21
22
  generateCssText: () => generateCssText
22
23
  });
23
24
  module.exports = __toCommonJS(css_exports);
@@ -27,7 +28,25 @@ var import_components = require("../components");
27
28
  var import_tree = require("../tree");
28
29
  var import_global_rules = require("./global-rules");
29
30
  var import_style_rules = require("./style-rules");
30
- const generateCssText = (data) => {
31
+ const createImageValueTransformer = (assets, options) => (styleValue) => {
32
+ if (styleValue.type === "image" && styleValue.value.type === "asset") {
33
+ const asset = assets.get(styleValue.value.value);
34
+ if (asset === void 0) {
35
+ return { type: "keyword", value: "none" };
36
+ }
37
+ const { publicPath = "/" } = options;
38
+ const url = asset.location === "REMOTE" ? asset.path : `${publicPath}${asset.name}`;
39
+ return {
40
+ type: "image",
41
+ value: {
42
+ type: "url",
43
+ url
44
+ },
45
+ hidden: styleValue.hidden
46
+ };
47
+ }
48
+ };
49
+ const generateCssText = (data, options) => {
31
50
  const assets = new Map(
32
51
  data.assets.map((asset) => [asset.id, asset])
33
52
  );
@@ -55,10 +74,14 @@ const generateCssText = (data) => {
55
74
  }
56
75
  const styleRules = (0, import_style_rules.getStyleRules)(styles, styleSourceSelections);
57
76
  for (const { breakpointId, instanceId, style } of styleRules) {
58
- engine.addStyleRule(`[${import_tree.idAttribute}="${instanceId}"]`, {
59
- breakpoint: breakpointId,
60
- style
61
- });
77
+ engine.addStyleRule(
78
+ `[${import_tree.idAttribute}="${instanceId}"]`,
79
+ {
80
+ breakpoint: breakpointId,
81
+ style
82
+ },
83
+ createImageValueTransformer(assets, options)
84
+ );
62
85
  }
63
86
  return engine.cssText;
64
87
  };
@@ -27,24 +27,30 @@ var import_react2 = require("@remix-run/react");
27
27
  var import_context = require("../context");
28
28
  var import_session_storage_polyfill = require("./session-storage-polyfill");
29
29
  const createElementsTree = ({
30
+ instances,
31
+ rootInstanceId,
30
32
  sandbox,
31
- instance,
32
33
  propsByInstanceIdStore,
33
34
  assetsStore,
34
35
  pagesStore,
35
36
  Component,
36
37
  getComponent
37
38
  }) => {
38
- const rootInstanceSelector = [instance.id];
39
+ const rootInstance = instances.get(rootInstanceId);
40
+ if (rootInstance === void 0) {
41
+ return null;
42
+ }
43
+ const rootInstanceSelector = [rootInstanceId];
39
44
  const children = createInstanceChildrenElements({
45
+ instances,
40
46
  instanceSelector: rootInstanceSelector,
41
47
  Component,
42
- children: instance.children,
48
+ children: rootInstance.children,
43
49
  getComponent
44
50
  });
45
51
  const root = createInstanceElement({
46
52
  Component,
47
- instance,
53
+ instance: rootInstance,
48
54
  instanceSelector: rootInstanceSelector,
49
55
  children: [
50
56
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react.Fragment, { children: [
@@ -65,6 +71,7 @@ const createElementsTree = ({
65
71
  );
66
72
  };
67
73
  const createInstanceChildrenElements = ({
74
+ instances,
68
75
  instanceSelector,
69
76
  children,
70
77
  Component,
@@ -76,15 +83,20 @@ const createInstanceChildrenElements = ({
76
83
  elements.push(child.value);
77
84
  continue;
78
85
  }
79
- const childInstanceSelector = [child.id, ...instanceSelector];
86
+ const childInstance = instances.get(child.value);
87
+ if (childInstance === void 0) {
88
+ continue;
89
+ }
90
+ const childInstanceSelector = [child.value, ...instanceSelector];
80
91
  const children2 = createInstanceChildrenElements({
92
+ instances,
81
93
  instanceSelector: childInstanceSelector,
82
- children: child.children,
94
+ children: childInstance.children,
83
95
  Component,
84
96
  getComponent
85
97
  });
86
98
  const element = createInstanceElement({
87
- instance: child,
99
+ instance: childInstance,
88
100
  instanceSelector: childInstanceSelector,
89
101
  Component,
90
102
  children: children2,
@@ -28,32 +28,6 @@ var import_components = require("../components");
28
28
  var import_custom_components = require("../app/custom-components");
29
29
  var import_params = require("../app/params");
30
30
  var import_props = require("../props");
31
- const denormalizeTree = (instances, rootInstanceId) => {
32
- const convertTree = (instance) => {
33
- const legacyInstance = {
34
- type: "instance",
35
- id: instance.id,
36
- component: instance.component,
37
- children: []
38
- };
39
- for (const child of instance.children) {
40
- if (child.type === "id") {
41
- const childInstance = instances.get(child.value);
42
- if (childInstance) {
43
- legacyInstance.children.push(convertTree(childInstance));
44
- }
45
- } else {
46
- legacyInstance.children.push(child);
47
- }
48
- }
49
- return legacyInstance;
50
- };
51
- const rootInstance = instances.get(rootInstanceId);
52
- if (rootInstance === void 0) {
53
- return void 0;
54
- }
55
- return convertTree(rootInstance);
56
- };
57
31
  const InstanceRoot = ({
58
32
  data,
59
33
  Component,
@@ -62,15 +36,9 @@ const InstanceRoot = ({
62
36
  }) => {
63
37
  (0, import_params.setParams)(data.params ?? null);
64
38
  (0, import_components.registerComponents)(customComponents);
65
- const instance = denormalizeTree(
66
- new Map(data.build.instances),
67
- data.page.rootInstanceId
68
- );
69
- if (instance === void 0) {
70
- return null;
71
- }
72
39
  return (0, import_create_elements_tree.createElementsTree)({
73
- instance,
40
+ instances: new Map(data.build.instances),
41
+ rootInstanceId: data.page.rootInstanceId,
74
42
  propsByInstanceIdStore: (0, import_nanostores.atom)(
75
43
  (0, import_props.getPropsByInstanceId)(new Map(data.build.props))
76
44
  ),
@@ -69,8 +69,7 @@ const meta = {
69
69
  children: ["Blockquote you can edit"]
70
70
  };
71
71
  const propsMeta = {
72
- props,
73
- initialProps: ["tag"]
72
+ props
74
73
  };
75
74
  export {
76
75
  meta,
@@ -30,7 +30,7 @@ const propsMeta = {
30
30
  ...props,
31
31
  src: {
32
32
  type: "string",
33
- control: "file-image",
33
+ control: "file",
34
34
  label: "Source",
35
35
  required: false
36
36
  }
package/lib/css/css.js CHANGED
@@ -4,7 +4,25 @@ import { getComponentMeta } from "../components";
4
4
  import { componentAttribute, idAttribute } from "../tree";
5
5
  import { addGlobalRules } from "./global-rules";
6
6
  import { getStyleRules } from "./style-rules";
7
- const generateCssText = (data) => {
7
+ const createImageValueTransformer = (assets, options) => (styleValue) => {
8
+ if (styleValue.type === "image" && styleValue.value.type === "asset") {
9
+ const asset = assets.get(styleValue.value.value);
10
+ if (asset === void 0) {
11
+ return { type: "keyword", value: "none" };
12
+ }
13
+ const { publicPath = "/" } = options;
14
+ const url = asset.location === "REMOTE" ? asset.path : `${publicPath}${asset.name}`;
15
+ return {
16
+ type: "image",
17
+ value: {
18
+ type: "url",
19
+ url
20
+ },
21
+ hidden: styleValue.hidden
22
+ };
23
+ }
24
+ };
25
+ const generateCssText = (data, options) => {
8
26
  const assets = new Map(
9
27
  data.assets.map((asset) => [asset.id, asset])
10
28
  );
@@ -32,13 +50,18 @@ const generateCssText = (data) => {
32
50
  }
33
51
  const styleRules = getStyleRules(styles, styleSourceSelections);
34
52
  for (const { breakpointId, instanceId, style } of styleRules) {
35
- engine.addStyleRule(`[${idAttribute}="${instanceId}"]`, {
36
- breakpoint: breakpointId,
37
- style
38
- });
53
+ engine.addStyleRule(
54
+ `[${idAttribute}="${instanceId}"]`,
55
+ {
56
+ breakpoint: breakpointId,
57
+ style
58
+ },
59
+ createImageValueTransformer(assets, options)
60
+ );
39
61
  }
40
62
  return engine.cssText;
41
63
  };
42
64
  export {
65
+ createImageValueTransformer,
43
66
  generateCssText
44
67
  };
@@ -4,24 +4,30 @@ import { Scripts, ScrollRestoration } from "@remix-run/react";
4
4
  import { ReactSdkContext } from "../context";
5
5
  import { SessionStoragePolyfill } from "./session-storage-polyfill";
6
6
  const createElementsTree = ({
7
+ instances,
8
+ rootInstanceId,
7
9
  sandbox,
8
- instance,
9
10
  propsByInstanceIdStore,
10
11
  assetsStore,
11
12
  pagesStore,
12
13
  Component,
13
14
  getComponent
14
15
  }) => {
15
- const rootInstanceSelector = [instance.id];
16
+ const rootInstance = instances.get(rootInstanceId);
17
+ if (rootInstance === void 0) {
18
+ return null;
19
+ }
20
+ const rootInstanceSelector = [rootInstanceId];
16
21
  const children = createInstanceChildrenElements({
22
+ instances,
17
23
  instanceSelector: rootInstanceSelector,
18
24
  Component,
19
- children: instance.children,
25
+ children: rootInstance.children,
20
26
  getComponent
21
27
  });
22
28
  const root = createInstanceElement({
23
29
  Component,
24
- instance,
30
+ instance: rootInstance,
25
31
  instanceSelector: rootInstanceSelector,
26
32
  children: [
27
33
  /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -42,6 +48,7 @@ const createElementsTree = ({
42
48
  );
43
49
  };
44
50
  const createInstanceChildrenElements = ({
51
+ instances,
45
52
  instanceSelector,
46
53
  children,
47
54
  Component,
@@ -53,15 +60,20 @@ const createInstanceChildrenElements = ({
53
60
  elements.push(child.value);
54
61
  continue;
55
62
  }
56
- const childInstanceSelector = [child.id, ...instanceSelector];
63
+ const childInstance = instances.get(child.value);
64
+ if (childInstance === void 0) {
65
+ continue;
66
+ }
67
+ const childInstanceSelector = [child.value, ...instanceSelector];
57
68
  const children2 = createInstanceChildrenElements({
69
+ instances,
58
70
  instanceSelector: childInstanceSelector,
59
- children: child.children,
71
+ children: childInstance.children,
60
72
  Component,
61
73
  getComponent
62
74
  });
63
75
  const element = createInstanceElement({
64
- instance: child,
76
+ instance: childInstance,
65
77
  instanceSelector: childInstanceSelector,
66
78
  Component,
67
79
  children: children2,
package/lib/tree/root.js CHANGED
@@ -5,32 +5,6 @@ import { registerComponents } from "../components";
5
5
  import { customComponents as defaultCustomComponents } from "../app/custom-components";
6
6
  import { setParams } from "../app/params";
7
7
  import { getPropsByInstanceId } from "../props";
8
- const denormalizeTree = (instances, rootInstanceId) => {
9
- const convertTree = (instance) => {
10
- const legacyInstance = {
11
- type: "instance",
12
- id: instance.id,
13
- component: instance.component,
14
- children: []
15
- };
16
- for (const child of instance.children) {
17
- if (child.type === "id") {
18
- const childInstance = instances.get(child.value);
19
- if (childInstance) {
20
- legacyInstance.children.push(convertTree(childInstance));
21
- }
22
- } else {
23
- legacyInstance.children.push(child);
24
- }
25
- }
26
- return legacyInstance;
27
- };
28
- const rootInstance = instances.get(rootInstanceId);
29
- if (rootInstance === void 0) {
30
- return void 0;
31
- }
32
- return convertTree(rootInstance);
33
- };
34
8
  const InstanceRoot = ({
35
9
  data,
36
10
  Component,
@@ -39,15 +13,9 @@ const InstanceRoot = ({
39
13
  }) => {
40
14
  setParams(data.params ?? null);
41
15
  registerComponents(customComponents);
42
- const instance = denormalizeTree(
43
- new Map(data.build.instances),
44
- data.page.rootInstanceId
45
- );
46
- if (instance === void 0) {
47
- return null;
48
- }
49
16
  return createElementsTree({
50
- instance,
17
+ instances: new Map(data.build.instances),
18
+ rootInstanceId: data.page.rootInstanceId,
51
19
  propsByInstanceIdStore: atom(
52
20
  getPropsByInstanceId(new Map(data.build.props))
53
21
  ),
@@ -1,5 +1,6 @@
1
1
  export type Params = {
2
2
  resizeOrigin?: string;
3
+ publicPath?: string;
3
4
  };
4
5
  export declare const getParams: () => Params;
5
6
  export declare const setParams: (newParams: Params | null) => void;
@@ -258,9 +258,10 @@ declare const WsComponentPropsMeta: z.ZodObject<{
258
258
  required: boolean;
259
259
  control: "inline-check";
260
260
  }>, z.ZodObject<{
261
- control: z.ZodLiteral<"file-image">;
261
+ control: z.ZodLiteral<"file">;
262
262
  type: z.ZodLiteral<"string">;
263
263
  defaultValue: z.ZodOptional<z.ZodString>;
264
+ accept: z.ZodOptional<z.ZodString>;
264
265
  label: z.ZodOptional<z.ZodString>;
265
266
  description: z.ZodOptional<z.ZodString>;
266
267
  required: z.ZodBoolean;
@@ -268,16 +269,18 @@ declare const WsComponentPropsMeta: z.ZodObject<{
268
269
  description?: string | undefined;
269
270
  label?: string | undefined;
270
271
  defaultValue?: string | undefined;
272
+ accept?: string | undefined;
271
273
  type: "string";
272
274
  required: boolean;
273
- control: "file-image";
275
+ control: "file";
274
276
  }, {
275
277
  description?: string | undefined;
276
278
  label?: string | undefined;
277
279
  defaultValue?: string | undefined;
280
+ accept?: string | undefined;
278
281
  type: "string";
279
282
  required: boolean;
280
- control: "file-image";
283
+ control: "file";
281
284
  }>, z.ZodObject<{
282
285
  control: z.ZodLiteral<"url">;
283
286
  type: z.ZodLiteral<"string">;
@@ -433,9 +436,10 @@ declare const WsComponentPropsMeta: z.ZodObject<{
433
436
  description?: string | undefined;
434
437
  label?: string | undefined;
435
438
  defaultValue?: string | undefined;
439
+ accept?: string | undefined;
436
440
  type: "string";
437
441
  required: boolean;
438
- control: "file-image";
442
+ control: "file";
439
443
  } | {
440
444
  description?: string | undefined;
441
445
  label?: string | undefined;
@@ -548,9 +552,10 @@ declare const WsComponentPropsMeta: z.ZodObject<{
548
552
  description?: string | undefined;
549
553
  label?: string | undefined;
550
554
  defaultValue?: string | undefined;
555
+ accept?: string | undefined;
551
556
  type: "string";
552
557
  required: boolean;
553
- control: "file-image";
558
+ control: "file";
554
559
  } | {
555
560
  description?: string | undefined;
556
561
  label?: string | undefined;
@@ -1,3 +1,4 @@
1
+ import { type TransformValue } from "@webstudio-is/css-engine";
1
2
  import type { Asset } from "@webstudio-is/asset-uploader";
2
3
  import type { Build } from "@webstudio-is/project-build";
3
4
  type Data = {
@@ -6,5 +7,48 @@ type Data = {
6
7
  styles?: Build["styles"];
7
8
  styleSourceSelections?: Build["styleSourceSelections"];
8
9
  };
9
- export declare const generateCssText: (data: Data) => string;
10
+ type CssOptions = {
11
+ publicPath?: string;
12
+ };
13
+ export declare const createImageValueTransformer: (assets: Map<string, {
14
+ name: string;
15
+ path: string;
16
+ type: "font";
17
+ format: "ttf" | "woff" | "woff2" | "otf";
18
+ id: string;
19
+ projectId: string;
20
+ size: number;
21
+ description: string | null;
22
+ location: "FS" | "REMOTE";
23
+ createdAt: string;
24
+ meta: {
25
+ style: "normal" | "italic" | "oblique";
26
+ weight: number;
27
+ family: string;
28
+ } | {
29
+ variationAxes: Partial<Record<"wght" | "wdth" | "slnt" | "opsz" | "ital" | "GRAD" | "XTRA" | "XOPQ" | "YOPQ" | "YTLC" | "YTUC" | "YTAS" | "YTDE" | "YTFI", {
30
+ name: string;
31
+ min: number;
32
+ default: number;
33
+ max: number;
34
+ }>>;
35
+ family: string;
36
+ };
37
+ } | {
38
+ name: string;
39
+ path: string;
40
+ type: "image";
41
+ format: string;
42
+ id: string;
43
+ projectId: string;
44
+ size: number;
45
+ description: string | null;
46
+ location: "FS" | "REMOTE";
47
+ createdAt: string;
48
+ meta: {
49
+ width: number;
50
+ height: number;
51
+ };
52
+ } | undefined>, options: CssOptions) => TransformValue;
53
+ export declare const generateCssText: (data: Data, options: CssOptions) => string;
10
54
  export {};
@@ -8,7 +8,8 @@ type StyleRule = {
8
8
  * Merge styles from different style sources
9
9
  * and group by instance and breakpoint
10
10
  */
11
- export declare const getStyleRules: (styles: Map<`${string}:${string}:filter` | `${string}:${string}:float` | `${string}:${string}:fontFamily` | `${string}:${string}:width` | `${string}:${string}:height` | `${string}:${string}:color` | `${string}:${string}:left` | `${string}:${string}:right` | `${string}:${string}:top` | `${string}:${string}:bottom` | `${string}:${string}:contain` | `${string}:${string}:clip` | `${string}:${string}:content` | `${string}:${string}:--${string}` | `${string}:${string}:accentColor` | `${string}:${string}:alignContent` | `${string}:${string}:alignItems` | `${string}:${string}:alignSelf` | `${string}:${string}:alignTracks` | `${string}:${string}:animationComposition` | `${string}:${string}:animationDelay` | `${string}:${string}:animationDirection` | `${string}:${string}:animationDuration` | `${string}:${string}:animationFillMode` | `${string}:${string}:animationIterationCount` | `${string}:${string}:animationName` | `${string}:${string}:animationPlayState` | `${string}:${string}:animationTimingFunction` | `${string}:${string}:animationTimeline` | `${string}:${string}:appearance` | `${string}:${string}:aspectRatio` | `${string}:${string}:backdropFilter` | `${string}:${string}:backfaceVisibility` | `${string}:${string}:backgroundAttachment` | `${string}:${string}:backgroundBlendMode` | `${string}:${string}:backgroundClip` | `${string}:${string}:backgroundColor` | `${string}:${string}:backgroundImage` | `${string}:${string}:backgroundOrigin` | `${string}:${string}:backgroundPosition` | `${string}:${string}:backgroundPositionX` | `${string}:${string}:backgroundPositionY` | `${string}:${string}:backgroundRepeat` | `${string}:${string}:backgroundSize` | `${string}:${string}:blockOverflow` | `${string}:${string}:blockSize` | `${string}:${string}:borderBlockColor` | `${string}:${string}:borderBlockStyle` | `${string}:${string}:borderBlockWidth` | `${string}:${string}:borderBlockEndColor` | `${string}:${string}:borderBlockEndStyle` | `${string}:${string}:borderBlockEndWidth` | `${string}:${string}:borderBlockStartColor` | `${string}:${string}:borderBlockStartStyle` | `${string}:${string}:borderBlockStartWidth` | `${string}:${string}:borderBottomColor` | `${string}:${string}:borderBottomLeftRadius` | `${string}:${string}:borderBottomRightRadius` | `${string}:${string}:borderBottomStyle` | `${string}:${string}:borderBottomWidth` | `${string}:${string}:borderCollapse` | `${string}:${string}:borderEndEndRadius` | `${string}:${string}:borderEndStartRadius` | `${string}:${string}:borderImageOutset` | `${string}:${string}:borderImageRepeat` | `${string}:${string}:borderImageSlice` | `${string}:${string}:borderImageSource` | `${string}:${string}:borderImageWidth` | `${string}:${string}:borderInlineColor` | `${string}:${string}:borderInlineStyle` | `${string}:${string}:borderInlineWidth` | `${string}:${string}:borderInlineEndColor` | `${string}:${string}:borderInlineEndStyle` | `${string}:${string}:borderInlineEndWidth` | `${string}:${string}:borderInlineStartColor` | `${string}:${string}:borderInlineStartStyle` | `${string}:${string}:borderInlineStartWidth` | `${string}:${string}:borderLeftColor` | `${string}:${string}:borderLeftStyle` | `${string}:${string}:borderLeftWidth` | `${string}:${string}:borderRightColor` | `${string}:${string}:borderRightStyle` | `${string}:${string}:borderRightWidth` | `${string}:${string}:borderSpacing` | `${string}:${string}:borderStartEndRadius` | `${string}:${string}:borderStartStartRadius` | `${string}:${string}:borderTopColor` | `${string}:${string}:borderTopLeftRadius` | `${string}:${string}:borderTopRightRadius` | `${string}:${string}:borderTopStyle` | `${string}:${string}:borderTopWidth` | `${string}:${string}:boxDecorationBreak` | `${string}:${string}:boxShadow` | `${string}:${string}:boxSizing` | `${string}:${string}:breakAfter` | `${string}:${string}:breakBefore` | `${string}:${string}:breakInside` | `${string}:${string}:captionSide` | `${string}:${string}:caretColor` | `${string}:${string}:caretShape` | `${string}:${string}:clear` | `${string}:${string}:clipPath` | `${string}:${string}:printColorAdjust` | `${string}:${string}:colorScheme` | `${string}:${string}:columnCount` | `${string}:${string}:columnFill` | `${string}:${string}:columnGap` | `${string}:${string}:columnRuleColor` | `${string}:${string}:columnRuleStyle` | `${string}:${string}:columnRuleWidth` | `${string}:${string}:columnSpan` | `${string}:${string}:columnWidth` | `${string}:${string}:containIntrinsicBlockSize` | `${string}:${string}:containIntrinsicHeight` | `${string}:${string}:containIntrinsicInlineSize` | `${string}:${string}:containIntrinsicWidth` | `${string}:${string}:contentVisibility` | `${string}:${string}:counterIncrement` | `${string}:${string}:counterReset` | `${string}:${string}:counterSet` | `${string}:${string}:cursor` | `${string}:${string}:direction` | `${string}:${string}:display` | `${string}:${string}:emptyCells` | `${string}:${string}:flexBasis` | `${string}:${string}:flexDirection` | `${string}:${string}:flexGrow` | `${string}:${string}:flexShrink` | `${string}:${string}:flexWrap` | `${string}:${string}:fontFeatureSettings` | `${string}:${string}:fontKerning` | `${string}:${string}:fontLanguageOverride` | `${string}:${string}:fontOpticalSizing` | `${string}:${string}:fontVariationSettings` | `${string}:${string}:fontSize` | `${string}:${string}:fontSizeAdjust` | `${string}:${string}:fontStretch` | `${string}:${string}:fontStyle` | `${string}:${string}:fontSynthesis` | `${string}:${string}:fontVariant` | `${string}:${string}:fontVariantAlternates` | `${string}:${string}:fontVariantCaps` | `${string}:${string}:fontVariantEastAsian` | `${string}:${string}:fontVariantLigatures` | `${string}:${string}:fontVariantNumeric` | `${string}:${string}:fontVariantPosition` | `${string}:${string}:fontWeight` | `${string}:${string}:forcedColorAdjust` | `${string}:${string}:gridAutoColumns` | `${string}:${string}:gridAutoFlow` | `${string}:${string}:gridAutoRows` | `${string}:${string}:gridColumnEnd` | `${string}:${string}:gridColumnStart` | `${string}:${string}:gridRowEnd` | `${string}:${string}:gridRowStart` | `${string}:${string}:gridTemplateAreas` | `${string}:${string}:gridTemplateColumns` | `${string}:${string}:gridTemplateRows` | `${string}:${string}:hangingPunctuation` | `${string}:${string}:hyphenateCharacter` | `${string}:${string}:hyphens` | `${string}:${string}:imageOrientation` | `${string}:${string}:imageRendering` | `${string}:${string}:imageResolution` | `${string}:${string}:initialLetter` | `${string}:${string}:initialLetterAlign` | `${string}:${string}:inlineSize` | `${string}:${string}:inputSecurity` | `${string}:${string}:insetBlockEnd` | `${string}:${string}:insetBlockStart` | `${string}:${string}:insetInlineEnd` | `${string}:${string}:insetInlineStart` | `${string}:${string}:isolation` | `${string}:${string}:justifyContent` | `${string}:${string}:justifyItems` | `${string}:${string}:justifySelf` | `${string}:${string}:justifyTracks` | `${string}:${string}:letterSpacing` | `${string}:${string}:lineBreak` | `${string}:${string}:lineClamp` | `${string}:${string}:lineHeight` | `${string}:${string}:lineHeightStep` | `${string}:${string}:listStyleImage` | `${string}:${string}:listStylePosition` | `${string}:${string}:listStyleType` | `${string}:${string}:marginBlockEnd` | `${string}:${string}:marginBlockStart` | `${string}:${string}:marginBottom` | `${string}:${string}:marginInlineEnd` | `${string}:${string}:marginInlineStart` | `${string}:${string}:marginLeft` | `${string}:${string}:marginRight` | `${string}:${string}:marginTop` | `${string}:${string}:marginTrim` | `${string}:${string}:maskBorderMode` | `${string}:${string}:maskBorderOutset` | `${string}:${string}:maskBorderRepeat` | `${string}:${string}:maskBorderSlice` | `${string}:${string}:maskBorderSource` | `${string}:${string}:maskBorderWidth` | `${string}:${string}:maskClip` | `${string}:${string}:maskComposite` | `${string}:${string}:maskImage` | `${string}:${string}:maskMode` | `${string}:${string}:maskOrigin` | `${string}:${string}:maskPosition` | `${string}:${string}:maskRepeat` | `${string}:${string}:maskSize` | `${string}:${string}:maskType` | `${string}:${string}:masonryAutoFlow` | `${string}:${string}:mathDepth` | `${string}:${string}:mathShift` | `${string}:${string}:mathStyle` | `${string}:${string}:maxBlockSize` | `${string}:${string}:maxHeight` | `${string}:${string}:maxInlineSize` | `${string}:${string}:maxLines` | `${string}:${string}:maxWidth` | `${string}:${string}:minBlockSize` | `${string}:${string}:minHeight` | `${string}:${string}:minInlineSize` | `${string}:${string}:minWidth` | `${string}:${string}:mixBlendMode` | `${string}:${string}:objectFit` | `${string}:${string}:objectPosition` | `${string}:${string}:offsetAnchor` | `${string}:${string}:offsetDistance` | `${string}:${string}:offsetPath` | `${string}:${string}:offsetPosition` | `${string}:${string}:offsetRotate` | `${string}:${string}:opacity` | `${string}:${string}:order` | `${string}:${string}:orphans` | `${string}:${string}:outlineColor` | `${string}:${string}:outlineOffset` | `${string}:${string}:outlineStyle` | `${string}:${string}:outlineWidth` | `${string}:${string}:overflow` | `${string}:${string}:overflowAnchor` | `${string}:${string}:overflowBlock` | `${string}:${string}:overflowClipMargin` | `${string}:${string}:overflowInline` | `${string}:${string}:overflowWrap` | `${string}:${string}:overflowX` | `${string}:${string}:overflowY` | `${string}:${string}:overscrollBehavior` | `${string}:${string}:overscrollBehaviorBlock` | `${string}:${string}:overscrollBehaviorInline` | `${string}:${string}:overscrollBehaviorX` | `${string}:${string}:overscrollBehaviorY` | `${string}:${string}:paddingBlockEnd` | `${string}:${string}:paddingBlockStart` | `${string}:${string}:paddingBottom` | `${string}:${string}:paddingInlineEnd` | `${string}:${string}:paddingInlineStart` | `${string}:${string}:paddingLeft` | `${string}:${string}:paddingRight` | `${string}:${string}:paddingTop` | `${string}:${string}:pageBreakAfter` | `${string}:${string}:pageBreakBefore` | `${string}:${string}:pageBreakInside` | `${string}:${string}:paintOrder` | `${string}:${string}:perspective` | `${string}:${string}:perspectiveOrigin` | `${string}:${string}:pointerEvents` | `${string}:${string}:position` | `${string}:${string}:quotes` | `${string}:${string}:resize` | `${string}:${string}:rotate` | `${string}:${string}:rowGap` | `${string}:${string}:rubyAlign` | `${string}:${string}:rubyMerge` | `${string}:${string}:rubyPosition` | `${string}:${string}:scale` | `${string}:${string}:scrollbarColor` | `${string}:${string}:scrollbarGutter` | `${string}:${string}:scrollbarWidth` | `${string}:${string}:scrollBehavior` | `${string}:${string}:scrollMarginBlockStart` | `${string}:${string}:scrollMarginBlockEnd` | `${string}:${string}:scrollMarginBottom` | `${string}:${string}:scrollMarginInlineStart` | `${string}:${string}:scrollMarginInlineEnd` | `${string}:${string}:scrollMarginLeft` | `${string}:${string}:scrollMarginRight` | `${string}:${string}:scrollMarginTop` | `${string}:${string}:scrollPaddingBlockStart` | `${string}:${string}:scrollPaddingBlockEnd` | `${string}:${string}:scrollPaddingBottom` | `${string}:${string}:scrollPaddingInlineStart` | `${string}:${string}:scrollPaddingInlineEnd` | `${string}:${string}:scrollPaddingLeft` | `${string}:${string}:scrollPaddingRight` | `${string}:${string}:scrollPaddingTop` | `${string}:${string}:scrollSnapAlign` | `${string}:${string}:scrollSnapStop` | `${string}:${string}:scrollSnapType` | `${string}:${string}:scrollTimelineAxis` | `${string}:${string}:scrollTimelineName` | `${string}:${string}:shapeImageThreshold` | `${string}:${string}:shapeMargin` | `${string}:${string}:shapeOutside` | `${string}:${string}:tabSize` | `${string}:${string}:tableLayout` | `${string}:${string}:textAlign` | `${string}:${string}:textAlignLast` | `${string}:${string}:textCombineUpright` | `${string}:${string}:textDecorationColor` | `${string}:${string}:textDecorationLine` | `${string}:${string}:textDecorationSkip` | `${string}:${string}:textDecorationSkipInk` | `${string}:${string}:textDecorationStyle` | `${string}:${string}:textDecorationThickness` | `${string}:${string}:textEmphasisColor` | `${string}:${string}:textEmphasisPosition` | `${string}:${string}:textEmphasisStyle` | `${string}:${string}:textIndent` | `${string}:${string}:textJustify` | `${string}:${string}:textOrientation` | `${string}:${string}:textOverflow` | `${string}:${string}:textRendering` | `${string}:${string}:textShadow` | `${string}:${string}:textSizeAdjust` | `${string}:${string}:textTransform` | `${string}:${string}:textUnderlineOffset` | `${string}:${string}:textUnderlinePosition` | `${string}:${string}:touchAction` | `${string}:${string}:transform` | `${string}:${string}:transformBox` | `${string}:${string}:transformOrigin` | `${string}:${string}:transformStyle` | `${string}:${string}:transitionDelay` | `${string}:${string}:transitionDuration` | `${string}:${string}:transitionProperty` | `${string}:${string}:transitionTimingFunction` | `${string}:${string}:translate` | `${string}:${string}:unicodeBidi` | `${string}:${string}:userSelect` | `${string}:${string}:verticalAlign` | `${string}:${string}:visibility` | `${string}:${string}:whiteSpace` | `${string}:${string}:widows` | `${string}:${string}:willChange` | `${string}:${string}:wordBreak` | `${string}:${string}:wordSpacing` | `${string}:${string}:wordWrap` | `${string}:${string}:writingMode` | `${string}:${string}:zIndex`, {
11
+ export declare const getStyleRules: (styles: Map<string, {
12
+ state?: string | undefined;
12
13
  value: {
13
14
  type: "unit";
14
15
  value: number;
@@ -34,22 +35,10 @@ export declare const getStyleRules: (styles: Map<`${string}:${string}:filter` |
34
35
  type: "image";
35
36
  value: {
36
37
  type: "asset";
37
- value: {
38
- name: string;
39
- path: string;
40
- type: "image";
41
- format: string;
42
- id: string;
43
- projectId: string;
44
- size: number;
45
- description: string | null;
46
- location: "FS" | "REMOTE";
47
- createdAt: string;
48
- meta: {
49
- width: number;
50
- height: number;
51
- };
52
- };
38
+ value: string;
39
+ } | {
40
+ type: "url";
41
+ url: string;
53
42
  };
54
43
  } | {
55
44
  type: "invalid";
@@ -89,22 +78,10 @@ export declare const getStyleRules: (styles: Map<`${string}:${string}:filter` |
89
78
  type: "image";
90
79
  value: {
91
80
  type: "asset";
92
- value: {
93
- name: string;
94
- path: string;
95
- type: "image";
96
- format: string;
97
- id: string;
98
- projectId: string;
99
- size: number;
100
- description: string | null;
101
- location: "FS" | "REMOTE";
102
- createdAt: string;
103
- meta: {
104
- width: number;
105
- height: number;
106
- };
107
- };
81
+ value: string;
82
+ } | {
83
+ type: "url";
84
+ url: string;
108
85
  };
109
86
  } | {
110
87
  type: "invalid";
@@ -152,22 +129,10 @@ export declare const getStyleRules: (styles: Map<`${string}:${string}:filter` |
152
129
  type: "image";
153
130
  value: {
154
131
  type: "asset";
155
- value: {
156
- name: string;
157
- path: string;
158
- type: "image";
159
- format: string;
160
- id: string;
161
- projectId: string;
162
- size: number;
163
- description: string | null;
164
- location: "FS" | "REMOTE";
165
- createdAt: string;
166
- meta: {
167
- width: number;
168
- height: number;
169
- };
170
- };
132
+ value: string;
133
+ } | {
134
+ type: "url";
135
+ url: string;
171
136
  };
172
137
  } | {
173
138
  type: "tuple";
@@ -201,22 +166,10 @@ export declare const getStyleRules: (styles: Map<`${string}:${string}:filter` |
201
166
  type: "image";
202
167
  value: {
203
168
  type: "asset";
204
- value: {
205
- name: string;
206
- path: string;
207
- type: "image";
208
- format: string;
209
- id: string;
210
- projectId: string;
211
- size: number;
212
- description: string | null;
213
- location: "FS" | "REMOTE";
214
- createdAt: string;
215
- meta: {
216
- width: number;
217
- height: number;
218
- };
219
- };
169
+ value: string;
170
+ } | {
171
+ type: "url";
172
+ url: string;
220
173
  };
221
174
  } | {
222
175
  type: "invalid";
@@ -1,16 +1,29 @@
1
1
  import { type ComponentProps } from "react";
2
2
  import type { ReadableAtom } from "nanostores";
3
3
  import type { Assets } from "@webstudio-is/asset-uploader";
4
- import type { Instance } from "@webstudio-is/project-build";
4
+ import type { Instance, Instances } from "@webstudio-is/project-build";
5
5
  import type { GetComponent } from "../components/components-utils";
6
6
  import type { Pages, PropsByInstanceId } from "../props";
7
7
  import type { WebstudioComponent } from "./webstudio-component";
8
- export declare const createElementsTree: ({ sandbox, instance, propsByInstanceIdStore, assetsStore, pagesStore, Component, getComponent, }: {
8
+ export declare const createElementsTree: ({ instances, rootInstanceId, sandbox, propsByInstanceIdStore, assetsStore, pagesStore, Component, getComponent, }: {
9
+ instances: Map<string, {
10
+ label?: string | undefined;
11
+ type: "instance";
12
+ id: string;
13
+ component: string;
14
+ children: ({
15
+ type: "text";
16
+ value: string;
17
+ } | {
18
+ type: "id";
19
+ value: string;
20
+ })[];
21
+ }>;
22
+ rootInstanceId: Instance["id"];
9
23
  sandbox?: boolean | undefined;
10
- instance: Instance;
11
24
  propsByInstanceIdStore: ReadableAtom<PropsByInstanceId>;
12
25
  assetsStore: ReadableAtom<Assets>;
13
26
  pagesStore: ReadableAtom<Pages>;
14
27
  Component: (props: ComponentProps<typeof WebstudioComponent>) => JSX.Element;
15
28
  getComponent: GetComponent;
16
- }) => JSX.Element;
29
+ }) => JSX.Element | null;
@@ -1,9 +1,9 @@
1
1
  /// <reference types="react" />
2
- import type { Instance } from "@webstudio-is/project-build";
2
+ import type { Instance, InstancesItem } from "@webstudio-is/project-build";
3
3
  import type { GetComponent } from "../components/components-utils";
4
4
  export declare const renderWebstudioComponentChildren: (children: Array<JSX.Element | string> | undefined) => Array<JSX.Element | string | Array<JSX.Element | string>> | undefined;
5
5
  type WebstudioComponentProps = {
6
- instance: Instance;
6
+ instance: InstancesItem;
7
7
  instanceSelector: Instance["id"][];
8
8
  children: Array<JSX.Element | string>;
9
9
  getComponent: GetComponent;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webstudio-is/react-sdk",
3
- "version": "0.53.0",
3
+ "version": "0.55.0",
4
4
  "description": "Webstudio JavaScript / TypeScript API",
5
5
  "author": "Webstudio <github@webstudio.is>",
6
6
  "homepage": "https://webstudio.is",
@@ -23,7 +23,7 @@
23
23
  "@webstudio-is/jest-config": "^1.0.2",
24
24
  "@webstudio-is/scripts": "^0.0.0",
25
25
  "@webstudio-is/storybook-config": "^0.0.0",
26
- "@webstudio-is/tsconfig": "^1.0.1"
26
+ "@webstudio-is/tsconfig": "^1.0.3"
27
27
  },
28
28
  "peerDependencies": {
29
29
  "@remix-run/react": "1.9.0",
@@ -38,16 +38,16 @@
38
38
  "html-tags": "^3.2.0",
39
39
  "nanoevents": "^7.0.1",
40
40
  "nanostores": "^0.7.1",
41
- "@webstudio-is/asset-uploader": "^0.53.0",
42
- "@webstudio-is/css-data": "^0.53.0",
43
- "@webstudio-is/css-engine": "^0.53.0",
44
- "@webstudio-is/css-vars": "^0.53.0",
45
- "@webstudio-is/fonts": "^0.53.0",
46
- "@webstudio-is/generate-arg-types": "^0.53.0",
47
- "@webstudio-is/icons": "^0.53.0",
48
- "@webstudio-is/image": "^0.53.0",
49
- "@webstudio-is/prisma-client": "^0.53.0",
50
- "@webstudio-is/project-build": "^0.53.0"
41
+ "@webstudio-is/asset-uploader": "^0.55.0",
42
+ "@webstudio-is/css-data": "^0.55.0",
43
+ "@webstudio-is/css-engine": "^0.55.0",
44
+ "@webstudio-is/css-vars": "^0.55.0",
45
+ "@webstudio-is/fonts": "^0.55.0",
46
+ "@webstudio-is/generate-arg-types": "^0.55.0",
47
+ "@webstudio-is/icons": "^0.55.0",
48
+ "@webstudio-is/prisma-client": "^0.55.0",
49
+ "@webstudio-is/project-build": "^0.55.0",
50
+ "@webstudio-is/image": "^0.55.0"
51
51
  },
52
52
  "exports": {
53
53
  ".": {
@@ -25,7 +25,7 @@ export const Image = forwardRef<ElementRef<typeof defaultTag>, Props>(
25
25
  if (asset.location === "REMOTE") {
26
26
  return loaders.cloudflareImageLoader(params);
27
27
  }
28
- return loaders.localImageLoader();
28
+ return loaders.localImageLoader(params);
29
29
  }, [asset, params]);
30
30
 
31
31
  let src = props.src;
package/src/app/params.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export type Params = {
2
2
  resizeOrigin?: string;
3
+ publicPath?: string;
3
4
  };
4
5
 
5
6
  let params: Params | null = {};
@@ -79,5 +79,4 @@ export const meta: WsComponentMeta = {
79
79
 
80
80
  export const propsMeta: WsComponentPropsMeta = {
81
81
  props,
82
- initialProps: ["tag"],
83
82
  };
@@ -37,7 +37,7 @@ export const propsMeta: WsComponentPropsMeta = {
37
37
  ...props,
38
38
  src: {
39
39
  type: "string",
40
- control: "file-image",
40
+ control: "file",
41
41
  label: "Source",
42
42
  required: false,
43
43
  },
package/src/css/css.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { createCssEngine } from "@webstudio-is/css-engine";
2
- import type { Asset } from "@webstudio-is/asset-uploader";
1
+ import { createCssEngine, type TransformValue } from "@webstudio-is/css-engine";
2
+ import type { Asset, Assets } from "@webstudio-is/asset-uploader";
3
3
  import type { Build } from "@webstudio-is/project-build";
4
4
  import { getComponentNames } from "../components/components-utils";
5
5
  import { getComponentMeta } from "../components";
@@ -14,7 +14,36 @@ type Data = {
14
14
  styleSourceSelections?: Build["styleSourceSelections"];
15
15
  };
16
16
 
17
- export const generateCssText = (data: Data) => {
17
+ type CssOptions = {
18
+ publicPath?: string;
19
+ };
20
+
21
+ export const createImageValueTransformer =
22
+ (assets: Assets, options: CssOptions): TransformValue =>
23
+ (styleValue) => {
24
+ if (styleValue.type === "image" && styleValue.value.type === "asset") {
25
+ const asset = assets.get(styleValue.value.value);
26
+ if (asset === undefined) {
27
+ return { type: "keyword", value: "none" };
28
+ }
29
+
30
+ // @todo reuse image loaders and generate image-set
31
+ const { publicPath = "/" } = options;
32
+ const url =
33
+ asset.location === "REMOTE" ? asset.path : `${publicPath}${asset.name}`;
34
+
35
+ return {
36
+ type: "image",
37
+ value: {
38
+ type: "url",
39
+ url,
40
+ },
41
+ hidden: styleValue.hidden,
42
+ };
43
+ }
44
+ };
45
+
46
+ export const generateCssText = (data: Data, options: CssOptions) => {
18
47
  const assets = new Map<Asset["id"], Asset>(
19
48
  data.assets.map((asset) => [asset.id, asset])
20
49
  );
@@ -47,10 +76,14 @@ export const generateCssText = (data: Data) => {
47
76
 
48
77
  const styleRules = getStyleRules(styles, styleSourceSelections);
49
78
  for (const { breakpointId, instanceId, style } of styleRules) {
50
- engine.addStyleRule(`[${idAttribute}="${instanceId}"]`, {
51
- breakpoint: breakpointId,
52
- style,
53
- });
79
+ engine.addStyleRule(
80
+ `[${idAttribute}="${instanceId}"]`,
81
+ {
82
+ breakpoint: breakpointId,
83
+ style,
84
+ },
85
+ createImageValueTransformer(assets, options)
86
+ );
54
87
  }
55
88
 
56
89
  return engine.cssText;
@@ -1,75 +1,60 @@
1
1
  import { test, expect } from "@jest/globals";
2
- import type {
2
+ import {
3
+ getStyleDeclKey,
4
+ StyleDecl,
3
5
  Styles,
4
6
  StyleSourceSelections,
5
7
  } from "@webstudio-is/project-build";
6
8
  import { getStyleRules } from "./style-rules";
7
9
 
10
+ const createStyleDeclPair = (styleDecl: StyleDecl) => {
11
+ return [getStyleDeclKey(styleDecl), styleDecl] as const;
12
+ };
13
+
8
14
  test("compute styles from different style sources", () => {
9
15
  const styles: Styles = new Map([
10
- [
11
- "styleSource1:a:width",
12
- {
13
- breakpointId: "a",
14
- styleSourceId: "styleSource1",
15
- property: "width",
16
- value: { type: "unit", value: 10, unit: "px" },
17
- },
18
- ],
19
- [
20
- "styleSource2:a:display",
21
- {
22
- breakpointId: "a",
23
- styleSourceId: "styleSource2",
24
- property: "display",
25
- value: { type: "keyword", value: "block" },
26
- },
27
- ],
28
- [
29
- "styleSource4:a:color",
30
- {
31
- breakpointId: "a",
32
- styleSourceId: "styleSource4",
33
- property: "color",
34
- value: { type: "keyword", value: "green" },
35
- },
36
- ],
37
- [
38
- "styleSource4:a:width",
39
- {
40
- breakpointId: "a",
41
- styleSourceId: "styleSource4",
42
- property: "width",
43
- value: { type: "keyword", value: "min-content" },
44
- },
45
- ],
46
- [
47
- "styleSource3:a:color",
48
- {
49
- breakpointId: "a",
50
- styleSourceId: "styleSource3",
51
- property: "color",
52
- value: { type: "keyword", value: "red" },
53
- },
54
- ],
55
- [
56
- "styleSource5:b:color",
57
- {
58
- breakpointId: "b",
59
- styleSourceId: "styleSource5",
60
- property: "color",
61
- value: { type: "keyword", value: "orange" },
62
- },
63
- ],
64
- [
65
- "styleSource6:a:color",
66
- {
67
- breakpointId: "a",
68
- styleSourceId: "styleSource6",
69
- property: "color",
70
- value: { type: "keyword", value: "blue" },
71
- },
72
- ],
16
+ createStyleDeclPair({
17
+ breakpointId: "a",
18
+ styleSourceId: "styleSource1",
19
+ property: "width",
20
+ value: { type: "unit", value: 10, unit: "px" },
21
+ }),
22
+ createStyleDeclPair({
23
+ breakpointId: "a",
24
+ styleSourceId: "styleSource2",
25
+ property: "display",
26
+ value: { type: "keyword", value: "block" },
27
+ }),
28
+ createStyleDeclPair({
29
+ breakpointId: "a",
30
+ styleSourceId: "styleSource4",
31
+ property: "color",
32
+ value: { type: "keyword", value: "green" },
33
+ }),
34
+ createStyleDeclPair({
35
+ breakpointId: "a",
36
+ styleSourceId: "styleSource4",
37
+ property: "width",
38
+ value: { type: "keyword", value: "min-content" },
39
+ }),
40
+ createStyleDeclPair({
41
+ breakpointId: "a",
42
+ styleSourceId: "styleSource3",
43
+ property: "color",
44
+ value: { type: "keyword", value: "red" },
45
+ }),
46
+ createStyleDeclPair({
47
+ breakpointId: "b",
48
+ styleSourceId: "styleSource5",
49
+ property: "color",
50
+ value: { type: "keyword", value: "orange" },
51
+ }),
52
+ createStyleDeclPair({
53
+ breakpointId: "a",
54
+ styleSourceId: "styleSource6",
55
+ property: "color",
56
+ value: { type: "keyword", value: "blue" },
57
+ }),
73
58
  ]);
74
59
  const styleSourceSelections: StyleSourceSelections = new Map([
75
60
  [
@@ -2,7 +2,11 @@ import { type ComponentProps, Fragment } from "react";
2
2
  import type { ReadableAtom } from "nanostores";
3
3
  import { Scripts, ScrollRestoration } from "@remix-run/react";
4
4
  import type { Assets } from "@webstudio-is/asset-uploader";
5
- import type { Instance } from "@webstudio-is/project-build";
5
+ import type {
6
+ Instance,
7
+ Instances,
8
+ InstancesItem,
9
+ } from "@webstudio-is/project-build";
6
10
  import type { GetComponent } from "../components/components-utils";
7
11
  import { ReactSdkContext } from "../context";
8
12
  import type { Pages, PropsByInstanceId } from "../props";
@@ -12,32 +16,40 @@ import { SessionStoragePolyfill } from "./session-storage-polyfill";
12
16
  type InstanceSelector = Instance["id"][];
13
17
 
14
18
  export const createElementsTree = ({
19
+ instances,
20
+ rootInstanceId,
15
21
  sandbox,
16
- instance,
17
22
  propsByInstanceIdStore,
18
23
  assetsStore,
19
24
  pagesStore,
20
25
  Component,
21
26
  getComponent,
22
27
  }: {
28
+ instances: Instances;
29
+ rootInstanceId: Instance["id"];
23
30
  sandbox?: boolean;
24
- instance: Instance;
25
31
  propsByInstanceIdStore: ReadableAtom<PropsByInstanceId>;
26
32
  assetsStore: ReadableAtom<Assets>;
27
33
  pagesStore: ReadableAtom<Pages>;
28
34
  Component: (props: ComponentProps<typeof WebstudioComponent>) => JSX.Element;
29
35
  getComponent: GetComponent;
30
36
  }) => {
31
- const rootInstanceSelector = [instance.id];
37
+ const rootInstance = instances.get(rootInstanceId);
38
+ if (rootInstance === undefined) {
39
+ return null;
40
+ }
41
+
42
+ const rootInstanceSelector = [rootInstanceId];
32
43
  const children = createInstanceChildrenElements({
44
+ instances,
33
45
  instanceSelector: rootInstanceSelector,
34
46
  Component,
35
- children: instance.children,
47
+ children: rootInstance.children,
36
48
  getComponent,
37
49
  });
38
50
  const root = createInstanceElement({
39
51
  Component,
40
- instance,
52
+ instance: rootInstance,
41
53
  instanceSelector: rootInstanceSelector,
42
54
  children: [
43
55
  <Fragment key="children">
@@ -59,13 +71,15 @@ export const createElementsTree = ({
59
71
  };
60
72
 
61
73
  const createInstanceChildrenElements = ({
74
+ instances,
62
75
  instanceSelector,
63
76
  children,
64
77
  Component,
65
78
  getComponent,
66
79
  }: {
80
+ instances: Instances;
67
81
  instanceSelector: InstanceSelector;
68
- children: Instance["children"];
82
+ children: InstancesItem["children"];
69
83
  Component: (props: ComponentProps<typeof WebstudioComponent>) => JSX.Element;
70
84
  getComponent: GetComponent;
71
85
  }) => {
@@ -75,15 +89,20 @@ const createInstanceChildrenElements = ({
75
89
  elements.push(child.value);
76
90
  continue;
77
91
  }
78
- const childInstanceSelector = [child.id, ...instanceSelector];
92
+ const childInstance = instances.get(child.value);
93
+ if (childInstance === undefined) {
94
+ continue;
95
+ }
96
+ const childInstanceSelector = [child.value, ...instanceSelector];
79
97
  const children = createInstanceChildrenElements({
98
+ instances,
80
99
  instanceSelector: childInstanceSelector,
81
- children: child.children,
100
+ children: childInstance.children,
82
101
  Component,
83
102
  getComponent,
84
103
  });
85
104
  const element = createInstanceElement({
86
- instance: child,
105
+ instance: childInstance,
87
106
  instanceSelector: childInstanceSelector,
88
107
  Component,
89
108
  children,
@@ -101,7 +120,7 @@ const createInstanceElement = ({
101
120
  children = [],
102
121
  getComponent,
103
122
  }: {
104
- instance: Instance;
123
+ instance: InstancesItem;
105
124
  instanceSelector: InstanceSelector;
106
125
  Component: (props: ComponentProps<typeof WebstudioComponent>) => JSX.Element;
107
126
  children?: Array<JSX.Element | string>;
package/src/tree/root.ts CHANGED
@@ -1,12 +1,6 @@
1
1
  import type { ComponentProps } from "react";
2
2
  import { atom } from "nanostores";
3
- import type {
4
- Build,
5
- Instance,
6
- Instances,
7
- InstancesItem,
8
- Page,
9
- } from "@webstudio-is/project-build";
3
+ import type { Build, Page } from "@webstudio-is/project-build";
10
4
  import type { Asset } from "@webstudio-is/asset-uploader";
11
5
  import { createElementsTree } from "./create-elements-tree";
12
6
  import { WebstudioComponent } from "./webstudio-component";
@@ -35,36 +29,6 @@ type RootProps = {
35
29
  getComponent: GetComponent;
36
30
  };
37
31
 
38
- const denormalizeTree = (
39
- instances: Instances,
40
- rootInstanceId: Instance["id"]
41
- ) => {
42
- const convertTree = (instance: InstancesItem) => {
43
- const legacyInstance: Instance = {
44
- type: "instance",
45
- id: instance.id,
46
- component: instance.component,
47
- children: [],
48
- };
49
- for (const child of instance.children) {
50
- if (child.type === "id") {
51
- const childInstance = instances.get(child.value);
52
- if (childInstance) {
53
- legacyInstance.children.push(convertTree(childInstance));
54
- }
55
- } else {
56
- legacyInstance.children.push(child);
57
- }
58
- }
59
- return legacyInstance;
60
- };
61
- const rootInstance = instances.get(rootInstanceId);
62
- if (rootInstance === undefined) {
63
- return undefined;
64
- }
65
- return convertTree(rootInstance);
66
- };
67
-
68
32
  export const InstanceRoot = ({
69
33
  data,
70
34
  Component,
@@ -72,17 +36,10 @@ export const InstanceRoot = ({
72
36
  getComponent,
73
37
  }: RootProps): JSX.Element | null => {
74
38
  setParams(data.params ?? null);
75
-
76
39
  registerComponents(customComponents);
77
- const instance = denormalizeTree(
78
- new Map(data.build.instances),
79
- data.page.rootInstanceId
80
- );
81
- if (instance === undefined) {
82
- return null;
83
- }
84
40
  return createElementsTree({
85
- instance,
41
+ instances: new Map(data.build.instances),
42
+ rootInstanceId: data.page.rootInstanceId,
86
43
  propsByInstanceIdStore: atom(
87
44
  getPropsByInstanceId(new Map(data.build.props))
88
45
  ),
@@ -1,5 +1,5 @@
1
1
  import { Fragment } from "react";
2
- import type { Instance } from "@webstudio-is/project-build";
2
+ import type { Instance, InstancesItem } from "@webstudio-is/project-build";
3
3
  import type { GetComponent } from "../components/components-utils";
4
4
  import { useInstanceProps } from "../props";
5
5
 
@@ -27,7 +27,7 @@ export const renderWebstudioComponentChildren = (
27
27
  };
28
28
 
29
29
  type WebstudioComponentProps = {
30
- instance: Instance;
30
+ instance: InstancesItem;
31
31
  instanceSelector: Instance["id"][];
32
32
  children: Array<JSX.Element | string>;
33
33
  getComponent: GetComponent;