@webstudio-is/react-sdk 0.76.0 → 0.77.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/css/normalize.js +42 -22
- package/lib/cjs/css/presets.js +111 -1
- package/lib/cjs/expression.js +43 -21
- package/lib/cjs/index.js +1 -0
- package/lib/cjs/tree/root.js +18 -35
- package/lib/css/normalize.js +32 -22
- package/lib/css/presets.js +111 -1
- package/lib/expression.js +43 -21
- package/lib/index.js +2 -0
- package/lib/tree/root.js +18 -39
- package/lib/types/css/normalize.d.ts +520 -0
- package/lib/types/css/presets.d.ts +282 -0
- package/lib/types/expression.d.ts +5 -0
- package/lib/types/index.d.ts +1 -1
- package/lib/types/tree/root.d.ts +4 -2
- package/package.json +7 -7
- package/src/css/normalize.ts +31 -22
- package/src/css/presets.ts +110 -0
- package/src/expression.test.ts +27 -2
- package/src/expression.ts +58 -24
- package/src/index.ts +1 -0
- package/src/tree/root.ts +29 -49
package/src/expression.ts
CHANGED
|
@@ -111,15 +111,42 @@ export const validateExpression = (
|
|
|
111
111
|
return generateCode(expression, true, transformIdentifier);
|
|
112
112
|
};
|
|
113
113
|
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
const sortTopologically = (
|
|
115
|
+
list: Set<string>,
|
|
116
|
+
depsById: Map<string, Set<string>>,
|
|
117
|
+
explored = new Set<string>(),
|
|
118
|
+
sorted: string[] = []
|
|
119
|
+
) => {
|
|
120
|
+
for (const id of list) {
|
|
121
|
+
if (explored.has(id)) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
explored.add(id);
|
|
125
|
+
const deps = depsById.get(id);
|
|
126
|
+
if (deps) {
|
|
127
|
+
sortTopologically(deps, depsById, explored, sorted);
|
|
128
|
+
}
|
|
129
|
+
sorted.push(id);
|
|
130
|
+
}
|
|
131
|
+
return sorted;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Generates a function body expecting map as _variables argument
|
|
136
|
+
* and outputing map of results
|
|
137
|
+
*/
|
|
138
|
+
export const generateExpressionsComputation = (
|
|
139
|
+
variables: Set<string>,
|
|
116
140
|
expressions: Map<string, string>
|
|
117
141
|
) => {
|
|
118
142
|
const depsById = new Map<string, Set<string>>();
|
|
119
143
|
for (const [id, code] of expressions) {
|
|
120
144
|
const deps = new Set<string>();
|
|
121
145
|
validateExpression(code, (identifier) => {
|
|
122
|
-
if (variables.has(identifier)
|
|
146
|
+
if (variables.has(identifier)) {
|
|
147
|
+
return identifier;
|
|
148
|
+
}
|
|
149
|
+
if (expressions.has(identifier)) {
|
|
123
150
|
deps.add(identifier);
|
|
124
151
|
return identifier;
|
|
125
152
|
}
|
|
@@ -128,38 +155,45 @@ export const executeExpressions = (
|
|
|
128
155
|
depsById.set(id, deps);
|
|
129
156
|
}
|
|
130
157
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
if (depsById.get(left)?.has(right)) {
|
|
135
|
-
return 1;
|
|
136
|
-
}
|
|
137
|
-
if (depsById.get(right)?.has(left)) {
|
|
138
|
-
return -1;
|
|
139
|
-
}
|
|
140
|
-
return 0;
|
|
141
|
-
}
|
|
158
|
+
const sortedExpressions = sortTopologically(
|
|
159
|
+
new Set(expressions.keys()),
|
|
160
|
+
depsById
|
|
142
161
|
);
|
|
143
162
|
|
|
144
|
-
//
|
|
145
|
-
let
|
|
146
|
-
for (const [id, value] of variables) {
|
|
147
|
-
header += `const ${id} = ${JSON.stringify(value)};\n`;
|
|
148
|
-
}
|
|
163
|
+
// generate code computing all expressions
|
|
164
|
+
let generatedCode = "";
|
|
149
165
|
|
|
150
|
-
const
|
|
166
|
+
for (const id of variables) {
|
|
167
|
+
generatedCode += `const ${id} = _variables.get('${id}');\n`;
|
|
168
|
+
}
|
|
151
169
|
|
|
152
170
|
for (const id of sortedExpressions) {
|
|
153
171
|
const code = expressions.get(id);
|
|
154
172
|
if (code === undefined) {
|
|
155
173
|
continue;
|
|
156
174
|
}
|
|
157
|
-
|
|
158
|
-
const value = executeFn();
|
|
159
|
-
header += `const ${id} = ${JSON.stringify(value)};\n`;
|
|
160
|
-
values.set(id, value);
|
|
175
|
+
generatedCode += `const ${id} = (${code});\n`;
|
|
161
176
|
}
|
|
162
177
|
|
|
178
|
+
generatedCode += `return new Map([\n`;
|
|
179
|
+
for (const id of sortedExpressions) {
|
|
180
|
+
generatedCode += ` ['${id}', ${id}],\n`;
|
|
181
|
+
}
|
|
182
|
+
generatedCode += `]);`;
|
|
183
|
+
|
|
184
|
+
return generatedCode;
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
export const executeExpressions = (
|
|
188
|
+
variables: Map<string, unknown>,
|
|
189
|
+
expressions: Map<string, string>
|
|
190
|
+
) => {
|
|
191
|
+
const generatedCode = generateExpressionsComputation(
|
|
192
|
+
new Set(variables.keys()),
|
|
193
|
+
expressions
|
|
194
|
+
);
|
|
195
|
+
const executeFn = new Function("_variables", generatedCode);
|
|
196
|
+
const values = executeFn(variables) as Map<string, unknown>;
|
|
163
197
|
return values;
|
|
164
198
|
};
|
|
165
199
|
|
package/src/index.ts
CHANGED
package/src/tree/root.ts
CHANGED
|
@@ -12,45 +12,6 @@ import { WebstudioComponent } from "./webstudio-component";
|
|
|
12
12
|
import { getPropsByInstanceId } from "../props";
|
|
13
13
|
import type { Components } from "../components/components-utils";
|
|
14
14
|
import type { Params } from "../context";
|
|
15
|
-
import {
|
|
16
|
-
executeExpressions,
|
|
17
|
-
encodeDataSourceVariable,
|
|
18
|
-
decodeDataSourceVariable,
|
|
19
|
-
} from "../expression";
|
|
20
|
-
|
|
21
|
-
const computeExpressions = (
|
|
22
|
-
dataSources: [DataSource["id"], DataSource][],
|
|
23
|
-
dataSourceValues: Map<DataSource["id"], unknown>
|
|
24
|
-
) => {
|
|
25
|
-
const outputValues = new Map<DataSource["id"], unknown>();
|
|
26
|
-
const variables = new Map<string, unknown>();
|
|
27
|
-
const expressions = new Map<string, string>();
|
|
28
|
-
for (const [dataSourceId, dataSource] of dataSources) {
|
|
29
|
-
const name = encodeDataSourceVariable(dataSourceId);
|
|
30
|
-
if (dataSource.type === "variable") {
|
|
31
|
-
const value =
|
|
32
|
-
dataSourceValues.get(dataSourceId) ?? dataSource.value.value;
|
|
33
|
-
variables.set(name, value);
|
|
34
|
-
outputValues.set(dataSourceId, value);
|
|
35
|
-
}
|
|
36
|
-
if (dataSource.type === "expression") {
|
|
37
|
-
expressions.set(name, dataSource.code);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
try {
|
|
41
|
-
const outputVariables = executeExpressions(variables, expressions);
|
|
42
|
-
for (const [name, value] of outputVariables) {
|
|
43
|
-
const id = decodeDataSourceVariable(name);
|
|
44
|
-
if (id !== undefined) {
|
|
45
|
-
outputValues.set(id, value);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
} catch (error) {
|
|
49
|
-
// eslint-disable-next-line no-console
|
|
50
|
-
console.error(error);
|
|
51
|
-
}
|
|
52
|
-
return outputValues;
|
|
53
|
-
};
|
|
54
15
|
|
|
55
16
|
export type Data = {
|
|
56
17
|
page: Page;
|
|
@@ -64,39 +25,58 @@ export type RootPropsData = Omit<Data, "build"> & {
|
|
|
64
25
|
build: Pick<Data["build"], "instances" | "props" | "dataSources">;
|
|
65
26
|
};
|
|
66
27
|
|
|
28
|
+
type DataSourceValues = Map<DataSource["id"], unknown>;
|
|
29
|
+
|
|
67
30
|
type RootProps = {
|
|
68
31
|
data: RootPropsData;
|
|
32
|
+
computeExpressions: (values: DataSourceValues) => DataSourceValues;
|
|
69
33
|
Component?: (props: ComponentProps<typeof WebstudioComponent>) => JSX.Element;
|
|
70
34
|
components: Components;
|
|
71
35
|
};
|
|
72
36
|
|
|
73
37
|
export const InstanceRoot = ({
|
|
74
38
|
data,
|
|
39
|
+
computeExpressions,
|
|
75
40
|
Component,
|
|
76
41
|
components,
|
|
77
42
|
}: RootProps): JSX.Element | null => {
|
|
78
43
|
const dataSourceVariablesStoreRef = useRef<
|
|
79
|
-
undefined | WritableAtom<
|
|
44
|
+
undefined | WritableAtom<DataSourceValues>
|
|
80
45
|
>(undefined);
|
|
81
|
-
// initialize store with default data source values
|
|
82
46
|
if (dataSourceVariablesStoreRef.current === undefined) {
|
|
83
|
-
|
|
84
|
-
for (const [dataSourceId, dataSource] of data.build.dataSources) {
|
|
85
|
-
dataSourceVariables.set(dataSourceId, dataSource);
|
|
86
|
-
}
|
|
87
|
-
dataSourceVariablesStoreRef.current = atom(dataSourceVariables);
|
|
47
|
+
dataSourceVariablesStoreRef.current = atom(new Map());
|
|
88
48
|
}
|
|
89
49
|
const dataSourceVariablesStore = dataSourceVariablesStoreRef.current;
|
|
90
50
|
|
|
91
51
|
const dataSourceValuesStoreRef = useRef<
|
|
92
|
-
undefined | ReadableAtom<
|
|
52
|
+
undefined | ReadableAtom<DataSourceValues>
|
|
93
53
|
>(undefined);
|
|
94
|
-
// initialize store with default data source values
|
|
95
54
|
if (dataSourceValuesStoreRef.current === undefined) {
|
|
96
55
|
dataSourceValuesStoreRef.current = computed(
|
|
97
56
|
dataSourceVariablesStore,
|
|
98
57
|
(dataSourceVariables) => {
|
|
99
|
-
|
|
58
|
+
// set vriables with defaults
|
|
59
|
+
const dataSourceValues: DataSourceValues = new Map();
|
|
60
|
+
for (const [dataSourceId, dataSource] of data.build.dataSources) {
|
|
61
|
+
if (dataSource.type === "variable") {
|
|
62
|
+
const value =
|
|
63
|
+
dataSourceVariables.get(dataSourceId) ?? dataSource.value.value;
|
|
64
|
+
dataSourceValues.set(dataSourceId, value);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// set expression values
|
|
69
|
+
try {
|
|
70
|
+
const result = computeExpressions(dataSourceValues);
|
|
71
|
+
for (const [id, value] of result) {
|
|
72
|
+
dataSourceValues.set(id, value);
|
|
73
|
+
}
|
|
74
|
+
} catch (error) {
|
|
75
|
+
// eslint-disable-next-line no-console
|
|
76
|
+
console.error(error);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return dataSourceValues;
|
|
100
80
|
}
|
|
101
81
|
);
|
|
102
82
|
}
|