@webstudio-is/react-sdk 0.75.0 → 0.76.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 (41) hide show
  1. package/lib/cjs/context.js +5 -1
  2. package/lib/cjs/css/normalize.js +9 -1
  3. package/lib/cjs/embed-template.js +68 -3
  4. package/lib/cjs/expression.js +191 -0
  5. package/lib/cjs/index.js +7 -1
  6. package/lib/cjs/props.js +28 -10
  7. package/lib/cjs/tree/create-elements-tree.js +14 -1
  8. package/lib/cjs/tree/root.js +55 -0
  9. package/lib/cjs/tree/webstudio-component.js +9 -2
  10. package/lib/context.js +5 -1
  11. package/lib/css/normalize.js +9 -1
  12. package/lib/embed-template.js +68 -3
  13. package/lib/expression.js +161 -0
  14. package/lib/index.js +13 -1
  15. package/lib/props.js +28 -10
  16. package/lib/tree/create-elements-tree.js +14 -1
  17. package/lib/tree/root.js +63 -1
  18. package/lib/tree/webstudio-component.js +9 -2
  19. package/lib/types/components/component-meta.d.ts +112 -0
  20. package/lib/types/context.d.ts +3 -0
  21. package/lib/types/css/normalize.d.ts +1316 -0
  22. package/lib/types/embed-template.d.ts +512 -0
  23. package/lib/types/expression.d.ts +6 -0
  24. package/lib/types/expression.test.d.ts +1 -0
  25. package/lib/types/index.d.ts +2 -1
  26. package/lib/types/props.d.ts +8 -7
  27. package/lib/types/tree/create-elements-tree.d.ts +4 -2
  28. package/lib/types/tree/root.d.ts +3 -3
  29. package/lib/types/tree/webstudio-component.d.ts +1 -0
  30. package/package.json +10 -10
  31. package/src/context.tsx +11 -0
  32. package/src/css/normalize.ts +9 -1
  33. package/src/embed-template.test.ts +177 -1
  34. package/src/embed-template.ts +73 -2
  35. package/src/expression.test.ts +122 -0
  36. package/src/expression.ts +183 -0
  37. package/src/index.ts +7 -0
  38. package/src/props.ts +29 -10
  39. package/src/tree/create-elements-tree.tsx +20 -1
  40. package/src/tree/root.ts +81 -4
  41. package/src/tree/webstudio-component.tsx +7 -1
@@ -28,5 +28,9 @@ const ReactSdkContext = (0, import_react.createContext)({
28
28
  assetBaseUrl: "/",
29
29
  propsByInstanceIdStore: (0, import_nanostores.atom)(/* @__PURE__ */ new Map()),
30
30
  assetsStore: (0, import_nanostores.atom)(/* @__PURE__ */ new Map()),
31
- pagesStore: (0, import_nanostores.atom)(/* @__PURE__ */ new Map())
31
+ pagesStore: (0, import_nanostores.atom)(/* @__PURE__ */ new Map()),
32
+ dataSourceValuesStore: (0, import_nanostores.atom)(/* @__PURE__ */ new Map()),
33
+ setDataSourceValue: () => {
34
+ throw Error("React SDK setDataSourceValue is not implemented");
35
+ }
32
36
  });
@@ -141,9 +141,17 @@ const body = [
141
141
  property: "fontFamily",
142
142
  value: {
143
143
  type: "keyword",
144
- value: `system-ui, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji'`
144
+ value: "Arial, sans-serif"
145
145
  }
146
146
  },
147
+ {
148
+ property: "fontSize",
149
+ value: { type: "unit", unit: "px", value: 16 }
150
+ },
151
+ {
152
+ property: "lineHeight",
153
+ value: { type: "unit", unit: "number", value: 1.2 }
154
+ },
147
155
  boxSizing,
148
156
  ...import_presets.borders
149
157
  ];
@@ -27,29 +27,45 @@ module.exports = __toCommonJS(embed_template_exports);
27
27
  var import_zod = require("zod");
28
28
  var import_nanoid = require("nanoid");
29
29
  var import_css_data = require("@webstudio-is/css-data");
30
+ var import_expression = require("./expression");
30
31
  const EmbedTemplateText = import_zod.z.object({
31
32
  type: import_zod.z.literal("text"),
32
33
  value: import_zod.z.string()
33
34
  });
35
+ const DataSourceRef = import_zod.z.union([
36
+ import_zod.z.object({
37
+ type: import_zod.z.literal("variable"),
38
+ name: import_zod.z.string()
39
+ }),
40
+ import_zod.z.object({
41
+ type: import_zod.z.literal("expression"),
42
+ name: import_zod.z.string(),
43
+ code: import_zod.z.string()
44
+ })
45
+ ]);
34
46
  const EmbedTemplateProp = import_zod.z.union([
35
47
  import_zod.z.object({
36
48
  type: import_zod.z.literal("number"),
37
49
  name: import_zod.z.string(),
50
+ dataSourceRef: import_zod.z.optional(DataSourceRef),
38
51
  value: import_zod.z.number()
39
52
  }),
40
53
  import_zod.z.object({
41
54
  type: import_zod.z.literal("string"),
42
55
  name: import_zod.z.string(),
56
+ dataSourceRef: import_zod.z.optional(DataSourceRef),
43
57
  value: import_zod.z.string()
44
58
  }),
45
59
  import_zod.z.object({
46
60
  type: import_zod.z.literal("boolean"),
47
61
  name: import_zod.z.string(),
62
+ dataSourceRef: import_zod.z.optional(DataSourceRef),
48
63
  value: import_zod.z.boolean()
49
64
  }),
50
65
  import_zod.z.object({
51
66
  type: import_zod.z.literal("string[]"),
52
67
  name: import_zod.z.string(),
68
+ dataSourceRef: import_zod.z.optional(DataSourceRef),
53
69
  value: import_zod.z.array(import_zod.z.string())
54
70
  })
55
71
  ]);
@@ -73,17 +89,52 @@ const EmbedTemplateInstance = import_zod.z.lazy(
73
89
  const WsEmbedTemplate = import_zod.z.lazy(
74
90
  () => import_zod.z.array(import_zod.z.union([EmbedTemplateInstance, EmbedTemplateText]))
75
91
  );
76
- const createInstancesFromTemplate = (treeTemplate, instances, props, styleSourceSelections, styleSources, styles, defaultBreakpointId) => {
92
+ const createInstancesFromTemplate = (treeTemplate, instances, props, dataSourceByRef, styleSourceSelections, styleSources, styles, defaultBreakpointId) => {
77
93
  const parentChildren = [];
78
94
  for (const item of treeTemplate) {
79
95
  if (item.type === "instance") {
80
96
  const instanceId = (0, import_nanoid.nanoid)();
81
97
  if (item.props) {
82
98
  for (const prop of item.props) {
99
+ const propId = (0, import_nanoid.nanoid)();
100
+ if (prop.dataSourceRef === void 0) {
101
+ props.push({ id: propId, instanceId, ...prop });
102
+ continue;
103
+ }
104
+ let dataSource = dataSourceByRef.get(prop.dataSourceRef.name);
105
+ if (dataSource === void 0) {
106
+ const id = (0, import_nanoid.nanoid)();
107
+ const { name: propName, dataSourceRef, ...rest } = prop;
108
+ if (dataSourceRef.type === "variable") {
109
+ dataSource = {
110
+ type: "variable",
111
+ id,
112
+ // the first instance where data source is appeared in becomes its scope
113
+ scopeInstanceId: instanceId,
114
+ name: dataSourceRef.name,
115
+ value: rest
116
+ };
117
+ dataSourceByRef.set(dataSourceRef.name, dataSource);
118
+ } else if (dataSourceRef.type === "expression") {
119
+ dataSource = {
120
+ type: "expression",
121
+ id,
122
+ scopeInstanceId: instanceId,
123
+ name: dataSourceRef.name,
124
+ code: dataSourceRef.code
125
+ };
126
+ dataSourceByRef.set(dataSourceRef.name, dataSource);
127
+ } else {
128
+ dataSourceRef;
129
+ continue;
130
+ }
131
+ }
83
132
  props.push({
84
- id: (0, import_nanoid.nanoid)(),
133
+ id: propId,
85
134
  instanceId,
86
- ...prop
135
+ type: "dataSource",
136
+ name: prop.name,
137
+ value: dataSource.id
87
138
  });
88
139
  }
89
140
  }
@@ -119,6 +170,7 @@ const createInstancesFromTemplate = (treeTemplate, instances, props, styleSource
119
170
  item.children,
120
171
  instances,
121
172
  props,
173
+ dataSourceByRef,
122
174
  styleSourceSelections,
123
175
  styleSources,
124
176
  styles,
@@ -141,6 +193,7 @@ const createInstancesFromTemplate = (treeTemplate, instances, props, styleSource
141
193
  const generateDataFromEmbedTemplate = (treeTemplate, defaultBreakpointId) => {
142
194
  const instances = [];
143
195
  const props = [];
196
+ const dataSourceByRef = /* @__PURE__ */ new Map();
144
197
  const styleSourceSelections = [];
145
198
  const styleSources = [];
146
199
  const styles = [];
@@ -148,15 +201,27 @@ const generateDataFromEmbedTemplate = (treeTemplate, defaultBreakpointId) => {
148
201
  treeTemplate,
149
202
  instances,
150
203
  props,
204
+ dataSourceByRef,
151
205
  styleSourceSelections,
152
206
  styleSources,
153
207
  styles,
154
208
  defaultBreakpointId
155
209
  );
210
+ const dataSources = [];
211
+ for (const dataSource of dataSourceByRef.values()) {
212
+ if (dataSource.type === "expression") {
213
+ dataSource.code = (0, import_expression.validateExpression)(dataSource.code, (ref) => {
214
+ const id = dataSourceByRef.get(ref)?.id ?? ref;
215
+ return (0, import_expression.encodeDataSourceVariable)(id);
216
+ });
217
+ }
218
+ dataSources.push(dataSource);
219
+ }
156
220
  return {
157
221
  children,
158
222
  instances,
159
223
  props,
224
+ dataSources,
160
225
  styleSourceSelections,
161
226
  styleSources,
162
227
  styles
@@ -0,0 +1,191 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var expression_exports = {};
30
+ __export(expression_exports, {
31
+ decodeDataSourceVariable: () => decodeDataSourceVariable,
32
+ encodeDataSourceVariable: () => encodeDataSourceVariable,
33
+ executeExpressions: () => executeExpressions,
34
+ validateExpression: () => validateExpression
35
+ });
36
+ module.exports = __toCommonJS(expression_exports);
37
+ var import_jsep = __toESM(require("jsep"), 1);
38
+ const generateCode = (node, failOnForbidden, transformIdentifier) => {
39
+ if (node.type === "Identifier") {
40
+ return transformIdentifier(node.name);
41
+ }
42
+ if (node.type === "MemberExpression") {
43
+ if (failOnForbidden) {
44
+ const object2 = generateCode(
45
+ node.object,
46
+ false,
47
+ transformIdentifier
48
+ );
49
+ const property2 = generateCode(
50
+ node.property,
51
+ false,
52
+ transformIdentifier
53
+ );
54
+ throw Error(`Cannot access "${property2}" of "${object2}"`);
55
+ }
56
+ const object = generateCode(
57
+ node.object,
58
+ failOnForbidden,
59
+ transformIdentifier
60
+ );
61
+ const property = generateCode(
62
+ node.property,
63
+ failOnForbidden,
64
+ transformIdentifier
65
+ );
66
+ return `${object}.${property}`;
67
+ }
68
+ if (node.type === "Literal") {
69
+ return node.raw;
70
+ }
71
+ if (node.type === "UnaryExpression") {
72
+ const arg = generateCode(
73
+ node.argument,
74
+ failOnForbidden,
75
+ transformIdentifier
76
+ );
77
+ return `${node.operator}${arg}`;
78
+ }
79
+ if (node.type === "BinaryExpression") {
80
+ const left = generateCode(
81
+ node.left,
82
+ failOnForbidden,
83
+ transformIdentifier
84
+ );
85
+ const right = generateCode(
86
+ node.right,
87
+ failOnForbidden,
88
+ transformIdentifier
89
+ );
90
+ return `${left} ${node.operator} ${right}`;
91
+ }
92
+ if (node.type === "ArrayExpression") {
93
+ const elements = node.elements.map(
94
+ (element) => generateCode(element, failOnForbidden, transformIdentifier)
95
+ );
96
+ return `[${elements.join(", ")}]`;
97
+ }
98
+ if (node.type === "CallExpression") {
99
+ if (failOnForbidden) {
100
+ const callee2 = generateCode(
101
+ node.callee,
102
+ false,
103
+ transformIdentifier
104
+ );
105
+ throw Error(`Cannot call "${callee2}"`);
106
+ }
107
+ const callee = generateCode(
108
+ node.callee,
109
+ failOnForbidden,
110
+ transformIdentifier
111
+ );
112
+ const args = node.arguments.map(
113
+ (arg) => generateCode(arg, failOnForbidden, transformIdentifier)
114
+ );
115
+ return `${callee}(${args.join(", ")})`;
116
+ }
117
+ if (node.type === "ThisExpression") {
118
+ if (failOnForbidden) {
119
+ throw Error(`"this" is not supported`);
120
+ }
121
+ return "this";
122
+ }
123
+ if (node.type === "ConditionalExpression") {
124
+ throw Error("Ternary operator is not supported");
125
+ }
126
+ if (node.type === "Compound") {
127
+ throw Error("Cannot use multiple expressions");
128
+ }
129
+ node;
130
+ return "";
131
+ };
132
+ const validateExpression = (code, transformIdentifier = (id) => id) => {
133
+ const expression = (0, import_jsep.default)(code);
134
+ return generateCode(expression, true, transformIdentifier);
135
+ };
136
+ const executeExpressions = (variables, expressions) => {
137
+ const depsById = /* @__PURE__ */ new Map();
138
+ for (const [id, code] of expressions) {
139
+ const deps = /* @__PURE__ */ new Set();
140
+ validateExpression(code, (identifier) => {
141
+ if (variables.has(identifier) || expressions.has(identifier)) {
142
+ deps.add(identifier);
143
+ return identifier;
144
+ }
145
+ throw Error(`Unknown dependency "${identifier}"`);
146
+ });
147
+ depsById.set(id, deps);
148
+ }
149
+ const sortedExpressions = Array.from(expressions.keys()).sort(
150
+ (left, right) => {
151
+ if (depsById.get(left)?.has(right)) {
152
+ return 1;
153
+ }
154
+ if (depsById.get(right)?.has(left)) {
155
+ return -1;
156
+ }
157
+ return 0;
158
+ }
159
+ );
160
+ let header = "";
161
+ for (const [id, value] of variables) {
162
+ header += `const ${id} = ${JSON.stringify(value)};
163
+ `;
164
+ }
165
+ const values = /* @__PURE__ */ new Map();
166
+ for (const id of sortedExpressions) {
167
+ const code = expressions.get(id);
168
+ if (code === void 0) {
169
+ continue;
170
+ }
171
+ const executeFn = new Function(`${header}
172
+ return (${code});`);
173
+ const value = executeFn();
174
+ header += `const ${id} = ${JSON.stringify(value)};
175
+ `;
176
+ values.set(id, value);
177
+ }
178
+ return values;
179
+ };
180
+ const dataSourceVariablePrefix = "$ws$dataSource$";
181
+ const encodeDataSourceVariable = (id) => {
182
+ const encoded = id.replaceAll("-", "__DASH__");
183
+ return `${dataSourceVariablePrefix}${encoded}`;
184
+ };
185
+ const decodeDataSourceVariable = (name) => {
186
+ if (name.startsWith(dataSourceVariablePrefix)) {
187
+ const encoded = name.slice(dataSourceVariablePrefix.length);
188
+ return encoded.replaceAll("__DASH__", "-");
189
+ }
190
+ return;
191
+ };
package/lib/cjs/index.js CHANGED
@@ -21,11 +21,16 @@ var src_exports = {};
21
21
  __export(src_exports, {
22
22
  ReactSdkContext: () => import_context.ReactSdkContext,
23
23
  componentCategories: () => import_component_meta.componentCategories,
24
+ decodeDataSourceVariable: () => import_expression.decodeDataSourceVariable,
24
25
  defaultStates: () => import_component_meta.defaultStates,
26
+ encodeDataSourceVariable: () => import_expression.encodeDataSourceVariable,
27
+ executeExpressions: () => import_expression.executeExpressions,
25
28
  getInstanceIdFromComponentProps: () => import_props.getInstanceIdFromComponentProps,
26
29
  stateCategories: () => import_component_meta.stateCategories,
30
+ useInstanceProps: () => import_props.useInstanceProps,
27
31
  usePropAsset: () => import_props.usePropAsset,
28
- usePropUrl: () => import_props.usePropUrl
32
+ usePropUrl: () => import_props.usePropUrl,
33
+ validateExpression: () => import_expression.validateExpression
29
34
  });
30
35
  module.exports = __toCommonJS(src_exports);
31
36
  __reExport(src_exports, require("./css"), module.exports);
@@ -37,3 +42,4 @@ var import_component_meta = require("./components/component-meta");
37
42
  __reExport(src_exports, require("./embed-template"), module.exports);
38
43
  var import_props = require("./props");
39
44
  var import_context = require("./context");
45
+ var import_expression = require("./expression");
package/lib/cjs/props.js CHANGED
@@ -44,17 +44,35 @@ const getPropsByInstanceId = (props) => {
44
44
  return propsByInstanceId;
45
45
  };
46
46
  const useInstanceProps = (instanceId) => {
47
- const { propsByInstanceIdStore } = (0, import_react.useContext)(import_context.ReactSdkContext);
48
- const propsByInstanceId = (0, import_react2.useStore)(propsByInstanceIdStore);
49
- const instanceProps = propsByInstanceId.get(instanceId);
50
- const instancePropsObject = {};
51
- if (instanceProps) {
52
- for (const prop of instanceProps) {
53
- if (prop.type !== "asset" && prop.type !== "page") {
54
- instancePropsObject[prop.name] = prop.value;
47
+ const { propsByInstanceIdStore, dataSourceValuesStore } = (0, import_react.useContext)(import_context.ReactSdkContext);
48
+ const instancePropsObjectStore = (0, import_react.useMemo)(() => {
49
+ return (0, import_nanostores.computed)(
50
+ [propsByInstanceIdStore, dataSourceValuesStore],
51
+ (propsByInstanceId, dataSourceValues) => {
52
+ const instancePropsObject2 = {};
53
+ const instanceProps = propsByInstanceId.get(instanceId);
54
+ if (instanceProps === void 0) {
55
+ return instancePropsObject2;
56
+ }
57
+ for (const prop of instanceProps) {
58
+ if (prop.type === "asset" || prop.type === "page") {
59
+ continue;
60
+ }
61
+ if (prop.type === "dataSource") {
62
+ const dataSourceId = prop.value;
63
+ const value = dataSourceValues.get(dataSourceId);
64
+ if (value !== void 0) {
65
+ instancePropsObject2[prop.name] = value;
66
+ }
67
+ continue;
68
+ }
69
+ instancePropsObject2[prop.name] = prop.value;
70
+ }
71
+ return instancePropsObject2;
55
72
  }
56
- }
57
- }
73
+ );
74
+ }, [propsByInstanceIdStore, dataSourceValuesStore, instanceId]);
75
+ const instancePropsObject = (0, import_react2.useStore)(instancePropsObjectStore);
58
76
  return instancePropsObject;
59
77
  };
60
78
  const usePropAsset = (instanceId, name) => {
@@ -34,6 +34,8 @@ const createElementsTree = ({
34
34
  propsByInstanceIdStore,
35
35
  assetsStore,
36
36
  pagesStore,
37
+ dataSourceValuesStore,
38
+ onDataSourceUpdate,
37
39
  Component,
38
40
  components
39
41
  }) => {
@@ -69,9 +71,20 @@ const createElementsTree = ({
69
71
  propsByInstanceIdStore,
70
72
  assetsStore,
71
73
  pagesStore,
74
+ dataSourceValuesStore,
72
75
  renderer,
73
76
  imageBaseUrl,
74
- assetBaseUrl
77
+ assetBaseUrl,
78
+ setDataSourceValue: (instanceId, propName, value) => {
79
+ const propsByInstanceId = propsByInstanceIdStore.get();
80
+ const props = propsByInstanceId.get(instanceId);
81
+ const prop = props?.find((prop2) => prop2.name === propName);
82
+ if (prop?.type !== "dataSource") {
83
+ throw Error(`${propName} is not data source`);
84
+ }
85
+ const dataSourceId = prop.value;
86
+ onDataSourceUpdate(dataSourceId, value);
87
+ }
75
88
  },
76
89
  children: root
77
90
  }
@@ -21,15 +21,64 @@ __export(root_exports, {
21
21
  InstanceRoot: () => InstanceRoot
22
22
  });
23
23
  module.exports = __toCommonJS(root_exports);
24
+ var import_react = require("react");
24
25
  var import_nanostores = require("nanostores");
25
26
  var import_create_elements_tree = require("./create-elements-tree");
26
27
  var import_webstudio_component = require("./webstudio-component");
27
28
  var import_props = require("../props");
29
+ var import_expression = require("../expression");
30
+ const computeExpressions = (dataSources, dataSourceValues) => {
31
+ const outputValues = /* @__PURE__ */ new Map();
32
+ const variables = /* @__PURE__ */ new Map();
33
+ const expressions = /* @__PURE__ */ new Map();
34
+ for (const [dataSourceId, dataSource] of dataSources) {
35
+ const name = (0, import_expression.encodeDataSourceVariable)(dataSourceId);
36
+ if (dataSource.type === "variable") {
37
+ const value = dataSourceValues.get(dataSourceId) ?? dataSource.value.value;
38
+ variables.set(name, value);
39
+ outputValues.set(dataSourceId, value);
40
+ }
41
+ if (dataSource.type === "expression") {
42
+ expressions.set(name, dataSource.code);
43
+ }
44
+ }
45
+ try {
46
+ const outputVariables = (0, import_expression.executeExpressions)(variables, expressions);
47
+ for (const [name, value] of outputVariables) {
48
+ const id = (0, import_expression.decodeDataSourceVariable)(name);
49
+ if (id !== void 0) {
50
+ outputValues.set(id, value);
51
+ }
52
+ }
53
+ } catch (error) {
54
+ console.error(error);
55
+ }
56
+ return outputValues;
57
+ };
28
58
  const InstanceRoot = ({
29
59
  data,
30
60
  Component,
31
61
  components
32
62
  }) => {
63
+ const dataSourceVariablesStoreRef = (0, import_react.useRef)(void 0);
64
+ if (dataSourceVariablesStoreRef.current === void 0) {
65
+ const dataSourceVariables = /* @__PURE__ */ new Map();
66
+ for (const [dataSourceId, dataSource] of data.build.dataSources) {
67
+ dataSourceVariables.set(dataSourceId, dataSource);
68
+ }
69
+ dataSourceVariablesStoreRef.current = (0, import_nanostores.atom)(dataSourceVariables);
70
+ }
71
+ const dataSourceVariablesStore = dataSourceVariablesStoreRef.current;
72
+ const dataSourceValuesStoreRef = (0, import_react.useRef)(void 0);
73
+ if (dataSourceValuesStoreRef.current === void 0) {
74
+ dataSourceValuesStoreRef.current = (0, import_nanostores.computed)(
75
+ dataSourceVariablesStore,
76
+ (dataSourceVariables) => {
77
+ return computeExpressions(data.build.dataSources, dataSourceVariables);
78
+ }
79
+ );
80
+ }
81
+ const dataSourceValuesStore = dataSourceValuesStoreRef.current;
33
82
  return (0, import_create_elements_tree.createElementsTree)({
34
83
  imageBaseUrl: data.params?.imageBaseUrl ?? "/",
35
84
  assetBaseUrl: data.params?.assetBaseUrl ?? "/",
@@ -40,6 +89,12 @@ const InstanceRoot = ({
40
89
  ),
41
90
  assetsStore: (0, import_nanostores.atom)(new Map(data.assets.map((asset) => [asset.id, asset]))),
42
91
  pagesStore: (0, import_nanostores.atom)(new Map(data.pages.map((page) => [page.id, page]))),
92
+ dataSourceValuesStore,
93
+ onDataSourceUpdate: (dataSourceId, value) => {
94
+ const dataSourceVariables = new Map(dataSourceVariablesStore.get());
95
+ dataSourceVariables.set(dataSourceId, value);
96
+ dataSourceVariablesStore.set(dataSourceVariables);
97
+ },
43
98
  Component: Component ?? import_webstudio_component.WebstudioComponent,
44
99
  components
45
100
  });
@@ -22,7 +22,8 @@ __export(webstudio_component_exports, {
22
22
  collapsedAttribute: () => collapsedAttribute,
23
23
  componentAttribute: () => componentAttribute,
24
24
  idAttribute: () => idAttribute,
25
- renderWebstudioComponentChildren: () => renderWebstudioComponentChildren
25
+ renderWebstudioComponentChildren: () => renderWebstudioComponentChildren,
26
+ showAttribute: () => showAttribute
26
27
  });
27
28
  module.exports = __toCommonJS(webstudio_component_exports);
28
29
  var import_jsx_runtime = require("react/jsx-runtime");
@@ -50,13 +51,18 @@ const WebstudioComponent = ({
50
51
  components,
51
52
  ...rest
52
53
  }) => {
53
- const instanceProps = (0, import_props.useInstanceProps)(instance.id);
54
+ const { [showAttribute]: show = true, ...instanceProps } = (0, import_props.useInstanceProps)(
55
+ instance.id
56
+ );
54
57
  const props = {
55
58
  ...instanceProps,
56
59
  ...rest,
57
60
  [idAttribute]: instance.id,
58
61
  [componentAttribute]: instance.component
59
62
  };
63
+ if (show === false) {
64
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, {});
65
+ }
60
66
  const Component = components.get(instance.component);
61
67
  if (Component === void 0) {
62
68
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, {});
@@ -65,4 +71,5 @@ const WebstudioComponent = ({
65
71
  };
66
72
  const idAttribute = "data-ws-id";
67
73
  const componentAttribute = "data-ws-component";
74
+ const showAttribute = "data-ws-show";
68
75
  const collapsedAttribute = "data-ws-collapsed";
package/lib/context.js CHANGED
@@ -5,7 +5,11 @@ const ReactSdkContext = createContext({
5
5
  assetBaseUrl: "/",
6
6
  propsByInstanceIdStore: atom(/* @__PURE__ */ new Map()),
7
7
  assetsStore: atom(/* @__PURE__ */ new Map()),
8
- pagesStore: atom(/* @__PURE__ */ new Map())
8
+ pagesStore: atom(/* @__PURE__ */ new Map()),
9
+ dataSourceValuesStore: atom(/* @__PURE__ */ new Map()),
10
+ setDataSourceValue: () => {
11
+ throw Error("React SDK setDataSourceValue is not implemented");
12
+ }
9
13
  });
10
14
  export {
11
15
  ReactSdkContext
@@ -72,9 +72,17 @@ const body = [
72
72
  property: "fontFamily",
73
73
  value: {
74
74
  type: "keyword",
75
- value: `system-ui, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji'`
75
+ value: "Arial, sans-serif"
76
76
  }
77
77
  },
78
+ {
79
+ property: "fontSize",
80
+ value: { type: "unit", unit: "px", value: 16 }
81
+ },
82
+ {
83
+ property: "lineHeight",
84
+ value: { type: "unit", unit: "number", value: 1.2 }
85
+ },
78
86
  boxSizing,
79
87
  ...borders
80
88
  ];