@webstudio-is/react-sdk 0.74.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.
- package/lib/cjs/components/component-meta.js +1 -0
- package/lib/cjs/context.js +5 -1
- package/lib/cjs/css/global-rules.js +1 -1
- package/lib/cjs/css/normalize.js +10 -13
- package/lib/cjs/embed-template.js +68 -3
- package/lib/cjs/expression.js +191 -0
- package/lib/cjs/index.js +7 -1
- package/lib/cjs/props.js +28 -10
- package/lib/cjs/tree/create-elements-tree.js +14 -1
- package/lib/cjs/tree/root.js +55 -0
- package/lib/cjs/tree/webstudio-component.js +9 -2
- package/lib/components/component-meta.js +1 -0
- package/lib/context.js +5 -1
- package/lib/css/global-rules.js +1 -1
- package/lib/css/normalize.js +10 -13
- package/lib/embed-template.js +68 -3
- package/lib/expression.js +161 -0
- package/lib/index.js +13 -1
- package/lib/props.js +28 -10
- package/lib/tree/create-elements-tree.js +14 -1
- package/lib/tree/root.js +63 -1
- package/lib/tree/webstudio-component.js +9 -2
- package/lib/types/components/component-meta.d.ts +115 -0
- package/lib/types/context.d.ts +3 -0
- package/lib/types/css/normalize.d.ts +1316 -0
- package/lib/types/embed-template.d.ts +512 -0
- package/lib/types/expression.d.ts +6 -0
- package/lib/types/expression.test.d.ts +1 -0
- package/lib/types/index.d.ts +2 -1
- package/lib/types/props.d.ts +8 -7
- package/lib/types/tree/create-elements-tree.d.ts +4 -2
- package/lib/types/tree/root.d.ts +3 -3
- package/lib/types/tree/webstudio-component.d.ts +1 -0
- package/package.json +15 -15
- package/src/components/component-meta.ts +1 -0
- package/src/context.tsx +11 -0
- package/src/css/global-rules.ts +2 -1
- package/src/css/normalize.ts +10 -13
- package/src/embed-template.test.ts +177 -1
- package/src/embed-template.ts +73 -2
- package/src/expression.test.ts +122 -0
- package/src/expression.ts +183 -0
- package/src/index.ts +7 -0
- package/src/props.ts +29 -10
- package/src/tree/create-elements-tree.tsx +20 -1
- package/src/tree/root.ts +81 -4
- package/src/tree/webstudio-component.tsx +7 -1
package/lib/css/normalize.js
CHANGED
|
@@ -24,18 +24,7 @@ const h5 = baseStyle;
|
|
|
24
24
|
const h6 = baseStyle;
|
|
25
25
|
const i = baseStyle;
|
|
26
26
|
const img = baseStyle;
|
|
27
|
-
const a =
|
|
28
|
-
...baseStyle,
|
|
29
|
-
{
|
|
30
|
-
property: "color",
|
|
31
|
-
value: { type: "rgb", r: 0, g: 0, b: 238, alpha: 1 }
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
state: ":visited",
|
|
35
|
-
property: "color",
|
|
36
|
-
value: { type: "rgb", r: 85, g: 26, b: 139, alpha: 1 }
|
|
37
|
-
}
|
|
38
|
-
];
|
|
27
|
+
const a = baseStyle;
|
|
39
28
|
const li = baseStyle;
|
|
40
29
|
const ul = baseStyle;
|
|
41
30
|
const ol = baseStyle;
|
|
@@ -83,9 +72,17 @@ const body = [
|
|
|
83
72
|
property: "fontFamily",
|
|
84
73
|
value: {
|
|
85
74
|
type: "keyword",
|
|
86
|
-
value:
|
|
75
|
+
value: "Arial, sans-serif"
|
|
87
76
|
}
|
|
88
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
|
+
},
|
|
89
86
|
boxSizing,
|
|
90
87
|
...borders
|
|
91
88
|
];
|
package/lib/embed-template.js
CHANGED
|
@@ -1,29 +1,45 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { nanoid } from "nanoid";
|
|
3
3
|
import { StyleValue } from "@webstudio-is/css-data";
|
|
4
|
+
import { encodeDataSourceVariable, validateExpression } from "./expression";
|
|
4
5
|
const EmbedTemplateText = z.object({
|
|
5
6
|
type: z.literal("text"),
|
|
6
7
|
value: z.string()
|
|
7
8
|
});
|
|
9
|
+
const DataSourceRef = z.union([
|
|
10
|
+
z.object({
|
|
11
|
+
type: z.literal("variable"),
|
|
12
|
+
name: z.string()
|
|
13
|
+
}),
|
|
14
|
+
z.object({
|
|
15
|
+
type: z.literal("expression"),
|
|
16
|
+
name: z.string(),
|
|
17
|
+
code: z.string()
|
|
18
|
+
})
|
|
19
|
+
]);
|
|
8
20
|
const EmbedTemplateProp = z.union([
|
|
9
21
|
z.object({
|
|
10
22
|
type: z.literal("number"),
|
|
11
23
|
name: z.string(),
|
|
24
|
+
dataSourceRef: z.optional(DataSourceRef),
|
|
12
25
|
value: z.number()
|
|
13
26
|
}),
|
|
14
27
|
z.object({
|
|
15
28
|
type: z.literal("string"),
|
|
16
29
|
name: z.string(),
|
|
30
|
+
dataSourceRef: z.optional(DataSourceRef),
|
|
17
31
|
value: z.string()
|
|
18
32
|
}),
|
|
19
33
|
z.object({
|
|
20
34
|
type: z.literal("boolean"),
|
|
21
35
|
name: z.string(),
|
|
36
|
+
dataSourceRef: z.optional(DataSourceRef),
|
|
22
37
|
value: z.boolean()
|
|
23
38
|
}),
|
|
24
39
|
z.object({
|
|
25
40
|
type: z.literal("string[]"),
|
|
26
41
|
name: z.string(),
|
|
42
|
+
dataSourceRef: z.optional(DataSourceRef),
|
|
27
43
|
value: z.array(z.string())
|
|
28
44
|
})
|
|
29
45
|
]);
|
|
@@ -47,17 +63,52 @@ const EmbedTemplateInstance = z.lazy(
|
|
|
47
63
|
const WsEmbedTemplate = z.lazy(
|
|
48
64
|
() => z.array(z.union([EmbedTemplateInstance, EmbedTemplateText]))
|
|
49
65
|
);
|
|
50
|
-
const createInstancesFromTemplate = (treeTemplate, instances, props, styleSourceSelections, styleSources, styles, defaultBreakpointId) => {
|
|
66
|
+
const createInstancesFromTemplate = (treeTemplate, instances, props, dataSourceByRef, styleSourceSelections, styleSources, styles, defaultBreakpointId) => {
|
|
51
67
|
const parentChildren = [];
|
|
52
68
|
for (const item of treeTemplate) {
|
|
53
69
|
if (item.type === "instance") {
|
|
54
70
|
const instanceId = nanoid();
|
|
55
71
|
if (item.props) {
|
|
56
72
|
for (const prop of item.props) {
|
|
73
|
+
const propId = nanoid();
|
|
74
|
+
if (prop.dataSourceRef === void 0) {
|
|
75
|
+
props.push({ id: propId, instanceId, ...prop });
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
let dataSource = dataSourceByRef.get(prop.dataSourceRef.name);
|
|
79
|
+
if (dataSource === void 0) {
|
|
80
|
+
const id = nanoid();
|
|
81
|
+
const { name: propName, dataSourceRef, ...rest } = prop;
|
|
82
|
+
if (dataSourceRef.type === "variable") {
|
|
83
|
+
dataSource = {
|
|
84
|
+
type: "variable",
|
|
85
|
+
id,
|
|
86
|
+
// the first instance where data source is appeared in becomes its scope
|
|
87
|
+
scopeInstanceId: instanceId,
|
|
88
|
+
name: dataSourceRef.name,
|
|
89
|
+
value: rest
|
|
90
|
+
};
|
|
91
|
+
dataSourceByRef.set(dataSourceRef.name, dataSource);
|
|
92
|
+
} else if (dataSourceRef.type === "expression") {
|
|
93
|
+
dataSource = {
|
|
94
|
+
type: "expression",
|
|
95
|
+
id,
|
|
96
|
+
scopeInstanceId: instanceId,
|
|
97
|
+
name: dataSourceRef.name,
|
|
98
|
+
code: dataSourceRef.code
|
|
99
|
+
};
|
|
100
|
+
dataSourceByRef.set(dataSourceRef.name, dataSource);
|
|
101
|
+
} else {
|
|
102
|
+
dataSourceRef;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
57
106
|
props.push({
|
|
58
|
-
id:
|
|
107
|
+
id: propId,
|
|
59
108
|
instanceId,
|
|
60
|
-
|
|
109
|
+
type: "dataSource",
|
|
110
|
+
name: prop.name,
|
|
111
|
+
value: dataSource.id
|
|
61
112
|
});
|
|
62
113
|
}
|
|
63
114
|
}
|
|
@@ -93,6 +144,7 @@ const createInstancesFromTemplate = (treeTemplate, instances, props, styleSource
|
|
|
93
144
|
item.children,
|
|
94
145
|
instances,
|
|
95
146
|
props,
|
|
147
|
+
dataSourceByRef,
|
|
96
148
|
styleSourceSelections,
|
|
97
149
|
styleSources,
|
|
98
150
|
styles,
|
|
@@ -115,6 +167,7 @@ const createInstancesFromTemplate = (treeTemplate, instances, props, styleSource
|
|
|
115
167
|
const generateDataFromEmbedTemplate = (treeTemplate, defaultBreakpointId) => {
|
|
116
168
|
const instances = [];
|
|
117
169
|
const props = [];
|
|
170
|
+
const dataSourceByRef = /* @__PURE__ */ new Map();
|
|
118
171
|
const styleSourceSelections = [];
|
|
119
172
|
const styleSources = [];
|
|
120
173
|
const styles = [];
|
|
@@ -122,15 +175,27 @@ const generateDataFromEmbedTemplate = (treeTemplate, defaultBreakpointId) => {
|
|
|
122
175
|
treeTemplate,
|
|
123
176
|
instances,
|
|
124
177
|
props,
|
|
178
|
+
dataSourceByRef,
|
|
125
179
|
styleSourceSelections,
|
|
126
180
|
styleSources,
|
|
127
181
|
styles,
|
|
128
182
|
defaultBreakpointId
|
|
129
183
|
);
|
|
184
|
+
const dataSources = [];
|
|
185
|
+
for (const dataSource of dataSourceByRef.values()) {
|
|
186
|
+
if (dataSource.type === "expression") {
|
|
187
|
+
dataSource.code = validateExpression(dataSource.code, (ref) => {
|
|
188
|
+
const id = dataSourceByRef.get(ref)?.id ?? ref;
|
|
189
|
+
return encodeDataSourceVariable(id);
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
dataSources.push(dataSource);
|
|
193
|
+
}
|
|
130
194
|
return {
|
|
131
195
|
children,
|
|
132
196
|
instances,
|
|
133
197
|
props,
|
|
198
|
+
dataSources,
|
|
134
199
|
styleSourceSelections,
|
|
135
200
|
styleSources,
|
|
136
201
|
styles
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import jsep from "jsep";
|
|
2
|
+
const generateCode = (node, failOnForbidden, transformIdentifier) => {
|
|
3
|
+
if (node.type === "Identifier") {
|
|
4
|
+
return transformIdentifier(node.name);
|
|
5
|
+
}
|
|
6
|
+
if (node.type === "MemberExpression") {
|
|
7
|
+
if (failOnForbidden) {
|
|
8
|
+
const object2 = generateCode(
|
|
9
|
+
node.object,
|
|
10
|
+
false,
|
|
11
|
+
transformIdentifier
|
|
12
|
+
);
|
|
13
|
+
const property2 = generateCode(
|
|
14
|
+
node.property,
|
|
15
|
+
false,
|
|
16
|
+
transformIdentifier
|
|
17
|
+
);
|
|
18
|
+
throw Error(`Cannot access "${property2}" of "${object2}"`);
|
|
19
|
+
}
|
|
20
|
+
const object = generateCode(
|
|
21
|
+
node.object,
|
|
22
|
+
failOnForbidden,
|
|
23
|
+
transformIdentifier
|
|
24
|
+
);
|
|
25
|
+
const property = generateCode(
|
|
26
|
+
node.property,
|
|
27
|
+
failOnForbidden,
|
|
28
|
+
transformIdentifier
|
|
29
|
+
);
|
|
30
|
+
return `${object}.${property}`;
|
|
31
|
+
}
|
|
32
|
+
if (node.type === "Literal") {
|
|
33
|
+
return node.raw;
|
|
34
|
+
}
|
|
35
|
+
if (node.type === "UnaryExpression") {
|
|
36
|
+
const arg = generateCode(
|
|
37
|
+
node.argument,
|
|
38
|
+
failOnForbidden,
|
|
39
|
+
transformIdentifier
|
|
40
|
+
);
|
|
41
|
+
return `${node.operator}${arg}`;
|
|
42
|
+
}
|
|
43
|
+
if (node.type === "BinaryExpression") {
|
|
44
|
+
const left = generateCode(
|
|
45
|
+
node.left,
|
|
46
|
+
failOnForbidden,
|
|
47
|
+
transformIdentifier
|
|
48
|
+
);
|
|
49
|
+
const right = generateCode(
|
|
50
|
+
node.right,
|
|
51
|
+
failOnForbidden,
|
|
52
|
+
transformIdentifier
|
|
53
|
+
);
|
|
54
|
+
return `${left} ${node.operator} ${right}`;
|
|
55
|
+
}
|
|
56
|
+
if (node.type === "ArrayExpression") {
|
|
57
|
+
const elements = node.elements.map(
|
|
58
|
+
(element) => generateCode(element, failOnForbidden, transformIdentifier)
|
|
59
|
+
);
|
|
60
|
+
return `[${elements.join(", ")}]`;
|
|
61
|
+
}
|
|
62
|
+
if (node.type === "CallExpression") {
|
|
63
|
+
if (failOnForbidden) {
|
|
64
|
+
const callee2 = generateCode(
|
|
65
|
+
node.callee,
|
|
66
|
+
false,
|
|
67
|
+
transformIdentifier
|
|
68
|
+
);
|
|
69
|
+
throw Error(`Cannot call "${callee2}"`);
|
|
70
|
+
}
|
|
71
|
+
const callee = generateCode(
|
|
72
|
+
node.callee,
|
|
73
|
+
failOnForbidden,
|
|
74
|
+
transformIdentifier
|
|
75
|
+
);
|
|
76
|
+
const args = node.arguments.map(
|
|
77
|
+
(arg) => generateCode(arg, failOnForbidden, transformIdentifier)
|
|
78
|
+
);
|
|
79
|
+
return `${callee}(${args.join(", ")})`;
|
|
80
|
+
}
|
|
81
|
+
if (node.type === "ThisExpression") {
|
|
82
|
+
if (failOnForbidden) {
|
|
83
|
+
throw Error(`"this" is not supported`);
|
|
84
|
+
}
|
|
85
|
+
return "this";
|
|
86
|
+
}
|
|
87
|
+
if (node.type === "ConditionalExpression") {
|
|
88
|
+
throw Error("Ternary operator is not supported");
|
|
89
|
+
}
|
|
90
|
+
if (node.type === "Compound") {
|
|
91
|
+
throw Error("Cannot use multiple expressions");
|
|
92
|
+
}
|
|
93
|
+
node;
|
|
94
|
+
return "";
|
|
95
|
+
};
|
|
96
|
+
const validateExpression = (code, transformIdentifier = (id) => id) => {
|
|
97
|
+
const expression = jsep(code);
|
|
98
|
+
return generateCode(expression, true, transformIdentifier);
|
|
99
|
+
};
|
|
100
|
+
const executeExpressions = (variables, expressions) => {
|
|
101
|
+
const depsById = /* @__PURE__ */ new Map();
|
|
102
|
+
for (const [id, code] of expressions) {
|
|
103
|
+
const deps = /* @__PURE__ */ new Set();
|
|
104
|
+
validateExpression(code, (identifier) => {
|
|
105
|
+
if (variables.has(identifier) || expressions.has(identifier)) {
|
|
106
|
+
deps.add(identifier);
|
|
107
|
+
return identifier;
|
|
108
|
+
}
|
|
109
|
+
throw Error(`Unknown dependency "${identifier}"`);
|
|
110
|
+
});
|
|
111
|
+
depsById.set(id, deps);
|
|
112
|
+
}
|
|
113
|
+
const sortedExpressions = Array.from(expressions.keys()).sort(
|
|
114
|
+
(left, right) => {
|
|
115
|
+
if (depsById.get(left)?.has(right)) {
|
|
116
|
+
return 1;
|
|
117
|
+
}
|
|
118
|
+
if (depsById.get(right)?.has(left)) {
|
|
119
|
+
return -1;
|
|
120
|
+
}
|
|
121
|
+
return 0;
|
|
122
|
+
}
|
|
123
|
+
);
|
|
124
|
+
let header = "";
|
|
125
|
+
for (const [id, value] of variables) {
|
|
126
|
+
header += `const ${id} = ${JSON.stringify(value)};
|
|
127
|
+
`;
|
|
128
|
+
}
|
|
129
|
+
const values = /* @__PURE__ */ new Map();
|
|
130
|
+
for (const id of sortedExpressions) {
|
|
131
|
+
const code = expressions.get(id);
|
|
132
|
+
if (code === void 0) {
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
const executeFn = new Function(`${header}
|
|
136
|
+
return (${code});`);
|
|
137
|
+
const value = executeFn();
|
|
138
|
+
header += `const ${id} = ${JSON.stringify(value)};
|
|
139
|
+
`;
|
|
140
|
+
values.set(id, value);
|
|
141
|
+
}
|
|
142
|
+
return values;
|
|
143
|
+
};
|
|
144
|
+
const dataSourceVariablePrefix = "$ws$dataSource$";
|
|
145
|
+
const encodeDataSourceVariable = (id) => {
|
|
146
|
+
const encoded = id.replaceAll("-", "__DASH__");
|
|
147
|
+
return `${dataSourceVariablePrefix}${encoded}`;
|
|
148
|
+
};
|
|
149
|
+
const decodeDataSourceVariable = (name) => {
|
|
150
|
+
if (name.startsWith(dataSourceVariablePrefix)) {
|
|
151
|
+
const encoded = name.slice(dataSourceVariablePrefix.length);
|
|
152
|
+
return encoded.replaceAll("__DASH__", "-");
|
|
153
|
+
}
|
|
154
|
+
return;
|
|
155
|
+
};
|
|
156
|
+
export {
|
|
157
|
+
decodeDataSourceVariable,
|
|
158
|
+
encodeDataSourceVariable,
|
|
159
|
+
executeExpressions,
|
|
160
|
+
validateExpression
|
|
161
|
+
};
|
package/lib/index.js
CHANGED
|
@@ -10,17 +10,29 @@ import {
|
|
|
10
10
|
} from "./components/component-meta";
|
|
11
11
|
export * from "./embed-template";
|
|
12
12
|
import {
|
|
13
|
+
useInstanceProps,
|
|
13
14
|
usePropUrl,
|
|
14
15
|
usePropAsset,
|
|
15
16
|
getInstanceIdFromComponentProps
|
|
16
17
|
} from "./props";
|
|
17
18
|
import { ReactSdkContext } from "./context";
|
|
19
|
+
import {
|
|
20
|
+
validateExpression,
|
|
21
|
+
executeExpressions,
|
|
22
|
+
encodeDataSourceVariable,
|
|
23
|
+
decodeDataSourceVariable
|
|
24
|
+
} from "./expression";
|
|
18
25
|
export {
|
|
19
26
|
ReactSdkContext,
|
|
20
27
|
componentCategories,
|
|
28
|
+
decodeDataSourceVariable,
|
|
21
29
|
defaultStates,
|
|
30
|
+
encodeDataSourceVariable,
|
|
31
|
+
executeExpressions,
|
|
22
32
|
getInstanceIdFromComponentProps,
|
|
23
33
|
stateCategories,
|
|
34
|
+
useInstanceProps,
|
|
24
35
|
usePropAsset,
|
|
25
|
-
usePropUrl
|
|
36
|
+
usePropUrl,
|
|
37
|
+
validateExpression
|
|
26
38
|
};
|
package/lib/props.js
CHANGED
|
@@ -16,17 +16,35 @@ const getPropsByInstanceId = (props) => {
|
|
|
16
16
|
return propsByInstanceId;
|
|
17
17
|
};
|
|
18
18
|
const useInstanceProps = (instanceId) => {
|
|
19
|
-
const { propsByInstanceIdStore } = useContext(ReactSdkContext);
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
19
|
+
const { propsByInstanceIdStore, dataSourceValuesStore } = useContext(ReactSdkContext);
|
|
20
|
+
const instancePropsObjectStore = useMemo(() => {
|
|
21
|
+
return computed(
|
|
22
|
+
[propsByInstanceIdStore, dataSourceValuesStore],
|
|
23
|
+
(propsByInstanceId, dataSourceValues) => {
|
|
24
|
+
const instancePropsObject2 = {};
|
|
25
|
+
const instanceProps = propsByInstanceId.get(instanceId);
|
|
26
|
+
if (instanceProps === void 0) {
|
|
27
|
+
return instancePropsObject2;
|
|
28
|
+
}
|
|
29
|
+
for (const prop of instanceProps) {
|
|
30
|
+
if (prop.type === "asset" || prop.type === "page") {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
if (prop.type === "dataSource") {
|
|
34
|
+
const dataSourceId = prop.value;
|
|
35
|
+
const value = dataSourceValues.get(dataSourceId);
|
|
36
|
+
if (value !== void 0) {
|
|
37
|
+
instancePropsObject2[prop.name] = value;
|
|
38
|
+
}
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
instancePropsObject2[prop.name] = prop.value;
|
|
42
|
+
}
|
|
43
|
+
return instancePropsObject2;
|
|
27
44
|
}
|
|
28
|
-
|
|
29
|
-
}
|
|
45
|
+
);
|
|
46
|
+
}, [propsByInstanceIdStore, dataSourceValuesStore, instanceId]);
|
|
47
|
+
const instancePropsObject = useStore(instancePropsObjectStore);
|
|
30
48
|
return instancePropsObject;
|
|
31
49
|
};
|
|
32
50
|
const usePropAsset = (instanceId, name) => {
|
|
@@ -11,6 +11,8 @@ const createElementsTree = ({
|
|
|
11
11
|
propsByInstanceIdStore,
|
|
12
12
|
assetsStore,
|
|
13
13
|
pagesStore,
|
|
14
|
+
dataSourceValuesStore,
|
|
15
|
+
onDataSourceUpdate,
|
|
14
16
|
Component,
|
|
15
17
|
components
|
|
16
18
|
}) => {
|
|
@@ -46,9 +48,20 @@ const createElementsTree = ({
|
|
|
46
48
|
propsByInstanceIdStore,
|
|
47
49
|
assetsStore,
|
|
48
50
|
pagesStore,
|
|
51
|
+
dataSourceValuesStore,
|
|
49
52
|
renderer,
|
|
50
53
|
imageBaseUrl,
|
|
51
|
-
assetBaseUrl
|
|
54
|
+
assetBaseUrl,
|
|
55
|
+
setDataSourceValue: (instanceId, propName, value) => {
|
|
56
|
+
const propsByInstanceId = propsByInstanceIdStore.get();
|
|
57
|
+
const props = propsByInstanceId.get(instanceId);
|
|
58
|
+
const prop = props?.find((prop2) => prop2.name === propName);
|
|
59
|
+
if (prop?.type !== "dataSource") {
|
|
60
|
+
throw Error(`${propName} is not data source`);
|
|
61
|
+
}
|
|
62
|
+
const dataSourceId = prop.value;
|
|
63
|
+
onDataSourceUpdate(dataSourceId, value);
|
|
64
|
+
}
|
|
52
65
|
},
|
|
53
66
|
children: root
|
|
54
67
|
}
|
package/lib/tree/root.js
CHANGED
|
@@ -1,12 +1,68 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useRef } from "react";
|
|
2
|
+
import {
|
|
3
|
+
atom,
|
|
4
|
+
computed
|
|
5
|
+
} from "nanostores";
|
|
2
6
|
import { createElementsTree } from "./create-elements-tree";
|
|
3
7
|
import { WebstudioComponent } from "./webstudio-component";
|
|
4
8
|
import { getPropsByInstanceId } from "../props";
|
|
9
|
+
import {
|
|
10
|
+
executeExpressions,
|
|
11
|
+
encodeDataSourceVariable,
|
|
12
|
+
decodeDataSourceVariable
|
|
13
|
+
} from "../expression";
|
|
14
|
+
const computeExpressions = (dataSources, dataSourceValues) => {
|
|
15
|
+
const outputValues = /* @__PURE__ */ new Map();
|
|
16
|
+
const variables = /* @__PURE__ */ new Map();
|
|
17
|
+
const expressions = /* @__PURE__ */ new Map();
|
|
18
|
+
for (const [dataSourceId, dataSource] of dataSources) {
|
|
19
|
+
const name = encodeDataSourceVariable(dataSourceId);
|
|
20
|
+
if (dataSource.type === "variable") {
|
|
21
|
+
const value = dataSourceValues.get(dataSourceId) ?? dataSource.value.value;
|
|
22
|
+
variables.set(name, value);
|
|
23
|
+
outputValues.set(dataSourceId, value);
|
|
24
|
+
}
|
|
25
|
+
if (dataSource.type === "expression") {
|
|
26
|
+
expressions.set(name, dataSource.code);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
const outputVariables = executeExpressions(variables, expressions);
|
|
31
|
+
for (const [name, value] of outputVariables) {
|
|
32
|
+
const id = decodeDataSourceVariable(name);
|
|
33
|
+
if (id !== void 0) {
|
|
34
|
+
outputValues.set(id, value);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
} catch (error) {
|
|
38
|
+
console.error(error);
|
|
39
|
+
}
|
|
40
|
+
return outputValues;
|
|
41
|
+
};
|
|
5
42
|
const InstanceRoot = ({
|
|
6
43
|
data,
|
|
7
44
|
Component,
|
|
8
45
|
components
|
|
9
46
|
}) => {
|
|
47
|
+
const dataSourceVariablesStoreRef = useRef(void 0);
|
|
48
|
+
if (dataSourceVariablesStoreRef.current === void 0) {
|
|
49
|
+
const dataSourceVariables = /* @__PURE__ */ new Map();
|
|
50
|
+
for (const [dataSourceId, dataSource] of data.build.dataSources) {
|
|
51
|
+
dataSourceVariables.set(dataSourceId, dataSource);
|
|
52
|
+
}
|
|
53
|
+
dataSourceVariablesStoreRef.current = atom(dataSourceVariables);
|
|
54
|
+
}
|
|
55
|
+
const dataSourceVariablesStore = dataSourceVariablesStoreRef.current;
|
|
56
|
+
const dataSourceValuesStoreRef = useRef(void 0);
|
|
57
|
+
if (dataSourceValuesStoreRef.current === void 0) {
|
|
58
|
+
dataSourceValuesStoreRef.current = computed(
|
|
59
|
+
dataSourceVariablesStore,
|
|
60
|
+
(dataSourceVariables) => {
|
|
61
|
+
return computeExpressions(data.build.dataSources, dataSourceVariables);
|
|
62
|
+
}
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
const dataSourceValuesStore = dataSourceValuesStoreRef.current;
|
|
10
66
|
return createElementsTree({
|
|
11
67
|
imageBaseUrl: data.params?.imageBaseUrl ?? "/",
|
|
12
68
|
assetBaseUrl: data.params?.assetBaseUrl ?? "/",
|
|
@@ -17,6 +73,12 @@ const InstanceRoot = ({
|
|
|
17
73
|
),
|
|
18
74
|
assetsStore: atom(new Map(data.assets.map((asset) => [asset.id, asset]))),
|
|
19
75
|
pagesStore: atom(new Map(data.pages.map((page) => [page.id, page]))),
|
|
76
|
+
dataSourceValuesStore,
|
|
77
|
+
onDataSourceUpdate: (dataSourceId, value) => {
|
|
78
|
+
const dataSourceVariables = new Map(dataSourceVariablesStore.get());
|
|
79
|
+
dataSourceVariables.set(dataSourceId, value);
|
|
80
|
+
dataSourceVariablesStore.set(dataSourceVariables);
|
|
81
|
+
},
|
|
20
82
|
Component: Component ?? WebstudioComponent,
|
|
21
83
|
components
|
|
22
84
|
});
|
|
@@ -23,13 +23,18 @@ const WebstudioComponent = ({
|
|
|
23
23
|
components,
|
|
24
24
|
...rest
|
|
25
25
|
}) => {
|
|
26
|
-
const instanceProps = useInstanceProps(
|
|
26
|
+
const { [showAttribute]: show = true, ...instanceProps } = useInstanceProps(
|
|
27
|
+
instance.id
|
|
28
|
+
);
|
|
27
29
|
const props = {
|
|
28
30
|
...instanceProps,
|
|
29
31
|
...rest,
|
|
30
32
|
[idAttribute]: instance.id,
|
|
31
33
|
[componentAttribute]: instance.component
|
|
32
34
|
};
|
|
35
|
+
if (show === false) {
|
|
36
|
+
return /* @__PURE__ */ jsx(Fragment, {});
|
|
37
|
+
}
|
|
33
38
|
const Component = components.get(instance.component);
|
|
34
39
|
if (Component === void 0) {
|
|
35
40
|
return /* @__PURE__ */ jsx(Fragment, {});
|
|
@@ -38,11 +43,13 @@ const WebstudioComponent = ({
|
|
|
38
43
|
};
|
|
39
44
|
const idAttribute = "data-ws-id";
|
|
40
45
|
const componentAttribute = "data-ws-component";
|
|
46
|
+
const showAttribute = "data-ws-show";
|
|
41
47
|
const collapsedAttribute = "data-ws-collapsed";
|
|
42
48
|
export {
|
|
43
49
|
WebstudioComponent,
|
|
44
50
|
collapsedAttribute,
|
|
45
51
|
componentAttribute,
|
|
46
52
|
idAttribute,
|
|
47
|
-
renderWebstudioComponentChildren
|
|
53
|
+
renderWebstudioComponentChildren,
|
|
54
|
+
showAttribute
|
|
48
55
|
};
|