@webstudio-is/react-sdk 0.95.0 → 0.96.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/css/normalize.js +127 -53
- package/lib/index.js +1843 -32
- package/lib/types/index.d.ts +0 -1
- package/package.json +6 -7
- package/lib/app/index.js +0 -2
- package/lib/app/root.js +0 -18
- package/lib/component-renderer.js +0 -130
- package/lib/components/component-meta.js +0 -62
- package/lib/components/components-utils.js +0 -2
- package/lib/context.js +0 -21
- package/lib/css/css.js +0 -59
- package/lib/css/global-rules.js +0 -15
- package/lib/css/index.js +0 -4
- package/lib/css/normalize-type-check.js +0 -4
- package/lib/css/presets.js +0 -25
- package/lib/css/style-rules.js +0 -63
- package/lib/css/style-rules.test.js +0 -149
- package/lib/embed-template.js +0 -341
- package/lib/embed-template.test.js +0 -648
- package/lib/expression.js +0 -330
- package/lib/expression.test.js +0 -281
- package/lib/generator.js +0 -112
- package/lib/generator.test.js +0 -166
- package/lib/hook.js +0 -12
- package/lib/hook.test.js +0 -15
- package/lib/instance-utils.js +0 -43
- package/lib/instance-utils.test.js +0 -65
- package/lib/prop-meta.js +0 -150
- package/lib/props.js +0 -176
- package/lib/props.test.js +0 -159
- package/lib/pubsub/create.js +0 -56
- package/lib/pubsub/index.js +0 -2
- package/lib/pubsub/raf-queue.js +0 -20
- package/lib/tree/create-elements-tree.js +0 -134
- package/lib/tree/index.js +0 -4
- package/lib/tree/root.js +0 -85
- package/lib/tree/webstudio-component.js +0 -61
- package/lib/types/pubsub/create.d.ts +0 -28
- package/lib/types/pubsub/index.d.ts +0 -1
- package/lib/types/pubsub/raf-queue.d.ts +0 -1
package/lib/index.js
CHANGED
|
@@ -1,37 +1,1848 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
// src/css/global-rules.ts
|
|
2
|
+
import { getFontFaces } from "@webstudio-is/fonts";
|
|
3
|
+
var addGlobalRules = (engine, { assets, assetBaseUrl }) => {
|
|
4
|
+
engine.addPlaintextRule("html {margin: 0; display: grid; min-height: 100%}");
|
|
5
|
+
const fontAssets = [];
|
|
6
|
+
for (const asset of assets.values()) {
|
|
7
|
+
if (asset.type === "font") {
|
|
8
|
+
fontAssets.push(asset);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
const fontFaces = getFontFaces(fontAssets, { assetBaseUrl });
|
|
12
|
+
for (const fontFace of fontFaces) {
|
|
13
|
+
engine.addFontFaceRule(fontFace);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// src/tree/create-elements-tree.tsx
|
|
18
|
+
import {
|
|
19
|
+
Fragment
|
|
20
|
+
} from "react";
|
|
21
|
+
|
|
22
|
+
// src/context.tsx
|
|
23
|
+
import { atom } from "nanostores";
|
|
24
|
+
import { createContext } from "react";
|
|
25
|
+
var ReactSdkContext = createContext({
|
|
26
|
+
imageBaseUrl: "/",
|
|
27
|
+
assetBaseUrl: "/",
|
|
28
|
+
propsByInstanceIdStore: atom(/* @__PURE__ */ new Map()),
|
|
29
|
+
assetsStore: atom(/* @__PURE__ */ new Map()),
|
|
30
|
+
pagesStore: atom(/* @__PURE__ */ new Map()),
|
|
31
|
+
dataSourceValuesStore: atom(/* @__PURE__ */ new Map()),
|
|
32
|
+
executeEffectfulExpression: () => {
|
|
33
|
+
throw Error("React SDK executeEffectfulExpression is not implemented");
|
|
34
|
+
},
|
|
35
|
+
setDataSourceValues: () => {
|
|
36
|
+
throw Error("React SDK setBoundDataSourceValue is not implemented");
|
|
37
|
+
},
|
|
38
|
+
setBoundDataSourceValue: () => {
|
|
39
|
+
throw Error("React SDK setBoundDataSourceValue is not implemented");
|
|
40
|
+
},
|
|
41
|
+
indexesWithinAncestors: /* @__PURE__ */ new Map()
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// src/tree/create-elements-tree.tsx
|
|
45
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
46
|
+
var createElementsTree = ({
|
|
47
|
+
renderer,
|
|
48
|
+
imageBaseUrl,
|
|
49
|
+
assetBaseUrl,
|
|
50
|
+
instances,
|
|
51
|
+
rootInstanceId,
|
|
52
|
+
propsByInstanceIdStore,
|
|
53
|
+
assetsStore,
|
|
54
|
+
pagesStore,
|
|
55
|
+
dataSourceValuesStore,
|
|
56
|
+
executeEffectfulExpression: executeEffectfulExpression2,
|
|
57
|
+
onDataSourceUpdate,
|
|
58
|
+
indexesWithinAncestors,
|
|
59
|
+
Component,
|
|
60
|
+
components,
|
|
61
|
+
scripts
|
|
62
|
+
}) => {
|
|
63
|
+
const rootInstance = instances.get(rootInstanceId);
|
|
64
|
+
if (rootInstance === void 0) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
const rootInstanceSelector = [rootInstanceId];
|
|
68
|
+
const children = createInstanceChildrenElements({
|
|
69
|
+
instances,
|
|
70
|
+
instanceSelector: rootInstanceSelector,
|
|
71
|
+
Component,
|
|
72
|
+
children: rootInstance.children,
|
|
73
|
+
components
|
|
74
|
+
});
|
|
75
|
+
const root = createInstanceElement({
|
|
76
|
+
Component,
|
|
77
|
+
instance: rootInstance,
|
|
78
|
+
instanceSelector: rootInstanceSelector,
|
|
79
|
+
children: [
|
|
80
|
+
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
81
|
+
children,
|
|
82
|
+
scripts
|
|
83
|
+
] }, "children")
|
|
84
|
+
],
|
|
85
|
+
components
|
|
86
|
+
});
|
|
87
|
+
return /* @__PURE__ */ jsx(
|
|
88
|
+
ReactSdkContext.Provider,
|
|
89
|
+
{
|
|
90
|
+
value: {
|
|
91
|
+
propsByInstanceIdStore,
|
|
92
|
+
assetsStore,
|
|
93
|
+
pagesStore,
|
|
94
|
+
dataSourceValuesStore,
|
|
95
|
+
renderer,
|
|
96
|
+
imageBaseUrl,
|
|
97
|
+
assetBaseUrl,
|
|
98
|
+
indexesWithinAncestors,
|
|
99
|
+
executeEffectfulExpression: executeEffectfulExpression2,
|
|
100
|
+
setDataSourceValues: onDataSourceUpdate,
|
|
101
|
+
setBoundDataSourceValue: (instanceId, propName, value) => {
|
|
102
|
+
const propsByInstanceId = propsByInstanceIdStore.get();
|
|
103
|
+
const props = propsByInstanceId.get(instanceId);
|
|
104
|
+
const prop = props?.find((prop2) => prop2.name === propName);
|
|
105
|
+
if (prop?.type !== "dataSource") {
|
|
106
|
+
throw Error(`${propName} is not data source`);
|
|
107
|
+
}
|
|
108
|
+
const dataSourceId = prop.value;
|
|
109
|
+
const newValues = /* @__PURE__ */ new Map();
|
|
110
|
+
newValues.set(dataSourceId, value);
|
|
111
|
+
onDataSourceUpdate(newValues);
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
children: root
|
|
115
|
+
}
|
|
116
|
+
);
|
|
117
|
+
};
|
|
118
|
+
var createInstanceChildrenElements = ({
|
|
119
|
+
instances,
|
|
120
|
+
instanceSelector,
|
|
121
|
+
children,
|
|
122
|
+
Component,
|
|
123
|
+
components
|
|
124
|
+
}) => {
|
|
125
|
+
const elements = [];
|
|
126
|
+
for (const child of children) {
|
|
127
|
+
if (child.type === "text") {
|
|
128
|
+
elements.push(child.value);
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
const childInstance = instances.get(child.value);
|
|
132
|
+
if (childInstance === void 0) {
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
const childInstanceSelector = [child.value, ...instanceSelector];
|
|
136
|
+
const children2 = createInstanceChildrenElements({
|
|
137
|
+
instances,
|
|
138
|
+
instanceSelector: childInstanceSelector,
|
|
139
|
+
children: childInstance.children,
|
|
140
|
+
Component,
|
|
141
|
+
components
|
|
142
|
+
});
|
|
143
|
+
const element = createInstanceElement({
|
|
144
|
+
instance: childInstance,
|
|
145
|
+
instanceSelector: childInstanceSelector,
|
|
146
|
+
Component,
|
|
147
|
+
children: children2,
|
|
148
|
+
components
|
|
149
|
+
});
|
|
150
|
+
elements.push(element);
|
|
151
|
+
}
|
|
152
|
+
return elements;
|
|
153
|
+
};
|
|
154
|
+
var createInstanceElement = ({
|
|
155
|
+
Component,
|
|
156
|
+
instance,
|
|
157
|
+
instanceSelector,
|
|
158
|
+
children = [],
|
|
159
|
+
components
|
|
160
|
+
}) => {
|
|
161
|
+
return /* @__PURE__ */ jsx(
|
|
162
|
+
Component,
|
|
163
|
+
{
|
|
164
|
+
instance,
|
|
165
|
+
instanceSelector,
|
|
166
|
+
components,
|
|
167
|
+
children
|
|
168
|
+
},
|
|
169
|
+
instance.id
|
|
170
|
+
);
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
// src/tree/root.ts
|
|
174
|
+
import {
|
|
175
|
+
useRef,
|
|
176
|
+
useCallback
|
|
177
|
+
} from "react";
|
|
178
|
+
import {
|
|
179
|
+
atom as atom2,
|
|
180
|
+
computed as computed2
|
|
181
|
+
} from "nanostores";
|
|
182
|
+
|
|
183
|
+
// src/tree/webstudio-component.tsx
|
|
184
|
+
import { Fragment as Fragment2, forwardRef } from "react";
|
|
185
|
+
|
|
186
|
+
// src/props.ts
|
|
187
|
+
import { useContext, useMemo } from "react";
|
|
188
|
+
import { computed } from "nanostores";
|
|
189
|
+
import { useStore } from "@nanostores/react";
|
|
190
|
+
var getPropsByInstanceId = (props) => {
|
|
191
|
+
const propsByInstanceId = /* @__PURE__ */ new Map();
|
|
192
|
+
for (const prop of props.values()) {
|
|
193
|
+
let instanceProps = propsByInstanceId.get(prop.instanceId);
|
|
194
|
+
if (instanceProps === void 0) {
|
|
195
|
+
instanceProps = [];
|
|
196
|
+
propsByInstanceId.set(prop.instanceId, instanceProps);
|
|
197
|
+
}
|
|
198
|
+
instanceProps.push(prop);
|
|
199
|
+
}
|
|
200
|
+
return propsByInstanceId;
|
|
201
|
+
};
|
|
202
|
+
var useInstanceProps = (instanceId) => {
|
|
203
|
+
const {
|
|
204
|
+
propsByInstanceIdStore,
|
|
205
|
+
dataSourceValuesStore,
|
|
206
|
+
executeEffectfulExpression: executeEffectfulExpression2,
|
|
207
|
+
setDataSourceValues,
|
|
208
|
+
indexesWithinAncestors
|
|
209
|
+
} = useContext(ReactSdkContext);
|
|
210
|
+
const index = indexesWithinAncestors.get(instanceId);
|
|
211
|
+
const instancePropsObjectStore = useMemo(() => {
|
|
212
|
+
return computed(
|
|
213
|
+
[propsByInstanceIdStore, dataSourceValuesStore],
|
|
214
|
+
(propsByInstanceId, dataSourceValues) => {
|
|
215
|
+
const instancePropsObject2 = {};
|
|
216
|
+
if (index !== void 0) {
|
|
217
|
+
instancePropsObject2[indexAttribute] = index.toString();
|
|
218
|
+
}
|
|
219
|
+
const instanceProps = propsByInstanceId.get(instanceId);
|
|
220
|
+
if (instanceProps === void 0) {
|
|
221
|
+
return instancePropsObject2;
|
|
222
|
+
}
|
|
223
|
+
for (const prop of instanceProps) {
|
|
224
|
+
if (prop.type === "asset" || prop.type === "page") {
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
if (prop.type === "dataSource") {
|
|
228
|
+
const dataSourceId = prop.value;
|
|
229
|
+
const value = dataSourceValues.get(dataSourceId);
|
|
230
|
+
if (value !== void 0) {
|
|
231
|
+
instancePropsObject2[prop.name] = value;
|
|
232
|
+
}
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
if (prop.type === "action") {
|
|
236
|
+
instancePropsObject2[prop.name] = (...args) => {
|
|
237
|
+
for (const value of prop.value) {
|
|
238
|
+
if (value.type === "execute") {
|
|
239
|
+
const argsMap = /* @__PURE__ */ new Map();
|
|
240
|
+
for (const [i, name] of value.args.entries()) {
|
|
241
|
+
argsMap.set(name, args[i]);
|
|
242
|
+
}
|
|
243
|
+
const newValues = executeEffectfulExpression2(
|
|
244
|
+
value.code,
|
|
245
|
+
argsMap,
|
|
246
|
+
dataSourceValues
|
|
247
|
+
);
|
|
248
|
+
setDataSourceValues(newValues);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
instancePropsObject2[prop.name] = prop.value;
|
|
255
|
+
}
|
|
256
|
+
return instancePropsObject2;
|
|
257
|
+
}
|
|
258
|
+
);
|
|
259
|
+
}, [
|
|
260
|
+
propsByInstanceIdStore,
|
|
261
|
+
dataSourceValuesStore,
|
|
262
|
+
instanceId,
|
|
263
|
+
executeEffectfulExpression2,
|
|
264
|
+
setDataSourceValues,
|
|
265
|
+
index
|
|
266
|
+
]);
|
|
267
|
+
const instancePropsObject = useStore(instancePropsObjectStore);
|
|
268
|
+
return instancePropsObject;
|
|
269
|
+
};
|
|
270
|
+
var usePropAsset = (instanceId, name) => {
|
|
271
|
+
const { propsByInstanceIdStore, assetsStore } = useContext(ReactSdkContext);
|
|
272
|
+
const assetStore = useMemo(() => {
|
|
273
|
+
return computed(
|
|
274
|
+
[propsByInstanceIdStore, assetsStore],
|
|
275
|
+
(propsByInstanceId, assets) => {
|
|
276
|
+
const instanceProps = propsByInstanceId.get(instanceId);
|
|
277
|
+
if (instanceProps === void 0) {
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
for (const prop of instanceProps) {
|
|
281
|
+
if (prop.type === "asset" && prop.name === name) {
|
|
282
|
+
const assetId = prop.value;
|
|
283
|
+
return assets.get(assetId);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
);
|
|
288
|
+
}, [propsByInstanceIdStore, assetsStore, instanceId, name]);
|
|
289
|
+
const asset = useStore(assetStore);
|
|
290
|
+
return asset;
|
|
291
|
+
};
|
|
292
|
+
var resolveUrlProp = (instanceId, name, {
|
|
293
|
+
props,
|
|
294
|
+
pages,
|
|
295
|
+
assets
|
|
296
|
+
}) => {
|
|
297
|
+
const instanceProps = props.get(instanceId);
|
|
298
|
+
if (instanceProps === void 0) {
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
let prop = void 0;
|
|
302
|
+
for (const intanceProp of instanceProps) {
|
|
303
|
+
if (intanceProp.name !== name) {
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
prop = intanceProp;
|
|
307
|
+
}
|
|
308
|
+
if (prop === void 0) {
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
if (prop.type === "page") {
|
|
312
|
+
if (typeof prop.value === "string") {
|
|
313
|
+
const page2 = pages.get(prop.value);
|
|
314
|
+
return page2 && { type: "page", page: page2 };
|
|
315
|
+
}
|
|
316
|
+
const { instanceId: instanceId2, pageId } = prop.value;
|
|
317
|
+
const page = pages.get(pageId);
|
|
318
|
+
if (page === void 0) {
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
const idProp = props.get(instanceId2)?.find((prop2) => prop2.name === "id");
|
|
322
|
+
return {
|
|
323
|
+
type: "page",
|
|
324
|
+
page,
|
|
325
|
+
instanceId: instanceId2,
|
|
326
|
+
hash: idProp === void 0 || idProp.type !== "string" ? void 0 : idProp.value
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
if (prop.type === "string") {
|
|
330
|
+
for (const page of pages.values()) {
|
|
331
|
+
if (page.path === prop.value) {
|
|
332
|
+
return { type: "page", page };
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
return { type: "string", url: prop.value };
|
|
336
|
+
}
|
|
337
|
+
if (prop.type === "asset") {
|
|
338
|
+
const asset = assets.get(prop.value);
|
|
339
|
+
return asset && { type: "asset", asset };
|
|
340
|
+
}
|
|
341
|
+
return;
|
|
342
|
+
};
|
|
343
|
+
var usePropUrl = (instanceId, name) => {
|
|
344
|
+
const { propsByInstanceIdStore, pagesStore, assetsStore } = useContext(ReactSdkContext);
|
|
345
|
+
const store = useMemo(
|
|
346
|
+
() => computed(
|
|
347
|
+
[propsByInstanceIdStore, pagesStore, assetsStore],
|
|
348
|
+
(props, pages, assets) => resolveUrlProp(instanceId, name, { props, pages, assets })
|
|
349
|
+
),
|
|
350
|
+
[propsByInstanceIdStore, pagesStore, assetsStore, instanceId, name]
|
|
351
|
+
);
|
|
352
|
+
return useStore(store);
|
|
353
|
+
};
|
|
354
|
+
var getInstanceIdFromComponentProps = (props) => {
|
|
355
|
+
return props[idAttribute];
|
|
356
|
+
};
|
|
357
|
+
var getIndexWithinAncestorFromComponentProps = (props) => {
|
|
358
|
+
return props[indexAttribute];
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
// src/tree/webstudio-component.tsx
|
|
362
|
+
import { Fragment as Fragment3, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
363
|
+
var renderText = (text) => {
|
|
364
|
+
const lines = text.split("\n");
|
|
365
|
+
return lines.map((line, index) => /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
366
|
+
line,
|
|
367
|
+
index < lines.length - 1 ? /* @__PURE__ */ jsx2("br", {}) : null
|
|
368
|
+
] }, index));
|
|
369
|
+
};
|
|
370
|
+
var renderWebstudioComponentChildren = (children) => {
|
|
371
|
+
if (children === void 0 || children.length === 0) {
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
return children.map((child) => {
|
|
375
|
+
return typeof child === "string" ? renderText(child) : child;
|
|
376
|
+
});
|
|
377
|
+
};
|
|
378
|
+
var WebstudioComponent = forwardRef(({ instance, instanceSelector, children, components, ...rest }, ref) => {
|
|
379
|
+
const { [showAttribute]: show = true, ...instanceProps } = useInstanceProps(
|
|
380
|
+
instance.id
|
|
381
|
+
);
|
|
382
|
+
const props = {
|
|
383
|
+
...instanceProps,
|
|
384
|
+
...rest,
|
|
385
|
+
[idAttribute]: instance.id,
|
|
386
|
+
[componentAttribute]: instance.component
|
|
387
|
+
};
|
|
388
|
+
if (show === false) {
|
|
389
|
+
return /* @__PURE__ */ jsx2(Fragment3, {});
|
|
390
|
+
}
|
|
391
|
+
const Component = components.get(instance.component);
|
|
392
|
+
if (Component === void 0) {
|
|
393
|
+
return /* @__PURE__ */ jsx2(Fragment3, {});
|
|
394
|
+
}
|
|
395
|
+
return /* @__PURE__ */ jsx2(Component, { ...props, ref, children: renderWebstudioComponentChildren(children) });
|
|
396
|
+
});
|
|
397
|
+
var idAttribute = "data-ws-id";
|
|
398
|
+
var selectorIdAttribute = "data-ws-selector";
|
|
399
|
+
var componentAttribute = "data-ws-component";
|
|
400
|
+
var showAttribute = "data-ws-show";
|
|
401
|
+
var indexAttribute = "data-ws-index";
|
|
402
|
+
var collapsedAttribute = "data-ws-collapsed";
|
|
403
|
+
var splitPropsWithWebstudioAttributes = ({
|
|
404
|
+
[idAttribute]: idAttributeValue,
|
|
405
|
+
[componentAttribute]: componentAttributeValue,
|
|
406
|
+
[showAttribute]: showAttributeValue,
|
|
407
|
+
[collapsedAttribute]: collapsedAttributeValue,
|
|
408
|
+
[selectorIdAttribute]: parentIdAttributeValue,
|
|
409
|
+
...props
|
|
410
|
+
}) => [
|
|
411
|
+
{
|
|
412
|
+
[idAttribute]: idAttributeValue,
|
|
413
|
+
[componentAttribute]: componentAttributeValue,
|
|
414
|
+
[showAttribute]: showAttributeValue,
|
|
415
|
+
[collapsedAttribute]: collapsedAttributeValue,
|
|
416
|
+
[selectorIdAttribute]: parentIdAttributeValue
|
|
417
|
+
},
|
|
418
|
+
props
|
|
419
|
+
];
|
|
420
|
+
|
|
421
|
+
// src/tree/root.ts
|
|
422
|
+
var InstanceRoot = ({
|
|
423
|
+
data,
|
|
424
|
+
utils,
|
|
425
|
+
Component,
|
|
426
|
+
components,
|
|
427
|
+
scripts
|
|
428
|
+
}) => {
|
|
429
|
+
const {
|
|
430
|
+
indexesWithinAncestors,
|
|
431
|
+
executeComputingExpressions: executeComputingExpressions2,
|
|
432
|
+
executeEffectfulExpression: executeEffectfulExpression2
|
|
433
|
+
} = utils;
|
|
434
|
+
const dataSourceVariablesStoreRef = useRef(void 0);
|
|
435
|
+
if (dataSourceVariablesStoreRef.current === void 0) {
|
|
436
|
+
dataSourceVariablesStoreRef.current = atom2(/* @__PURE__ */ new Map());
|
|
437
|
+
}
|
|
438
|
+
const dataSourceVariablesStore = dataSourceVariablesStoreRef.current;
|
|
439
|
+
const dataSourceValuesStoreRef = useRef(void 0);
|
|
440
|
+
if (dataSourceValuesStoreRef.current === void 0) {
|
|
441
|
+
dataSourceValuesStoreRef.current = computed2(
|
|
442
|
+
dataSourceVariablesStore,
|
|
443
|
+
(dataSourceVariables) => {
|
|
444
|
+
const dataSourceValues = /* @__PURE__ */ new Map();
|
|
445
|
+
for (const [dataSourceId, dataSource] of data.build.dataSources) {
|
|
446
|
+
if (dataSource.type === "variable") {
|
|
447
|
+
const value = dataSourceVariables.get(dataSourceId) ?? dataSource.value.value;
|
|
448
|
+
dataSourceValues.set(dataSourceId, value);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
try {
|
|
452
|
+
const result = executeComputingExpressions2(dataSourceValues);
|
|
453
|
+
for (const [id, value] of result) {
|
|
454
|
+
dataSourceValues.set(id, value);
|
|
455
|
+
}
|
|
456
|
+
} catch (error) {
|
|
457
|
+
console.error(error);
|
|
458
|
+
}
|
|
459
|
+
return dataSourceValues;
|
|
460
|
+
}
|
|
461
|
+
);
|
|
462
|
+
}
|
|
463
|
+
const dataSourceValuesStore = dataSourceValuesStoreRef.current;
|
|
464
|
+
const onDataSourceUpdate = useCallback(
|
|
465
|
+
(newValues) => {
|
|
466
|
+
const dataSourceVariables = new Map(dataSourceVariablesStore.get());
|
|
467
|
+
for (const [dataSourceId, value] of newValues) {
|
|
468
|
+
dataSourceVariables.set(dataSourceId, value);
|
|
469
|
+
}
|
|
470
|
+
dataSourceVariablesStore.set(dataSourceVariables);
|
|
471
|
+
},
|
|
472
|
+
[dataSourceVariablesStore]
|
|
473
|
+
);
|
|
474
|
+
return createElementsTree({
|
|
475
|
+
imageBaseUrl: data.params?.imageBaseUrl ?? "/",
|
|
476
|
+
assetBaseUrl: data.params?.assetBaseUrl ?? "/",
|
|
477
|
+
instances: new Map(data.build.instances),
|
|
478
|
+
rootInstanceId: data.page.rootInstanceId,
|
|
479
|
+
propsByInstanceIdStore: atom2(
|
|
480
|
+
getPropsByInstanceId(new Map(data.build.props))
|
|
481
|
+
),
|
|
482
|
+
assetsStore: atom2(new Map(data.assets.map((asset) => [asset.id, asset]))),
|
|
483
|
+
pagesStore: atom2(new Map(data.pages.map((page) => [page.id, page]))),
|
|
484
|
+
indexesWithinAncestors,
|
|
485
|
+
executeEffectfulExpression: executeEffectfulExpression2,
|
|
486
|
+
dataSourceValuesStore,
|
|
487
|
+
onDataSourceUpdate,
|
|
488
|
+
Component: Component ?? WebstudioComponent,
|
|
489
|
+
components,
|
|
490
|
+
scripts
|
|
491
|
+
});
|
|
492
|
+
};
|
|
493
|
+
|
|
494
|
+
// src/css/style-rules.ts
|
|
495
|
+
var getStyleRules = (styles, styleSourceSelections) => {
|
|
496
|
+
if (styles === void 0 || styleSourceSelections === void 0) {
|
|
497
|
+
return [];
|
|
498
|
+
}
|
|
499
|
+
const stylesByStyleSourceId = /* @__PURE__ */ new Map();
|
|
500
|
+
for (const styleDecl of styles.values()) {
|
|
501
|
+
const { styleSourceId } = styleDecl;
|
|
502
|
+
let styleSourceStyles = stylesByStyleSourceId.get(styleSourceId);
|
|
503
|
+
if (styleSourceStyles === void 0) {
|
|
504
|
+
styleSourceStyles = [];
|
|
505
|
+
stylesByStyleSourceId.set(styleSourceId, styleSourceStyles);
|
|
506
|
+
}
|
|
507
|
+
styleSourceStyles.push(styleDecl);
|
|
508
|
+
}
|
|
509
|
+
const styleRules = [];
|
|
510
|
+
for (const { instanceId, values } of styleSourceSelections.values()) {
|
|
511
|
+
const styleRuleByBreakpointId = /* @__PURE__ */ new Map();
|
|
512
|
+
for (const styleSourceId of values) {
|
|
513
|
+
const styleSourceStyles = stylesByStyleSourceId.get(styleSourceId);
|
|
514
|
+
if (styleSourceStyles === void 0) {
|
|
515
|
+
continue;
|
|
516
|
+
}
|
|
517
|
+
for (const {
|
|
518
|
+
breakpointId,
|
|
519
|
+
state,
|
|
520
|
+
property,
|
|
521
|
+
value
|
|
522
|
+
} of styleSourceStyles) {
|
|
523
|
+
const key = `${breakpointId}:${state ?? ""}`;
|
|
524
|
+
let styleRule = styleRuleByBreakpointId.get(key);
|
|
525
|
+
if (styleRule === void 0) {
|
|
526
|
+
styleRule = {
|
|
527
|
+
instanceId,
|
|
528
|
+
breakpointId,
|
|
529
|
+
state,
|
|
530
|
+
style: {}
|
|
531
|
+
};
|
|
532
|
+
styleRuleByBreakpointId.set(key, styleRule);
|
|
533
|
+
}
|
|
534
|
+
styleRule.style[property] = value;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
styleRules.push(...styleRuleByBreakpointId.values());
|
|
538
|
+
}
|
|
539
|
+
return styleRules;
|
|
540
|
+
};
|
|
541
|
+
var getPresetStyleRules = (component, presetStyle) => {
|
|
542
|
+
const presetStyleRules = /* @__PURE__ */ new Map();
|
|
543
|
+
for (const [tag, styles] of Object.entries(presetStyle)) {
|
|
544
|
+
for (const styleDecl of styles) {
|
|
545
|
+
const selector = `${tag}:where([${componentAttribute}="${component}"])${styleDecl.state ?? ""}`;
|
|
546
|
+
let rule = presetStyleRules.get(selector);
|
|
547
|
+
if (rule === void 0) {
|
|
548
|
+
rule = {};
|
|
549
|
+
presetStyleRules.set(selector, rule);
|
|
550
|
+
}
|
|
551
|
+
rule[styleDecl.property] = styleDecl.value;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
return presetStyleRules;
|
|
555
|
+
};
|
|
556
|
+
|
|
557
|
+
// src/css/css.ts
|
|
558
|
+
import { createCssEngine } from "@webstudio-is/css-engine";
|
|
559
|
+
var createImageValueTransformer = (assets, options) => (styleValue) => {
|
|
560
|
+
if (styleValue.type === "image" && styleValue.value.type === "asset") {
|
|
561
|
+
const asset = assets.get(styleValue.value.value);
|
|
562
|
+
if (asset === void 0) {
|
|
563
|
+
return { type: "keyword", value: "none" };
|
|
564
|
+
}
|
|
565
|
+
const { assetBaseUrl } = options;
|
|
566
|
+
const url = `${assetBaseUrl}${asset.name}`;
|
|
567
|
+
return {
|
|
568
|
+
type: "image",
|
|
569
|
+
value: {
|
|
570
|
+
type: "url",
|
|
571
|
+
url
|
|
572
|
+
},
|
|
573
|
+
hidden: styleValue.hidden
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
};
|
|
577
|
+
var generateCssText = (data, options) => {
|
|
578
|
+
const assets = new Map(data.assets.map((asset) => [asset.id, asset]));
|
|
579
|
+
const breakpoints = new Map(data.breakpoints);
|
|
580
|
+
const styles = new Map(data.styles);
|
|
581
|
+
const styleSourceSelections = new Map(data.styleSourceSelections);
|
|
582
|
+
const engine = createCssEngine({ name: "ssr" });
|
|
583
|
+
addGlobalRules(engine, {
|
|
584
|
+
assets,
|
|
585
|
+
assetBaseUrl: options.assetBaseUrl
|
|
586
|
+
});
|
|
587
|
+
for (const breakpoint of breakpoints.values()) {
|
|
588
|
+
engine.addMediaRule(breakpoint.id, breakpoint);
|
|
589
|
+
}
|
|
590
|
+
for (const [component, meta] of data.componentMetas) {
|
|
591
|
+
const presetStyle = meta.presetStyle;
|
|
592
|
+
if (presetStyle === void 0) {
|
|
593
|
+
continue;
|
|
594
|
+
}
|
|
595
|
+
const rules = getPresetStyleRules(component, presetStyle);
|
|
596
|
+
for (const [selector, style] of rules) {
|
|
597
|
+
engine.addStyleRule(selector, { style });
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
const styleRules = getStyleRules(styles, styleSourceSelections);
|
|
601
|
+
for (const { breakpointId, instanceId, state, style } of styleRules) {
|
|
602
|
+
engine.addStyleRule(
|
|
603
|
+
`[${idAttribute}="${instanceId}"]${state ?? ""}`,
|
|
604
|
+
{
|
|
605
|
+
breakpoint: breakpointId,
|
|
606
|
+
style
|
|
607
|
+
},
|
|
608
|
+
createImageValueTransformer(assets, options)
|
|
609
|
+
);
|
|
610
|
+
}
|
|
611
|
+
return engine.cssText;
|
|
612
|
+
};
|
|
613
|
+
|
|
614
|
+
// src/app/root.tsx
|
|
615
|
+
import { Links, Meta, Outlet as DefaultOutlet } from "@remix-run/react";
|
|
616
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
617
|
+
var Root = ({
|
|
618
|
+
Outlet = DefaultOutlet
|
|
619
|
+
}) => {
|
|
620
|
+
return /* @__PURE__ */ jsxs3("html", { lang: "en", children: [
|
|
621
|
+
/* @__PURE__ */ jsxs3("head", { children: [
|
|
622
|
+
/* @__PURE__ */ jsx3("meta", { charSet: "utf-8" }),
|
|
623
|
+
/* @__PURE__ */ jsx3("meta", { name: "viewport", content: "width=device-width,initial-scale=1" }),
|
|
624
|
+
/* @__PURE__ */ jsx3("link", { rel: "icon", href: "/favicon.ico", type: "image/x-icon" }),
|
|
625
|
+
/* @__PURE__ */ jsx3("link", { rel: "shortcut icon", href: "/favicon.ico", type: "image/x-icon" }),
|
|
626
|
+
/* @__PURE__ */ jsx3(Meta, {}),
|
|
627
|
+
/* @__PURE__ */ jsx3(Links, {})
|
|
628
|
+
] }),
|
|
629
|
+
/* @__PURE__ */ jsx3(Outlet, {})
|
|
630
|
+
] });
|
|
631
|
+
};
|
|
632
|
+
|
|
633
|
+
// src/prop-meta.ts
|
|
634
|
+
import { z } from "zod";
|
|
635
|
+
var common = {
|
|
636
|
+
label: z.string().optional(),
|
|
637
|
+
description: z.string().optional(),
|
|
638
|
+
required: z.boolean()
|
|
639
|
+
};
|
|
640
|
+
var Number = z.object({
|
|
641
|
+
...common,
|
|
642
|
+
control: z.literal("number"),
|
|
643
|
+
type: z.literal("number"),
|
|
644
|
+
defaultValue: z.number().optional()
|
|
645
|
+
});
|
|
646
|
+
var Range = z.object({
|
|
647
|
+
...common,
|
|
648
|
+
control: z.literal("range"),
|
|
649
|
+
type: z.literal("number"),
|
|
650
|
+
defaultValue: z.number().optional()
|
|
651
|
+
});
|
|
652
|
+
var Text = z.object({
|
|
653
|
+
...common,
|
|
654
|
+
control: z.literal("text"),
|
|
655
|
+
type: z.literal("string"),
|
|
656
|
+
defaultValue: z.string().optional(),
|
|
657
|
+
/**
|
|
658
|
+
* The number of rows in <textarea>. If set to 0 an <input> will be used instead.
|
|
659
|
+
* In line with Storybook team's plan: https://github.com/storybookjs/storybook/issues/21100
|
|
660
|
+
*/
|
|
661
|
+
rows: z.number().optional()
|
|
662
|
+
});
|
|
663
|
+
var Code = z.object({
|
|
664
|
+
...common,
|
|
665
|
+
control: z.literal("code"),
|
|
666
|
+
type: z.literal("string"),
|
|
667
|
+
defaultValue: z.string().optional(),
|
|
668
|
+
/**
|
|
669
|
+
* The number of rows in <textarea>. If set to 0 an <input> will be used instead.
|
|
670
|
+
* In line with Storybook team's plan: https://github.com/storybookjs/storybook/issues/21100
|
|
671
|
+
*/
|
|
672
|
+
rows: z.number().optional()
|
|
673
|
+
});
|
|
674
|
+
var Color = z.object({
|
|
675
|
+
...common,
|
|
676
|
+
control: z.literal("color"),
|
|
677
|
+
type: z.literal("string"),
|
|
678
|
+
defaultValue: z.string().optional()
|
|
679
|
+
});
|
|
680
|
+
var Boolean = z.object({
|
|
681
|
+
...common,
|
|
682
|
+
control: z.literal("boolean"),
|
|
683
|
+
type: z.literal("boolean"),
|
|
684
|
+
defaultValue: z.boolean().optional()
|
|
685
|
+
});
|
|
686
|
+
var Radio = z.object({
|
|
687
|
+
...common,
|
|
688
|
+
control: z.literal("radio"),
|
|
689
|
+
type: z.literal("string"),
|
|
690
|
+
defaultValue: z.string().optional(),
|
|
691
|
+
options: z.array(z.string())
|
|
692
|
+
});
|
|
693
|
+
var InlineRadio = z.object({
|
|
694
|
+
...common,
|
|
695
|
+
control: z.literal("inline-radio"),
|
|
696
|
+
type: z.literal("string"),
|
|
697
|
+
defaultValue: z.string().optional(),
|
|
698
|
+
options: z.array(z.string())
|
|
699
|
+
});
|
|
700
|
+
var Select = z.object({
|
|
701
|
+
...common,
|
|
702
|
+
control: z.literal("select"),
|
|
703
|
+
type: z.literal("string"),
|
|
704
|
+
defaultValue: z.string().optional(),
|
|
705
|
+
options: z.array(z.string())
|
|
706
|
+
});
|
|
707
|
+
var Check = z.object({
|
|
708
|
+
...common,
|
|
709
|
+
control: z.literal("check"),
|
|
710
|
+
type: z.literal("string[]"),
|
|
711
|
+
defaultValue: z.array(z.string()).optional(),
|
|
712
|
+
options: z.array(z.string())
|
|
713
|
+
});
|
|
714
|
+
var InlineCheck = z.object({
|
|
715
|
+
...common,
|
|
716
|
+
control: z.literal("inline-check"),
|
|
717
|
+
type: z.literal("string[]"),
|
|
718
|
+
defaultValue: z.array(z.string()).optional(),
|
|
719
|
+
options: z.array(z.string())
|
|
720
|
+
});
|
|
721
|
+
var MultiSelect = z.object({
|
|
722
|
+
...common,
|
|
723
|
+
control: z.literal("multi-select"),
|
|
724
|
+
type: z.literal("string[]"),
|
|
725
|
+
defaultValue: z.array(z.string()).optional(),
|
|
726
|
+
options: z.array(z.string())
|
|
727
|
+
});
|
|
728
|
+
var File = z.object({
|
|
729
|
+
...common,
|
|
730
|
+
control: z.literal("file"),
|
|
731
|
+
type: z.literal("string"),
|
|
732
|
+
defaultValue: z.string().optional(),
|
|
733
|
+
/** https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#accept */
|
|
734
|
+
accept: z.string().optional()
|
|
735
|
+
});
|
|
736
|
+
var Url = z.object({
|
|
737
|
+
...common,
|
|
738
|
+
control: z.literal("url"),
|
|
739
|
+
type: z.literal("string"),
|
|
740
|
+
defaultValue: z.string().optional()
|
|
741
|
+
});
|
|
742
|
+
var ObjectType = z.object({
|
|
743
|
+
...common,
|
|
744
|
+
control: z.literal("object"),
|
|
745
|
+
// @todo not sure what type should be here
|
|
746
|
+
// (we don't support Object yet, added for completeness)
|
|
747
|
+
type: z.literal("Record<string, string>"),
|
|
748
|
+
defaultValue: z.record(z.string()).optional()
|
|
749
|
+
});
|
|
750
|
+
var Date = z.object({
|
|
751
|
+
...common,
|
|
752
|
+
control: z.literal("date"),
|
|
753
|
+
// @todo not sure what type should be here
|
|
754
|
+
// (we don't support Date yet, added for completeness)
|
|
755
|
+
type: z.literal("string"),
|
|
756
|
+
defaultValue: z.string().optional()
|
|
757
|
+
});
|
|
758
|
+
var Action = z.object({
|
|
759
|
+
...common,
|
|
760
|
+
control: z.literal("action"),
|
|
761
|
+
type: z.literal("action"),
|
|
762
|
+
defaultValue: z.undefined().optional()
|
|
763
|
+
});
|
|
764
|
+
var PropMeta = z.union([
|
|
765
|
+
Number,
|
|
766
|
+
Range,
|
|
767
|
+
Text,
|
|
768
|
+
Code,
|
|
769
|
+
Color,
|
|
770
|
+
Boolean,
|
|
771
|
+
Radio,
|
|
772
|
+
InlineRadio,
|
|
773
|
+
Select,
|
|
774
|
+
MultiSelect,
|
|
775
|
+
Check,
|
|
776
|
+
InlineCheck,
|
|
777
|
+
File,
|
|
778
|
+
Url,
|
|
779
|
+
ObjectType,
|
|
780
|
+
Date,
|
|
781
|
+
Action
|
|
782
|
+
]);
|
|
783
|
+
|
|
784
|
+
// src/components/component-meta.ts
|
|
785
|
+
import { z as z3 } from "zod";
|
|
786
|
+
|
|
787
|
+
// src/embed-template.ts
|
|
788
|
+
import { z as z2 } from "zod";
|
|
789
|
+
import { nanoid } from "nanoid";
|
|
790
|
+
import { titleCase } from "title-case";
|
|
791
|
+
import { noCase } from "no-case";
|
|
792
|
+
import { StyleValue } from "@webstudio-is/css-engine";
|
|
793
|
+
|
|
794
|
+
// src/expression.ts
|
|
795
|
+
import jsep from "jsep";
|
|
796
|
+
import jsepAssignment from "@jsep-plugin/assignment";
|
|
797
|
+
jsep.plugins.register(jsepAssignment);
|
|
798
|
+
var generateCode = (node, failOnForbidden, effectful, transformIdentifier) => {
|
|
799
|
+
if (node.type === "Identifier") {
|
|
800
|
+
return transformIdentifier(node.name, false);
|
|
801
|
+
}
|
|
802
|
+
if (node.type === "MemberExpression") {
|
|
803
|
+
if (failOnForbidden) {
|
|
804
|
+
const object2 = generateCode(
|
|
805
|
+
node.object,
|
|
806
|
+
false,
|
|
807
|
+
effectful,
|
|
808
|
+
transformIdentifier
|
|
809
|
+
);
|
|
810
|
+
const property2 = generateCode(
|
|
811
|
+
node.property,
|
|
812
|
+
false,
|
|
813
|
+
effectful,
|
|
814
|
+
transformIdentifier
|
|
815
|
+
);
|
|
816
|
+
throw Error(`Cannot access "${property2}" of "${object2}"`);
|
|
817
|
+
}
|
|
818
|
+
const object = generateCode(
|
|
819
|
+
node.object,
|
|
820
|
+
failOnForbidden,
|
|
821
|
+
effectful,
|
|
822
|
+
transformIdentifier
|
|
823
|
+
);
|
|
824
|
+
const property = generateCode(
|
|
825
|
+
node.property,
|
|
826
|
+
failOnForbidden,
|
|
827
|
+
effectful,
|
|
828
|
+
transformIdentifier
|
|
829
|
+
);
|
|
830
|
+
return `${object}.${property}`;
|
|
831
|
+
}
|
|
832
|
+
if (node.type === "Literal") {
|
|
833
|
+
return node.raw;
|
|
834
|
+
}
|
|
835
|
+
if (node.type === "UnaryExpression") {
|
|
836
|
+
const arg = generateCode(
|
|
837
|
+
node.argument,
|
|
838
|
+
failOnForbidden,
|
|
839
|
+
effectful,
|
|
840
|
+
transformIdentifier
|
|
841
|
+
);
|
|
842
|
+
return `${node.operator}${arg}`;
|
|
843
|
+
}
|
|
844
|
+
if (node.type === "BinaryExpression") {
|
|
845
|
+
const left = generateCode(
|
|
846
|
+
node.left,
|
|
847
|
+
failOnForbidden,
|
|
848
|
+
effectful,
|
|
849
|
+
transformIdentifier
|
|
850
|
+
);
|
|
851
|
+
const right = generateCode(
|
|
852
|
+
node.right,
|
|
853
|
+
failOnForbidden,
|
|
854
|
+
effectful,
|
|
855
|
+
transformIdentifier
|
|
856
|
+
);
|
|
857
|
+
return `${left} ${node.operator} ${right}`;
|
|
858
|
+
}
|
|
859
|
+
if (node.type === "ArrayExpression") {
|
|
860
|
+
const elements = node.elements.map(
|
|
861
|
+
(element) => generateCode(
|
|
862
|
+
element,
|
|
863
|
+
failOnForbidden,
|
|
864
|
+
effectful,
|
|
865
|
+
transformIdentifier
|
|
866
|
+
)
|
|
867
|
+
);
|
|
868
|
+
return `[${elements.join(", ")}]`;
|
|
869
|
+
}
|
|
870
|
+
if (node.type === "CallExpression") {
|
|
871
|
+
if (failOnForbidden) {
|
|
872
|
+
const callee2 = generateCode(
|
|
873
|
+
node.callee,
|
|
874
|
+
false,
|
|
875
|
+
effectful,
|
|
876
|
+
transformIdentifier
|
|
877
|
+
);
|
|
878
|
+
throw Error(`Cannot call "${callee2}"`);
|
|
879
|
+
}
|
|
880
|
+
const callee = generateCode(
|
|
881
|
+
node.callee,
|
|
882
|
+
failOnForbidden,
|
|
883
|
+
effectful,
|
|
884
|
+
transformIdentifier
|
|
885
|
+
);
|
|
886
|
+
const args = node.arguments.map(
|
|
887
|
+
(arg) => generateCode(arg, failOnForbidden, effectful, transformIdentifier)
|
|
888
|
+
);
|
|
889
|
+
return `${callee}(${args.join(", ")})`;
|
|
890
|
+
}
|
|
891
|
+
if (node.type === "ThisExpression") {
|
|
892
|
+
if (failOnForbidden) {
|
|
893
|
+
throw Error(`"this" is not supported`);
|
|
894
|
+
}
|
|
895
|
+
return "this";
|
|
896
|
+
}
|
|
897
|
+
if (node.type === "ConditionalExpression") {
|
|
898
|
+
throw Error("Ternary operator is not supported");
|
|
899
|
+
}
|
|
900
|
+
if (node.type === "Compound") {
|
|
901
|
+
throw Error("Cannot use multiple expressions");
|
|
902
|
+
}
|
|
903
|
+
if (node.type === "AssignmentExpression") {
|
|
904
|
+
if (node.operator !== "=") {
|
|
905
|
+
throw Error(`Only "=" assignment operator is supported`);
|
|
906
|
+
}
|
|
907
|
+
if (effectful === false) {
|
|
908
|
+
throw Error(`Cannot use assignment in this expression`);
|
|
909
|
+
}
|
|
910
|
+
const left = generateCode(
|
|
911
|
+
node.left,
|
|
912
|
+
failOnForbidden,
|
|
913
|
+
effectful,
|
|
914
|
+
// override and mark all identifiers inside of left expression as assignee
|
|
915
|
+
(id) => transformIdentifier(id, true)
|
|
916
|
+
);
|
|
917
|
+
const right = generateCode(
|
|
918
|
+
node.right,
|
|
919
|
+
failOnForbidden,
|
|
920
|
+
effectful,
|
|
921
|
+
transformIdentifier
|
|
922
|
+
);
|
|
923
|
+
return `${left} ${node.operator} ${right}`;
|
|
924
|
+
}
|
|
925
|
+
if (node.type === "UpdateExpression") {
|
|
926
|
+
throw Error(`"${node.operator}" operator is not supported`);
|
|
927
|
+
}
|
|
928
|
+
node;
|
|
929
|
+
return "";
|
|
930
|
+
};
|
|
931
|
+
var validateExpression = (code, options) => {
|
|
932
|
+
const { effectful = false, transformIdentifier = (id) => id } = options ?? {};
|
|
933
|
+
const expression = jsep(code);
|
|
934
|
+
return generateCode(expression, true, effectful, transformIdentifier);
|
|
935
|
+
};
|
|
936
|
+
var sortTopologically = (list, depsById, explored = /* @__PURE__ */ new Set(), sorted = []) => {
|
|
937
|
+
for (const id of list) {
|
|
938
|
+
if (explored.has(id)) {
|
|
939
|
+
continue;
|
|
940
|
+
}
|
|
941
|
+
explored.add(id);
|
|
942
|
+
const deps = depsById.get(id);
|
|
943
|
+
if (deps) {
|
|
944
|
+
sortTopologically(deps, depsById, explored, sorted);
|
|
945
|
+
}
|
|
946
|
+
sorted.push(id);
|
|
947
|
+
}
|
|
948
|
+
return sorted;
|
|
949
|
+
};
|
|
950
|
+
var generateComputingExpressions = (expressions, allowedVariables) => {
|
|
951
|
+
const depsById = /* @__PURE__ */ new Map();
|
|
952
|
+
const inputVariables = /* @__PURE__ */ new Set();
|
|
953
|
+
for (const [id, code] of expressions) {
|
|
954
|
+
const deps = /* @__PURE__ */ new Set();
|
|
955
|
+
validateExpression(code, {
|
|
956
|
+
transformIdentifier: (identifier) => {
|
|
957
|
+
if (allowedVariables.has(identifier)) {
|
|
958
|
+
inputVariables.add(identifier);
|
|
959
|
+
return identifier;
|
|
960
|
+
}
|
|
961
|
+
if (expressions.has(identifier)) {
|
|
962
|
+
deps.add(identifier);
|
|
963
|
+
return identifier;
|
|
964
|
+
}
|
|
965
|
+
throw Error(`Unknown dependency "${identifier}"`);
|
|
966
|
+
}
|
|
967
|
+
});
|
|
968
|
+
depsById.set(id, deps);
|
|
969
|
+
}
|
|
970
|
+
const sortedExpressions = sortTopologically(
|
|
971
|
+
new Set(expressions.keys()),
|
|
972
|
+
depsById
|
|
973
|
+
);
|
|
974
|
+
let generatedCode = "";
|
|
975
|
+
for (const id of inputVariables) {
|
|
976
|
+
generatedCode += `const ${id} = _variables.get('${id}');
|
|
977
|
+
`;
|
|
978
|
+
}
|
|
979
|
+
for (const id of sortedExpressions) {
|
|
980
|
+
const code = expressions.get(id);
|
|
981
|
+
if (code === void 0) {
|
|
982
|
+
continue;
|
|
983
|
+
}
|
|
984
|
+
generatedCode += `const ${id} = (${code});
|
|
985
|
+
`;
|
|
986
|
+
}
|
|
987
|
+
generatedCode += `return new Map([
|
|
988
|
+
`;
|
|
989
|
+
for (const id of sortedExpressions) {
|
|
990
|
+
generatedCode += ` ['${id}', ${id}],
|
|
991
|
+
`;
|
|
992
|
+
}
|
|
993
|
+
generatedCode += `]);`;
|
|
994
|
+
return generatedCode;
|
|
995
|
+
};
|
|
996
|
+
var executeComputingExpressions = (expressions, variables) => {
|
|
997
|
+
const generatedCode = generateComputingExpressions(
|
|
998
|
+
expressions,
|
|
999
|
+
new Set(variables.keys())
|
|
1000
|
+
);
|
|
1001
|
+
const executeFn = new Function("_variables", generatedCode);
|
|
1002
|
+
const values = executeFn(variables);
|
|
1003
|
+
return values;
|
|
1004
|
+
};
|
|
1005
|
+
var generateEffectfulExpression = (code, args, allowedVariables) => {
|
|
1006
|
+
const inputVariables = /* @__PURE__ */ new Set();
|
|
1007
|
+
const outputVariables = /* @__PURE__ */ new Set();
|
|
1008
|
+
validateExpression(code, {
|
|
1009
|
+
effectful: true,
|
|
1010
|
+
transformIdentifier: (identifier, assignee) => {
|
|
1011
|
+
if (args.has(identifier)) {
|
|
1012
|
+
return identifier;
|
|
1013
|
+
}
|
|
1014
|
+
if (allowedVariables.has(identifier)) {
|
|
1015
|
+
if (assignee) {
|
|
1016
|
+
outputVariables.add(identifier);
|
|
1017
|
+
} else {
|
|
1018
|
+
inputVariables.add(identifier);
|
|
1019
|
+
}
|
|
1020
|
+
return identifier;
|
|
1021
|
+
}
|
|
1022
|
+
throw Error(`Unknown dependency "${identifier}"`);
|
|
1023
|
+
}
|
|
1024
|
+
});
|
|
1025
|
+
let generatedCode = "";
|
|
1026
|
+
for (const id of args) {
|
|
1027
|
+
generatedCode += `let ${id} = _args.get('${id}');
|
|
1028
|
+
`;
|
|
1029
|
+
}
|
|
1030
|
+
for (const id of inputVariables) {
|
|
1031
|
+
generatedCode += `let ${id} = _variables.get('${id}');
|
|
1032
|
+
`;
|
|
1033
|
+
}
|
|
1034
|
+
for (const id of outputVariables) {
|
|
1035
|
+
if (inputVariables.has(id) === false) {
|
|
1036
|
+
generatedCode += `let ${id};
|
|
1037
|
+
`;
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
generatedCode += `${code};
|
|
1041
|
+
`;
|
|
1042
|
+
generatedCode += `return new Map([
|
|
1043
|
+
`;
|
|
1044
|
+
for (const id of outputVariables) {
|
|
1045
|
+
generatedCode += ` ['${id}', ${id}],
|
|
1046
|
+
`;
|
|
1047
|
+
}
|
|
1048
|
+
generatedCode += `]);`;
|
|
1049
|
+
return generatedCode;
|
|
1050
|
+
};
|
|
1051
|
+
var executeEffectfulExpression = (code, args, variables) => {
|
|
1052
|
+
const generatedCode = generateEffectfulExpression(
|
|
1053
|
+
code,
|
|
1054
|
+
new Set(args.keys()),
|
|
1055
|
+
new Set(variables.keys())
|
|
1056
|
+
);
|
|
1057
|
+
const executeFn = new Function("_variables", "_args", generatedCode);
|
|
1058
|
+
const values = executeFn(variables, args);
|
|
1059
|
+
return values;
|
|
1060
|
+
};
|
|
1061
|
+
var computeExpressionDependencies = (expressions, expressionId, dependencies) => {
|
|
1062
|
+
const depsById = dependencies.get(expressionId);
|
|
1063
|
+
if (depsById) {
|
|
1064
|
+
return depsById;
|
|
1065
|
+
}
|
|
1066
|
+
const parentDeps = /* @__PURE__ */ new Set();
|
|
1067
|
+
const code = expressions.get(expressionId);
|
|
1068
|
+
if (code === void 0) {
|
|
1069
|
+
return parentDeps;
|
|
1070
|
+
}
|
|
1071
|
+
dependencies.set(expressionId, parentDeps);
|
|
1072
|
+
validateExpression(code, {
|
|
1073
|
+
transformIdentifier: (id) => {
|
|
1074
|
+
parentDeps.add(id);
|
|
1075
|
+
const childDeps = computeExpressionDependencies(
|
|
1076
|
+
expressions,
|
|
1077
|
+
id,
|
|
1078
|
+
dependencies
|
|
1079
|
+
);
|
|
1080
|
+
for (const depId of childDeps) {
|
|
1081
|
+
parentDeps.add(depId);
|
|
1082
|
+
}
|
|
1083
|
+
return id;
|
|
1084
|
+
}
|
|
1085
|
+
});
|
|
1086
|
+
return parentDeps;
|
|
1087
|
+
};
|
|
1088
|
+
var computeExpressionsDependencies = (expressions) => {
|
|
1089
|
+
const dependencies = /* @__PURE__ */ new Map();
|
|
1090
|
+
for (const id of expressions.keys()) {
|
|
1091
|
+
computeExpressionDependencies(expressions, id, dependencies);
|
|
1092
|
+
}
|
|
1093
|
+
return dependencies;
|
|
1094
|
+
};
|
|
1095
|
+
var dataSourceVariablePrefix = "$ws$dataSource$";
|
|
1096
|
+
var encodeDataSourceVariable = (id) => {
|
|
1097
|
+
const encoded = id.replaceAll("-", "__DASH__");
|
|
1098
|
+
return `${dataSourceVariablePrefix}${encoded}`;
|
|
1099
|
+
};
|
|
1100
|
+
var encodeVariablesMap = (values) => {
|
|
1101
|
+
const encodedValues = /* @__PURE__ */ new Map();
|
|
1102
|
+
for (const [id, value] of values) {
|
|
1103
|
+
encodedValues.set(encodeDataSourceVariable(id), value);
|
|
1104
|
+
}
|
|
1105
|
+
return encodedValues;
|
|
1106
|
+
};
|
|
1107
|
+
var decodeDataSourceVariable = (name) => {
|
|
1108
|
+
if (name.startsWith(dataSourceVariablePrefix)) {
|
|
1109
|
+
const encoded = name.slice(dataSourceVariablePrefix.length);
|
|
1110
|
+
return encoded.replaceAll("__DASH__", "-");
|
|
1111
|
+
}
|
|
1112
|
+
return;
|
|
1113
|
+
};
|
|
1114
|
+
var decodeVariablesMap = (values) => {
|
|
1115
|
+
const decodedValues = /* @__PURE__ */ new Map();
|
|
1116
|
+
for (const [name, value] of values) {
|
|
1117
|
+
const id = decodeDataSourceVariable(name);
|
|
1118
|
+
if (id !== void 0) {
|
|
1119
|
+
decodedValues.set(id, value);
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
return decodedValues;
|
|
1123
|
+
};
|
|
1124
|
+
|
|
1125
|
+
// src/embed-template.ts
|
|
1126
|
+
var EmbedTemplateText = z2.object({
|
|
1127
|
+
type: z2.literal("text"),
|
|
1128
|
+
value: z2.string()
|
|
1129
|
+
});
|
|
1130
|
+
var EmbedTemplateDataSource = z2.union([
|
|
1131
|
+
z2.object({
|
|
1132
|
+
type: z2.literal("variable"),
|
|
1133
|
+
initialValue: z2.union([
|
|
1134
|
+
z2.string(),
|
|
1135
|
+
z2.number(),
|
|
1136
|
+
z2.boolean(),
|
|
1137
|
+
z2.array(z2.string())
|
|
1138
|
+
])
|
|
1139
|
+
}),
|
|
1140
|
+
z2.object({
|
|
1141
|
+
type: z2.literal("expression"),
|
|
1142
|
+
code: z2.string()
|
|
1143
|
+
})
|
|
1144
|
+
]);
|
|
1145
|
+
var EmbedTemplateProp = z2.union([
|
|
1146
|
+
z2.object({
|
|
1147
|
+
type: z2.literal("dataSource"),
|
|
1148
|
+
name: z2.string(),
|
|
1149
|
+
dataSourceName: z2.string()
|
|
1150
|
+
}),
|
|
1151
|
+
z2.object({
|
|
1152
|
+
type: z2.literal("number"),
|
|
1153
|
+
name: z2.string(),
|
|
1154
|
+
value: z2.number()
|
|
1155
|
+
}),
|
|
1156
|
+
z2.object({
|
|
1157
|
+
type: z2.literal("string"),
|
|
1158
|
+
name: z2.string(),
|
|
1159
|
+
value: z2.string()
|
|
1160
|
+
}),
|
|
1161
|
+
z2.object({
|
|
1162
|
+
type: z2.literal("boolean"),
|
|
1163
|
+
name: z2.string(),
|
|
1164
|
+
value: z2.boolean()
|
|
1165
|
+
}),
|
|
1166
|
+
z2.object({
|
|
1167
|
+
type: z2.literal("string[]"),
|
|
1168
|
+
name: z2.string(),
|
|
1169
|
+
value: z2.array(z2.string())
|
|
1170
|
+
}),
|
|
1171
|
+
z2.object({
|
|
1172
|
+
type: z2.literal("action"),
|
|
1173
|
+
name: z2.string(),
|
|
1174
|
+
value: z2.array(
|
|
1175
|
+
z2.object({
|
|
1176
|
+
type: z2.literal("execute"),
|
|
1177
|
+
args: z2.optional(z2.array(z2.string())),
|
|
1178
|
+
code: z2.string()
|
|
1179
|
+
})
|
|
1180
|
+
)
|
|
1181
|
+
})
|
|
1182
|
+
]);
|
|
1183
|
+
var EmbedTemplateStyleDeclRaw = z2.object({
|
|
1184
|
+
// State selector, e.g. :hover
|
|
1185
|
+
state: z2.optional(z2.string()),
|
|
1186
|
+
property: z2.string(),
|
|
1187
|
+
value: StyleValue
|
|
1188
|
+
});
|
|
1189
|
+
var EmbedTemplateStyleDecl = EmbedTemplateStyleDeclRaw;
|
|
1190
|
+
var EmbedTemplateInstance = z2.lazy(
|
|
1191
|
+
() => z2.object({
|
|
1192
|
+
type: z2.literal("instance"),
|
|
1193
|
+
component: z2.string(),
|
|
1194
|
+
label: z2.optional(z2.string()),
|
|
1195
|
+
dataSources: z2.optional(z2.record(z2.string(), EmbedTemplateDataSource)),
|
|
1196
|
+
props: z2.optional(z2.array(EmbedTemplateProp)),
|
|
1197
|
+
tokens: z2.optional(z2.array(z2.string())),
|
|
1198
|
+
styles: z2.optional(z2.array(EmbedTemplateStyleDecl)),
|
|
1199
|
+
children: WsEmbedTemplate
|
|
1200
|
+
})
|
|
1201
|
+
);
|
|
1202
|
+
var WsEmbedTemplate = z2.lazy(
|
|
1203
|
+
() => z2.array(z2.union([EmbedTemplateInstance, EmbedTemplateText]))
|
|
1204
|
+
);
|
|
1205
|
+
var getDataSourceValue = (value) => {
|
|
1206
|
+
if (typeof value === "string") {
|
|
1207
|
+
return { type: "string", value };
|
|
1208
|
+
}
|
|
1209
|
+
if (typeof value === "number") {
|
|
1210
|
+
return { type: "number", value };
|
|
1211
|
+
}
|
|
1212
|
+
if (typeof value === "boolean") {
|
|
1213
|
+
return { type: "boolean", value };
|
|
1214
|
+
}
|
|
1215
|
+
if (Array.isArray(value)) {
|
|
1216
|
+
return { type: "string[]", value };
|
|
1217
|
+
}
|
|
1218
|
+
value;
|
|
1219
|
+
throw Error("Impossible case");
|
|
1220
|
+
};
|
|
1221
|
+
var createInstancesFromTemplate = (treeTemplate, instances, props, dataSourceByRef, styleSourceSelections, styleSources, styles, metas, defaultBreakpointId) => {
|
|
1222
|
+
const parentChildren = [];
|
|
1223
|
+
for (const item of treeTemplate) {
|
|
1224
|
+
if (item.type === "instance") {
|
|
1225
|
+
const instanceId = nanoid();
|
|
1226
|
+
if (item.dataSources) {
|
|
1227
|
+
for (const [name, dataSource] of Object.entries(item.dataSources)) {
|
|
1228
|
+
if (dataSourceByRef.has(name)) {
|
|
1229
|
+
throw Error(`${name} data source already defined`);
|
|
1230
|
+
}
|
|
1231
|
+
if (dataSource.type === "variable") {
|
|
1232
|
+
dataSourceByRef.set(name, {
|
|
1233
|
+
type: "variable",
|
|
1234
|
+
id: nanoid(),
|
|
1235
|
+
scopeInstanceId: instanceId,
|
|
1236
|
+
name,
|
|
1237
|
+
value: getDataSourceValue(dataSource.initialValue)
|
|
1238
|
+
});
|
|
1239
|
+
}
|
|
1240
|
+
if (dataSource.type === "expression") {
|
|
1241
|
+
dataSourceByRef.set(name, {
|
|
1242
|
+
type: "expression",
|
|
1243
|
+
id: nanoid(),
|
|
1244
|
+
scopeInstanceId: instanceId,
|
|
1245
|
+
name,
|
|
1246
|
+
// replace all references with variable names
|
|
1247
|
+
code: validateExpression(dataSource.code, {
|
|
1248
|
+
transformIdentifier: (ref) => {
|
|
1249
|
+
const id = dataSourceByRef.get(ref)?.id ?? ref;
|
|
1250
|
+
return encodeDataSourceVariable(id);
|
|
1251
|
+
}
|
|
1252
|
+
})
|
|
1253
|
+
});
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
if (item.props) {
|
|
1258
|
+
for (const prop of item.props) {
|
|
1259
|
+
const propId = nanoid();
|
|
1260
|
+
if (prop.type === "action") {
|
|
1261
|
+
props.push({
|
|
1262
|
+
id: propId,
|
|
1263
|
+
instanceId,
|
|
1264
|
+
type: "action",
|
|
1265
|
+
name: prop.name,
|
|
1266
|
+
value: prop.value.map((value) => {
|
|
1267
|
+
const args = value.args ?? [];
|
|
1268
|
+
return {
|
|
1269
|
+
type: "execute",
|
|
1270
|
+
args,
|
|
1271
|
+
// replace all references with variable names
|
|
1272
|
+
code: validateExpression(value.code, {
|
|
1273
|
+
effectful: true,
|
|
1274
|
+
transformIdentifier: (ref) => {
|
|
1275
|
+
if (args.includes(ref)) {
|
|
1276
|
+
return ref;
|
|
1277
|
+
}
|
|
1278
|
+
const id = dataSourceByRef.get(ref)?.id ?? ref;
|
|
1279
|
+
return encodeDataSourceVariable(id);
|
|
1280
|
+
}
|
|
1281
|
+
})
|
|
1282
|
+
};
|
|
1283
|
+
})
|
|
1284
|
+
});
|
|
1285
|
+
continue;
|
|
1286
|
+
}
|
|
1287
|
+
if (prop.type === "dataSource") {
|
|
1288
|
+
const dataSource = dataSourceByRef.get(prop.dataSourceName);
|
|
1289
|
+
if (dataSource === void 0) {
|
|
1290
|
+
throw Error(`${prop.dataSourceName} data source is not defined`);
|
|
1291
|
+
}
|
|
1292
|
+
props.push({
|
|
1293
|
+
id: propId,
|
|
1294
|
+
instanceId,
|
|
1295
|
+
type: "dataSource",
|
|
1296
|
+
name: prop.name,
|
|
1297
|
+
value: dataSource.id
|
|
1298
|
+
});
|
|
1299
|
+
continue;
|
|
1300
|
+
}
|
|
1301
|
+
props.push({ id: propId, instanceId, ...prop });
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
const styleSourceIds = [];
|
|
1305
|
+
if (item.tokens) {
|
|
1306
|
+
const meta = metas.get(item.component);
|
|
1307
|
+
if (meta?.presetTokens) {
|
|
1308
|
+
for (const name of item.tokens) {
|
|
1309
|
+
const tokenValue = meta.presetTokens[name];
|
|
1310
|
+
if (tokenValue) {
|
|
1311
|
+
const styleSourceId = `${item.component}:${name}`;
|
|
1312
|
+
styleSourceIds.push(styleSourceId);
|
|
1313
|
+
styleSources.push({
|
|
1314
|
+
type: "token",
|
|
1315
|
+
id: styleSourceId,
|
|
1316
|
+
name: titleCase(noCase(name))
|
|
1317
|
+
});
|
|
1318
|
+
for (const styleDecl of tokenValue.styles) {
|
|
1319
|
+
styles.push({
|
|
1320
|
+
breakpointId: defaultBreakpointId,
|
|
1321
|
+
styleSourceId,
|
|
1322
|
+
state: styleDecl.state,
|
|
1323
|
+
property: styleDecl.property,
|
|
1324
|
+
value: styleDecl.value
|
|
1325
|
+
});
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
if (item.styles) {
|
|
1332
|
+
const styleSourceId = nanoid();
|
|
1333
|
+
styleSources.push({
|
|
1334
|
+
type: "local",
|
|
1335
|
+
id: styleSourceId
|
|
1336
|
+
});
|
|
1337
|
+
styleSourceIds.push(styleSourceId);
|
|
1338
|
+
for (const styleDecl of item.styles) {
|
|
1339
|
+
styles.push({
|
|
1340
|
+
breakpointId: defaultBreakpointId,
|
|
1341
|
+
styleSourceId,
|
|
1342
|
+
state: styleDecl.state,
|
|
1343
|
+
property: styleDecl.property,
|
|
1344
|
+
value: styleDecl.value
|
|
1345
|
+
});
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
if (styleSourceIds.length > 0) {
|
|
1349
|
+
styleSourceSelections.push({
|
|
1350
|
+
instanceId,
|
|
1351
|
+
values: styleSourceIds
|
|
1352
|
+
});
|
|
1353
|
+
}
|
|
1354
|
+
const instance = {
|
|
1355
|
+
type: "instance",
|
|
1356
|
+
id: instanceId,
|
|
1357
|
+
label: item.label,
|
|
1358
|
+
component: item.component,
|
|
1359
|
+
children: []
|
|
1360
|
+
};
|
|
1361
|
+
instances.push(instance);
|
|
1362
|
+
instance.children = createInstancesFromTemplate(
|
|
1363
|
+
item.children,
|
|
1364
|
+
instances,
|
|
1365
|
+
props,
|
|
1366
|
+
dataSourceByRef,
|
|
1367
|
+
styleSourceSelections,
|
|
1368
|
+
styleSources,
|
|
1369
|
+
styles,
|
|
1370
|
+
metas,
|
|
1371
|
+
defaultBreakpointId
|
|
1372
|
+
);
|
|
1373
|
+
parentChildren.push({
|
|
1374
|
+
type: "id",
|
|
1375
|
+
value: instanceId
|
|
1376
|
+
});
|
|
1377
|
+
}
|
|
1378
|
+
if (item.type === "text") {
|
|
1379
|
+
parentChildren.push({
|
|
1380
|
+
type: "text",
|
|
1381
|
+
value: item.value
|
|
1382
|
+
});
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
return parentChildren;
|
|
1386
|
+
};
|
|
1387
|
+
var generateDataFromEmbedTemplate = (treeTemplate, metas, defaultBreakpointId) => {
|
|
1388
|
+
const instances = [];
|
|
1389
|
+
const props = [];
|
|
1390
|
+
const dataSourceByRef = /* @__PURE__ */ new Map();
|
|
1391
|
+
const styleSourceSelections = [];
|
|
1392
|
+
const styleSources = [];
|
|
1393
|
+
const styles = [];
|
|
1394
|
+
const children = createInstancesFromTemplate(
|
|
1395
|
+
treeTemplate,
|
|
1396
|
+
instances,
|
|
1397
|
+
props,
|
|
1398
|
+
dataSourceByRef,
|
|
1399
|
+
styleSourceSelections,
|
|
1400
|
+
styleSources,
|
|
1401
|
+
styles,
|
|
1402
|
+
metas,
|
|
1403
|
+
defaultBreakpointId
|
|
1404
|
+
);
|
|
1405
|
+
return {
|
|
1406
|
+
children,
|
|
1407
|
+
instances,
|
|
1408
|
+
props,
|
|
1409
|
+
dataSources: Array.from(dataSourceByRef.values()),
|
|
1410
|
+
styleSourceSelections,
|
|
1411
|
+
styleSources,
|
|
1412
|
+
styles
|
|
1413
|
+
};
|
|
1414
|
+
};
|
|
1415
|
+
var namespaceEmbedTemplateComponents = (template, namespace, components) => {
|
|
1416
|
+
return template.map((item) => {
|
|
1417
|
+
if (item.type === "text") {
|
|
1418
|
+
return item;
|
|
1419
|
+
}
|
|
1420
|
+
if (item.type === "instance") {
|
|
1421
|
+
const prefix = components.has(item.component) ? `${namespace}:` : "";
|
|
1422
|
+
return {
|
|
1423
|
+
...item,
|
|
1424
|
+
component: `${prefix}${item.component}`,
|
|
1425
|
+
children: namespaceEmbedTemplateComponents(
|
|
1426
|
+
item.children,
|
|
1427
|
+
namespace,
|
|
1428
|
+
components
|
|
1429
|
+
)
|
|
1430
|
+
};
|
|
1431
|
+
}
|
|
1432
|
+
item;
|
|
1433
|
+
throw Error("Impossible case");
|
|
1434
|
+
});
|
|
1435
|
+
};
|
|
1436
|
+
var namespaceMeta = (meta, namespace, components) => {
|
|
1437
|
+
const newMeta = { ...meta };
|
|
1438
|
+
if (newMeta.requiredAncestors) {
|
|
1439
|
+
newMeta.requiredAncestors = newMeta.requiredAncestors.map(
|
|
1440
|
+
(component) => components.has(component) ? `${namespace}:${component}` : component
|
|
1441
|
+
);
|
|
1442
|
+
}
|
|
1443
|
+
if (newMeta.invalidAncestors) {
|
|
1444
|
+
newMeta.invalidAncestors = newMeta.invalidAncestors.map(
|
|
1445
|
+
(component) => components.has(component) ? `${namespace}:${component}` : component
|
|
1446
|
+
);
|
|
1447
|
+
}
|
|
1448
|
+
if (newMeta.indexWithinAncestor) {
|
|
1449
|
+
newMeta.indexWithinAncestor = components.has(newMeta.indexWithinAncestor) ? `${namespace}:${newMeta.indexWithinAncestor}` : newMeta.indexWithinAncestor;
|
|
1450
|
+
}
|
|
1451
|
+
if (newMeta.template) {
|
|
1452
|
+
newMeta.template = namespaceEmbedTemplateComponents(
|
|
1453
|
+
newMeta.template,
|
|
1454
|
+
namespace,
|
|
1455
|
+
components
|
|
1456
|
+
);
|
|
1457
|
+
}
|
|
1458
|
+
return newMeta;
|
|
1459
|
+
};
|
|
1460
|
+
|
|
1461
|
+
// src/components/component-meta.ts
|
|
1462
|
+
var WsComponentPropsMeta = z3.object({
|
|
1463
|
+
props: z3.record(PropMeta),
|
|
1464
|
+
// Props that will be always visible in properties panel.
|
|
1465
|
+
initialProps: z3.array(z3.string()).optional()
|
|
1466
|
+
});
|
|
1467
|
+
var componentCategories = [
|
|
1468
|
+
"general",
|
|
1469
|
+
"text",
|
|
1470
|
+
"media",
|
|
1471
|
+
"forms",
|
|
1472
|
+
"radix",
|
|
1473
|
+
"hidden"
|
|
1474
|
+
];
|
|
1475
|
+
var stateCategories = ["states", "component-states"];
|
|
1476
|
+
var ComponentState = z3.object({
|
|
1477
|
+
category: z3.enum(stateCategories).optional(),
|
|
1478
|
+
selector: z3.string(),
|
|
1479
|
+
label: z3.string()
|
|
1480
|
+
});
|
|
1481
|
+
var ComponentToken = z3.object({
|
|
1482
|
+
variant: z3.optional(z3.string()),
|
|
1483
|
+
styles: z3.array(EmbedTemplateStyleDecl)
|
|
1484
|
+
});
|
|
1485
|
+
var defaultStates = [
|
|
1486
|
+
{ selector: ":hover", label: "Hover" },
|
|
1487
|
+
{ selector: ":active", label: "Active" },
|
|
1488
|
+
{ selector: ":focus", label: "Focus" },
|
|
1489
|
+
{ selector: ":focus-visible", label: "Focus Visible" },
|
|
1490
|
+
{ selector: ":focus-within", label: "Focus Within" }
|
|
1491
|
+
];
|
|
1492
|
+
var WsComponentMeta = z3.object({
|
|
1493
|
+
category: z3.enum(componentCategories).optional(),
|
|
1494
|
+
// container - can accept other components with dnd or be edited as text
|
|
1495
|
+
// control - usually form controls like inputs, without children
|
|
1496
|
+
// embed - images, videos or other embeddable components, without children
|
|
1497
|
+
// rich-text-child - formatted text fragment, not listed in components list
|
|
1498
|
+
type: z3.enum(["container", "control", "embed", "rich-text-child"]),
|
|
1499
|
+
requiredAncestors: z3.optional(z3.array(z3.string())),
|
|
1500
|
+
invalidAncestors: z3.optional(z3.array(z3.string())),
|
|
1501
|
+
// when this field is specified component receives
|
|
1502
|
+
// prop with index of same components withiin specified ancestor
|
|
1503
|
+
// important to automatically enumerate collections without
|
|
1504
|
+
// naming every item manually
|
|
1505
|
+
indexWithinAncestor: z3.optional(z3.string()),
|
|
1506
|
+
stylable: z3.optional(z3.boolean()),
|
|
1507
|
+
// specifies whether the instance can be deleted,
|
|
1508
|
+
// copied or dragged out of its parent instance
|
|
1509
|
+
// true by default
|
|
1510
|
+
detachable: z3.optional(z3.boolean()),
|
|
1511
|
+
label: z3.optional(z3.string()),
|
|
1512
|
+
description: z3.string().optional(),
|
|
1513
|
+
icon: z3.string(),
|
|
1514
|
+
presetStyle: z3.optional(z3.record(z3.string(), EmbedTemplateStyleDecl)),
|
|
1515
|
+
presetTokens: z3.optional(z3.record(z3.string(), ComponentToken)),
|
|
1516
|
+
states: z3.optional(z3.array(ComponentState)),
|
|
1517
|
+
template: z3.optional(WsEmbedTemplate),
|
|
1518
|
+
order: z3.number().optional()
|
|
1519
|
+
});
|
|
1520
|
+
|
|
1521
|
+
// src/component-renderer.tsx
|
|
1522
|
+
import { getStyleDeclKey } from "@webstudio-is/sdk";
|
|
1523
|
+
|
|
1524
|
+
// src/instance-utils.ts
|
|
1525
|
+
var getIndexesWithinAncestors = (metas, instances, rootIds) => {
|
|
1526
|
+
const ancestors = /* @__PURE__ */ new Set();
|
|
1527
|
+
for (const meta of metas.values()) {
|
|
1528
|
+
if (meta.indexWithinAncestor !== void 0) {
|
|
1529
|
+
ancestors.add(meta.indexWithinAncestor);
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
const indexes = /* @__PURE__ */ new Map();
|
|
1533
|
+
const traverseInstances = (instances2, instanceId, latestIndexes2 = /* @__PURE__ */ new Map()) => {
|
|
1534
|
+
const instance = instances2.get(instanceId);
|
|
1535
|
+
if (instance === void 0) {
|
|
1536
|
+
return;
|
|
1537
|
+
}
|
|
1538
|
+
const meta = metas.get(instance.component);
|
|
1539
|
+
if (meta === void 0) {
|
|
1540
|
+
return;
|
|
1541
|
+
}
|
|
1542
|
+
if (ancestors.has(instance.component)) {
|
|
1543
|
+
latestIndexes2 = new Map(latestIndexes2);
|
|
1544
|
+
latestIndexes2.set(instance.component, /* @__PURE__ */ new Map());
|
|
1545
|
+
}
|
|
1546
|
+
if (meta.indexWithinAncestor !== void 0) {
|
|
1547
|
+
const ancestorIndexes = latestIndexes2.get(meta.indexWithinAncestor);
|
|
1548
|
+
if (ancestorIndexes !== void 0) {
|
|
1549
|
+
let index = ancestorIndexes.get(instance.component) ?? -1;
|
|
1550
|
+
index += 1;
|
|
1551
|
+
ancestorIndexes.set(instance.component, index);
|
|
1552
|
+
indexes.set(instance.id, index);
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
for (const child of instance.children) {
|
|
1556
|
+
if (child.type === "id") {
|
|
1557
|
+
traverseInstances(instances2, child.value, latestIndexes2);
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
};
|
|
1561
|
+
const latestIndexes = /* @__PURE__ */ new Map();
|
|
1562
|
+
for (const instanceId of rootIds) {
|
|
1563
|
+
traverseInstances(instances, instanceId, latestIndexes);
|
|
1564
|
+
}
|
|
1565
|
+
return indexes;
|
|
1566
|
+
};
|
|
1567
|
+
|
|
1568
|
+
// src/component-renderer.tsx
|
|
1569
|
+
import { Fragment as Fragment4, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1570
|
+
var renderComponentTemplate = ({
|
|
1571
|
+
name,
|
|
1572
|
+
metas: metasRecord,
|
|
1573
|
+
components,
|
|
1574
|
+
props
|
|
1575
|
+
}) => {
|
|
1576
|
+
const metas = new Map(Object.entries(metasRecord));
|
|
1577
|
+
const template = metas.get(name)?.template ?? [
|
|
1578
|
+
{
|
|
1579
|
+
type: "instance",
|
|
1580
|
+
component: name,
|
|
1581
|
+
children: []
|
|
1582
|
+
}
|
|
1583
|
+
];
|
|
1584
|
+
if (template[0].type === "instance" && props !== void 0) {
|
|
1585
|
+
template[0].props = Object.entries(props).map(([prop, value]) => {
|
|
1586
|
+
if (typeof value === "string") {
|
|
1587
|
+
return { type: "string", name: prop, value };
|
|
1588
|
+
}
|
|
1589
|
+
if (typeof value === "number") {
|
|
1590
|
+
return { type: "number", name: prop, value };
|
|
1591
|
+
}
|
|
1592
|
+
if (typeof value === "boolean") {
|
|
1593
|
+
return { type: "boolean", name: prop, value };
|
|
1594
|
+
}
|
|
1595
|
+
throw new Error(`Unsupported prop ${props} with value ${value}`);
|
|
1596
|
+
});
|
|
1597
|
+
}
|
|
1598
|
+
const data = generateDataFromEmbedTemplate(template, metas, "base");
|
|
1599
|
+
const instances = [
|
|
1600
|
+
[
|
|
1601
|
+
"root",
|
|
1602
|
+
{
|
|
1603
|
+
type: "instance",
|
|
1604
|
+
id: "root",
|
|
1605
|
+
component: "Box",
|
|
1606
|
+
children: data.children
|
|
1607
|
+
}
|
|
1608
|
+
],
|
|
1609
|
+
...data.instances.map(
|
|
1610
|
+
(instance) => [instance.id, instance]
|
|
1611
|
+
)
|
|
1612
|
+
];
|
|
1613
|
+
return /* @__PURE__ */ jsxs4(Fragment4, { children: [
|
|
1614
|
+
/* @__PURE__ */ jsx4("style", { children: generateCssText(
|
|
1615
|
+
{
|
|
1616
|
+
assets: [],
|
|
1617
|
+
breakpoints: [["base", { id: "base", label: "base" }]],
|
|
1618
|
+
styles: data.styles.map((item) => [getStyleDeclKey(item), item]),
|
|
1619
|
+
styleSourceSelections: data.styleSourceSelections.map((item) => [
|
|
1620
|
+
item.instanceId,
|
|
1621
|
+
item
|
|
1622
|
+
]),
|
|
1623
|
+
componentMetas: metas
|
|
1624
|
+
},
|
|
1625
|
+
{ assetBaseUrl: "/" }
|
|
1626
|
+
) }),
|
|
1627
|
+
/* @__PURE__ */ jsx4(
|
|
1628
|
+
InstanceRoot,
|
|
1629
|
+
{
|
|
1630
|
+
data: {
|
|
1631
|
+
page: {
|
|
1632
|
+
path: "",
|
|
1633
|
+
id: "",
|
|
1634
|
+
name: "",
|
|
1635
|
+
title: "",
|
|
1636
|
+
meta: {},
|
|
1637
|
+
rootInstanceId: "root"
|
|
1638
|
+
},
|
|
1639
|
+
pages: [],
|
|
1640
|
+
assets: [],
|
|
1641
|
+
build: {
|
|
1642
|
+
instances,
|
|
1643
|
+
props: data.props.map((prop) => [prop.id, prop]),
|
|
1644
|
+
dataSources: data.dataSources.map((dataSource) => [
|
|
1645
|
+
dataSource.id,
|
|
1646
|
+
dataSource
|
|
1647
|
+
])
|
|
1648
|
+
}
|
|
1649
|
+
},
|
|
1650
|
+
utils: {
|
|
1651
|
+
indexesWithinAncestors: getIndexesWithinAncestors(
|
|
1652
|
+
metas,
|
|
1653
|
+
new Map(instances),
|
|
1654
|
+
["root"]
|
|
1655
|
+
),
|
|
1656
|
+
executeComputingExpressions: (values) => {
|
|
1657
|
+
const expressions = /* @__PURE__ */ new Map();
|
|
1658
|
+
for (const dataSource of data.dataSources) {
|
|
1659
|
+
const name2 = encodeDataSourceVariable(dataSource.id);
|
|
1660
|
+
if (dataSource.type === "expression") {
|
|
1661
|
+
expressions.set(name2, dataSource.code);
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
return decodeVariablesMap(
|
|
1665
|
+
executeComputingExpressions(
|
|
1666
|
+
expressions,
|
|
1667
|
+
encodeVariablesMap(values)
|
|
1668
|
+
)
|
|
1669
|
+
);
|
|
1670
|
+
},
|
|
1671
|
+
executeEffectfulExpression: (code, args, values) => {
|
|
1672
|
+
return decodeVariablesMap(
|
|
1673
|
+
executeEffectfulExpression(code, args, encodeVariablesMap(values))
|
|
1674
|
+
);
|
|
1675
|
+
}
|
|
1676
|
+
},
|
|
1677
|
+
Component: WebstudioComponent,
|
|
1678
|
+
components: new Map(Object.entries(components))
|
|
1679
|
+
}
|
|
1680
|
+
)
|
|
1681
|
+
] });
|
|
1682
|
+
};
|
|
1683
|
+
|
|
1684
|
+
// src/hook.ts
|
|
1685
|
+
var getClosestInstance = (instancePath, currentInstance, closestComponent) => {
|
|
1686
|
+
let matched = false;
|
|
1687
|
+
for (const instance of instancePath) {
|
|
1688
|
+
if (currentInstance === instance) {
|
|
1689
|
+
matched = true;
|
|
1690
|
+
}
|
|
1691
|
+
if (matched && instance.component === closestComponent) {
|
|
1692
|
+
return instance;
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
};
|
|
1696
|
+
|
|
1697
|
+
// src/generator.ts
|
|
1698
|
+
var generateUtilsExport = (siteData) => {
|
|
1699
|
+
const indexesWithinAncestors = getIndexesWithinAncestors(
|
|
1700
|
+
siteData.metas,
|
|
1701
|
+
siteData.instances,
|
|
1702
|
+
[siteData.page.rootInstanceId]
|
|
1703
|
+
);
|
|
1704
|
+
let indexesWithinAncestorsEntries = "";
|
|
1705
|
+
for (const [key, value] of indexesWithinAncestors) {
|
|
1706
|
+
const keyString = JSON.stringify(key);
|
|
1707
|
+
const valueString = JSON.stringify(value);
|
|
1708
|
+
indexesWithinAncestorsEntries += `[${keyString}, ${valueString}],
|
|
1709
|
+
`;
|
|
1710
|
+
}
|
|
1711
|
+
const generatedIndexesWithinAncestors = `
|
|
1712
|
+
const indexesWithinAncestors = new Map<string, number>([
|
|
1713
|
+
${indexesWithinAncestorsEntries}
|
|
1714
|
+
]);
|
|
1715
|
+
`;
|
|
1716
|
+
const variables = /* @__PURE__ */ new Set();
|
|
1717
|
+
const expressions = /* @__PURE__ */ new Map();
|
|
1718
|
+
for (const dataSource of siteData.dataSources.values()) {
|
|
1719
|
+
if (dataSource.type === "variable") {
|
|
1720
|
+
variables.add(encodeDataSourceVariable(dataSource.id));
|
|
1721
|
+
}
|
|
1722
|
+
if (dataSource.type === "expression") {
|
|
1723
|
+
expressions.set(encodeDataSourceVariable(dataSource.id), dataSource.code);
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1726
|
+
const generatedExecuteComputingExpressions = `
|
|
1727
|
+
const rawExecuteComputingExpressions = (
|
|
1728
|
+
_variables: Map<string, unknown>
|
|
1729
|
+
): Map<string, unknown> => {
|
|
1730
|
+
${generateComputingExpressions(expressions, variables)}
|
|
1731
|
+
};
|
|
1732
|
+
const executeComputingExpressions = (variables: Map<string, unknown>) => {
|
|
1733
|
+
const encodedvariables = sdk.encodeVariablesMap(variables);
|
|
1734
|
+
const encodedResult = rawExecuteComputingExpressions(encodedvariables);
|
|
1735
|
+
return sdk.decodeVariablesMap(encodedResult);
|
|
1736
|
+
};
|
|
1737
|
+
`;
|
|
1738
|
+
let effectfulExpressionsEntries = "";
|
|
1739
|
+
for (const prop of siteData.props.values()) {
|
|
1740
|
+
if (prop.type === "action") {
|
|
1741
|
+
for (const executableValue of prop.value) {
|
|
1742
|
+
const codeString = JSON.stringify(executableValue.code);
|
|
1743
|
+
const generatedCode = generateEffectfulExpression(
|
|
1744
|
+
executableValue.code,
|
|
1745
|
+
new Set(executableValue.args),
|
|
1746
|
+
variables
|
|
1747
|
+
);
|
|
1748
|
+
const generatedFunction = `(_args: Map<string, any>, _variables: Map<string, any>) => { ${generatedCode} }`;
|
|
1749
|
+
effectfulExpressionsEntries += `[${codeString}, ${generatedFunction}],
|
|
1750
|
+
`;
|
|
1751
|
+
}
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1754
|
+
const generatedExecuteEffectfulExpression = `const generatedEffectfulExpressions = new Map<
|
|
1755
|
+
string,
|
|
1756
|
+
(args: Map<string, any>, variables: Map<string, any>) => Map<string, unknown>
|
|
1757
|
+
>([
|
|
1758
|
+
${effectfulExpressionsEntries}
|
|
1759
|
+
]);
|
|
1760
|
+
|
|
1761
|
+
const rawExecuteEffectfulExpression = (
|
|
1762
|
+
code: string,
|
|
1763
|
+
args: Map<string, unknown>,
|
|
1764
|
+
variables: Map<string, unknown>
|
|
1765
|
+
): Map<string, unknown> => {
|
|
1766
|
+
if(generatedEffectfulExpressions.has(code)) {
|
|
1767
|
+
return generatedEffectfulExpressions.get(code)!(args, variables);
|
|
1768
|
+
}
|
|
1769
|
+
console.error("Effectful expression not found", code);
|
|
1770
|
+
throw new Error("Effectful expression not found");
|
|
1771
|
+
};
|
|
1772
|
+
|
|
1773
|
+
const executeEffectfulExpression = (
|
|
1774
|
+
code: string,
|
|
1775
|
+
args: Map<string, unknown>,
|
|
1776
|
+
variables: Map<string, unknown>
|
|
1777
|
+
) => {
|
|
1778
|
+
const encodedvariables = sdk.encodeVariablesMap(variables);
|
|
1779
|
+
const encodedResult = rawExecuteEffectfulExpression(code, args, encodedvariables);
|
|
1780
|
+
return sdk.decodeVariablesMap(encodedResult);
|
|
1781
|
+
};
|
|
1782
|
+
`;
|
|
1783
|
+
return `
|
|
1784
|
+
/* eslint-disable */
|
|
1785
|
+
|
|
1786
|
+
${generatedIndexesWithinAncestors.trim()}
|
|
1787
|
+
|
|
1788
|
+
${generatedExecuteComputingExpressions.trim()}
|
|
1789
|
+
|
|
1790
|
+
${generatedExecuteEffectfulExpression.trim()}
|
|
1791
|
+
|
|
1792
|
+
export const utils = {
|
|
1793
|
+
indexesWithinAncestors,
|
|
1794
|
+
executeComputingExpressions,
|
|
1795
|
+
executeEffectfulExpression,
|
|
1796
|
+
};
|
|
1797
|
+
|
|
1798
|
+
/* eslint-enable */
|
|
1799
|
+
`;
|
|
1800
|
+
};
|
|
8
1801
|
export {
|
|
1802
|
+
EmbedTemplateInstance,
|
|
1803
|
+
EmbedTemplateStyleDecl,
|
|
1804
|
+
InstanceRoot,
|
|
1805
|
+
PropMeta,
|
|
1806
|
+
ReactSdkContext,
|
|
1807
|
+
Root,
|
|
1808
|
+
WebstudioComponent,
|
|
1809
|
+
WsEmbedTemplate,
|
|
1810
|
+
addGlobalRules,
|
|
1811
|
+
collapsedAttribute,
|
|
1812
|
+
componentAttribute,
|
|
9
1813
|
componentCategories,
|
|
10
|
-
stateCategories,
|
|
11
|
-
defaultStates
|
|
12
|
-
} from "./components/component-meta";
|
|
13
|
-
export * from "./embed-template";
|
|
14
|
-
export {
|
|
15
|
-
useInstanceProps,
|
|
16
|
-
usePropUrl,
|
|
17
|
-
usePropAsset,
|
|
18
|
-
getInstanceIdFromComponentProps,
|
|
19
|
-
getIndexWithinAncestorFromComponentProps
|
|
20
|
-
} from "./props";
|
|
21
|
-
export { ReactSdkContext } from "./context";
|
|
22
|
-
export {
|
|
23
|
-
validateExpression,
|
|
24
|
-
generateComputingExpressions,
|
|
25
|
-
executeComputingExpressions,
|
|
26
|
-
generateEffectfulExpression,
|
|
27
|
-
executeEffectfulExpression,
|
|
28
1814
|
computeExpressionsDependencies,
|
|
1815
|
+
createElementsTree,
|
|
1816
|
+
createImageValueTransformer,
|
|
1817
|
+
decodeDataSourceVariable,
|
|
1818
|
+
decodeVariablesMap,
|
|
1819
|
+
defaultStates,
|
|
29
1820
|
encodeDataSourceVariable,
|
|
30
1821
|
encodeVariablesMap,
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
1822
|
+
executeComputingExpressions,
|
|
1823
|
+
executeEffectfulExpression,
|
|
1824
|
+
generateComputingExpressions,
|
|
1825
|
+
generateCssText,
|
|
1826
|
+
generateDataFromEmbedTemplate,
|
|
1827
|
+
generateEffectfulExpression,
|
|
1828
|
+
generateUtilsExport,
|
|
1829
|
+
getClosestInstance,
|
|
1830
|
+
getIndexWithinAncestorFromComponentProps,
|
|
1831
|
+
getIndexesWithinAncestors,
|
|
1832
|
+
getInstanceIdFromComponentProps,
|
|
1833
|
+
getPresetStyleRules,
|
|
1834
|
+
getStyleRules,
|
|
1835
|
+
idAttribute,
|
|
1836
|
+
indexAttribute,
|
|
1837
|
+
namespaceMeta,
|
|
1838
|
+
renderComponentTemplate,
|
|
1839
|
+
renderWebstudioComponentChildren,
|
|
1840
|
+
selectorIdAttribute,
|
|
1841
|
+
showAttribute,
|
|
1842
|
+
splitPropsWithWebstudioAttributes,
|
|
1843
|
+
stateCategories,
|
|
1844
|
+
useInstanceProps,
|
|
1845
|
+
usePropAsset,
|
|
1846
|
+
usePropUrl,
|
|
1847
|
+
validateExpression
|
|
1848
|
+
};
|