@webstudio-is/react-sdk 0.82.0 → 0.84.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/LICENSE +661 -21
- package/lib/cjs/component-renderer.js +125 -0
- package/lib/cjs/components/component-meta.js +10 -0
- package/lib/cjs/components/components-utils.js +1 -0
- package/lib/cjs/context.js +2 -1
- package/lib/cjs/css/index.js +0 -1
- package/lib/cjs/css/style-rules.js +1 -1
- package/lib/cjs/embed-template.js +130 -55
- package/lib/cjs/expression.js +47 -4
- package/lib/cjs/hook.js +34 -0
- package/lib/cjs/index.js +7 -0
- package/lib/cjs/instance-utils.js +65 -0
- package/lib/cjs/props.js +18 -3
- package/lib/cjs/tree/create-elements-tree.js +5 -4
- package/lib/cjs/tree/root.js +7 -2
- package/lib/cjs/tree/webstudio-component.js +26 -10
- package/lib/component-renderer.js +111 -0
- package/lib/components/component-meta.js +10 -0
- package/lib/components/components-utils.js +1 -0
- package/lib/context.js +2 -1
- package/lib/css/index.js +0 -1
- package/lib/css/style-rules.js +1 -1
- package/lib/embed-template.js +138 -55
- package/lib/expression.js +47 -4
- package/lib/hook.js +14 -0
- package/lib/index.js +10 -1
- package/lib/instance-utils.js +45 -0
- package/lib/props.js +19 -4
- package/lib/tree/create-elements-tree.js +8 -5
- package/lib/tree/root.js +14 -4
- package/lib/tree/webstudio-component.js +27 -11
- package/lib/types/app/root.d.ts +1 -2
- package/lib/types/component-renderer.d.ts +8 -0
- package/lib/types/components/component-meta.d.ts +14 -8
- package/lib/types/context.d.ts +3 -1
- package/lib/types/css/css.d.ts +19 -19
- package/lib/types/css/global-rules.d.ts +19 -19
- package/lib/types/css/index.d.ts +0 -1
- package/lib/types/css/normalize.d.ts +47 -47
- package/lib/types/embed-template.d.ts +297 -174
- package/lib/types/expression.d.ts +3 -2
- package/lib/types/hook.d.ts +31 -0
- package/lib/types/index.d.ts +5 -2
- package/lib/types/instance-utils.d.ts +16 -0
- package/lib/types/instance-utils.test.d.ts +1 -0
- package/lib/types/props.d.ts +48 -46
- package/lib/types/tree/create-elements-tree.d.ts +9 -6
- package/lib/types/tree/root.d.ts +8 -5
- package/lib/types/tree/webstudio-component.d.ts +16 -7
- package/package.json +18 -19
- package/src/component-renderer.tsx +117 -0
- package/src/components/component-meta.ts +10 -0
- package/src/context.tsx +4 -0
- package/src/css/index.ts +0 -1
- package/src/css/style-rules.ts +1 -1
- package/src/embed-template.test.ts +113 -26
- package/src/embed-template.ts +149 -56
- package/src/expression.test.ts +74 -6
- package/src/expression.ts +55 -2
- package/src/hook.ts +42 -0
- package/src/index.ts +5 -0
- package/src/instance-utils.test.ts +89 -0
- package/src/instance-utils.ts +65 -0
- package/src/props.ts +19 -2
- package/src/tree/create-elements-tree.tsx +25 -8
- package/src/tree/root.ts +22 -3
- package/src/tree/webstudio-component.tsx +42 -14
- package/lib/cjs/css/get-browser-style.js +0 -83
- package/lib/css/get-browser-style.js +0 -65
- package/lib/types/css/get-browser-style.d.ts +0 -2
- package/src/css/get-browser-style.ts +0 -81
package/lib/cjs/props.js
CHANGED
|
@@ -18,6 +18,7 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
var props_exports = {};
|
|
20
20
|
__export(props_exports, {
|
|
21
|
+
getIndexWithinAncestorFromComponentProps: () => getIndexWithinAncestorFromComponentProps,
|
|
21
22
|
getInstanceIdFromComponentProps: () => getInstanceIdFromComponentProps,
|
|
22
23
|
getPropsByInstanceId: () => getPropsByInstanceId,
|
|
23
24
|
resolveUrlProp: () => resolveUrlProp,
|
|
@@ -49,13 +50,18 @@ const useInstanceProps = (instanceId) => {
|
|
|
49
50
|
dataSourceValuesStore,
|
|
50
51
|
executeEffectfulExpression,
|
|
51
52
|
setDataSourceValues,
|
|
52
|
-
renderer
|
|
53
|
+
renderer,
|
|
54
|
+
indexesWithinAncestors
|
|
53
55
|
} = (0, import_react.useContext)(import_context.ReactSdkContext);
|
|
56
|
+
const index = indexesWithinAncestors.get(instanceId);
|
|
54
57
|
const instancePropsObjectStore = (0, import_react.useMemo)(() => {
|
|
55
58
|
return (0, import_nanostores.computed)(
|
|
56
59
|
[propsByInstanceIdStore, dataSourceValuesStore],
|
|
57
60
|
(propsByInstanceId, dataSourceValues) => {
|
|
58
61
|
const instancePropsObject2 = {};
|
|
62
|
+
if (index !== void 0) {
|
|
63
|
+
instancePropsObject2[import_webstudio_component.indexAttribute] = index.toString();
|
|
64
|
+
}
|
|
59
65
|
const instanceProps = propsByInstanceId.get(instanceId);
|
|
60
66
|
if (instanceProps === void 0) {
|
|
61
67
|
return instancePropsObject2;
|
|
@@ -73,14 +79,19 @@ const useInstanceProps = (instanceId) => {
|
|
|
73
79
|
continue;
|
|
74
80
|
}
|
|
75
81
|
if (prop.type === "action") {
|
|
76
|
-
instancePropsObject2[prop.name] = () => {
|
|
82
|
+
instancePropsObject2[prop.name] = (...args) => {
|
|
77
83
|
if (renderer === "canvas") {
|
|
78
84
|
return;
|
|
79
85
|
}
|
|
80
86
|
for (const value of prop.value) {
|
|
81
87
|
if (value.type === "execute") {
|
|
88
|
+
const argsMap = /* @__PURE__ */ new Map();
|
|
89
|
+
for (const [i, name] of value.args.entries()) {
|
|
90
|
+
argsMap.set(name, args[i]);
|
|
91
|
+
}
|
|
82
92
|
const newValues = executeEffectfulExpression(
|
|
83
93
|
value.code,
|
|
94
|
+
argsMap,
|
|
84
95
|
dataSourceValues
|
|
85
96
|
);
|
|
86
97
|
setDataSourceValues(newValues);
|
|
@@ -100,7 +111,8 @@ const useInstanceProps = (instanceId) => {
|
|
|
100
111
|
instanceId,
|
|
101
112
|
renderer,
|
|
102
113
|
executeEffectfulExpression,
|
|
103
|
-
setDataSourceValues
|
|
114
|
+
setDataSourceValues,
|
|
115
|
+
index
|
|
104
116
|
]);
|
|
105
117
|
const instancePropsObject = (0, import_react2.useStore)(instancePropsObjectStore);
|
|
106
118
|
return instancePropsObject;
|
|
@@ -187,3 +199,6 @@ const usePropUrl = (instanceId, name) => {
|
|
|
187
199
|
const getInstanceIdFromComponentProps = (props) => {
|
|
188
200
|
return props[import_webstudio_component.idAttribute];
|
|
189
201
|
};
|
|
202
|
+
const getIndexWithinAncestorFromComponentProps = (props) => {
|
|
203
|
+
return props[import_webstudio_component.indexAttribute];
|
|
204
|
+
};
|
|
@@ -23,7 +23,6 @@ __export(create_elements_tree_exports, {
|
|
|
23
23
|
module.exports = __toCommonJS(create_elements_tree_exports);
|
|
24
24
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
25
25
|
var import_react = require("react");
|
|
26
|
-
var import_react2 = require("@remix-run/react");
|
|
27
26
|
var import_context = require("../context");
|
|
28
27
|
const createElementsTree = ({
|
|
29
28
|
renderer,
|
|
@@ -37,8 +36,10 @@ const createElementsTree = ({
|
|
|
37
36
|
dataSourceValuesStore,
|
|
38
37
|
executeEffectfulExpression,
|
|
39
38
|
onDataSourceUpdate,
|
|
39
|
+
indexesWithinAncestors,
|
|
40
40
|
Component,
|
|
41
|
-
components
|
|
41
|
+
components,
|
|
42
|
+
scripts
|
|
42
43
|
}) => {
|
|
43
44
|
const rootInstance = instances.get(rootInstanceId);
|
|
44
45
|
if (rootInstance === void 0) {
|
|
@@ -59,8 +60,7 @@ const createElementsTree = ({
|
|
|
59
60
|
children: [
|
|
60
61
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react.Fragment, { children: [
|
|
61
62
|
children,
|
|
62
|
-
|
|
63
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react2.Scripts, {})
|
|
63
|
+
scripts
|
|
64
64
|
] }, "children")
|
|
65
65
|
],
|
|
66
66
|
components
|
|
@@ -76,6 +76,7 @@ const createElementsTree = ({
|
|
|
76
76
|
renderer,
|
|
77
77
|
imageBaseUrl,
|
|
78
78
|
assetBaseUrl,
|
|
79
|
+
indexesWithinAncestors,
|
|
79
80
|
executeEffectfulExpression,
|
|
80
81
|
setDataSourceValues: onDataSourceUpdate,
|
|
81
82
|
setBoundDataSourceValue: (instanceId, propName, value) => {
|
package/lib/cjs/tree/root.js
CHANGED
|
@@ -23,15 +23,18 @@ __export(root_exports, {
|
|
|
23
23
|
module.exports = __toCommonJS(root_exports);
|
|
24
24
|
var import_react = require("react");
|
|
25
25
|
var import_nanostores = require("nanostores");
|
|
26
|
+
var import_project_build = require("@webstudio-is/project-build");
|
|
26
27
|
var import_create_elements_tree = require("./create-elements-tree");
|
|
27
28
|
var import_webstudio_component = require("./webstudio-component");
|
|
28
29
|
var import_props = require("../props");
|
|
29
30
|
const InstanceRoot = ({
|
|
30
31
|
data,
|
|
32
|
+
indexesWithinAncestors,
|
|
31
33
|
executeComputingExpressions,
|
|
32
34
|
executeEffectfulExpression,
|
|
33
35
|
Component,
|
|
34
|
-
components
|
|
36
|
+
components,
|
|
37
|
+
scripts
|
|
35
38
|
}) => {
|
|
36
39
|
const dataSourceVariablesStoreRef = (0, import_react.useRef)(void 0);
|
|
37
40
|
if (dataSourceVariablesStoreRef.current === void 0) {
|
|
@@ -83,10 +86,12 @@ const InstanceRoot = ({
|
|
|
83
86
|
),
|
|
84
87
|
assetsStore: (0, import_nanostores.atom)(new Map(data.assets.map((asset) => [asset.id, asset]))),
|
|
85
88
|
pagesStore: (0, import_nanostores.atom)(new Map(data.pages.map((page) => [page.id, page]))),
|
|
89
|
+
indexesWithinAncestors,
|
|
86
90
|
executeEffectfulExpression,
|
|
87
91
|
dataSourceValuesStore,
|
|
88
92
|
onDataSourceUpdate,
|
|
89
93
|
Component: Component ?? import_webstudio_component.WebstudioComponent,
|
|
90
|
-
components
|
|
94
|
+
components,
|
|
95
|
+
scripts
|
|
91
96
|
});
|
|
92
97
|
};
|
|
@@ -22,8 +22,11 @@ __export(webstudio_component_exports, {
|
|
|
22
22
|
collapsedAttribute: () => collapsedAttribute,
|
|
23
23
|
componentAttribute: () => componentAttribute,
|
|
24
24
|
idAttribute: () => idAttribute,
|
|
25
|
+
indexAttribute: () => indexAttribute,
|
|
25
26
|
renderWebstudioComponentChildren: () => renderWebstudioComponentChildren,
|
|
26
|
-
|
|
27
|
+
selectorIdAttribute: () => selectorIdAttribute,
|
|
28
|
+
showAttribute: () => showAttribute,
|
|
29
|
+
splitPropsWithWebstudioAttributes: () => splitPropsWithWebstudioAttributes
|
|
27
30
|
});
|
|
28
31
|
module.exports = __toCommonJS(webstudio_component_exports);
|
|
29
32
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
@@ -44,13 +47,7 @@ const renderWebstudioComponentChildren = (children) => {
|
|
|
44
47
|
return typeof child === "string" ? renderText(child) : child;
|
|
45
48
|
});
|
|
46
49
|
};
|
|
47
|
-
const WebstudioComponent = ({
|
|
48
|
-
instance,
|
|
49
|
-
instanceSelector,
|
|
50
|
-
children,
|
|
51
|
-
components,
|
|
52
|
-
...rest
|
|
53
|
-
}) => {
|
|
50
|
+
const WebstudioComponent = (0, import_react.forwardRef)(({ instance, instanceSelector, children, components, ...rest }, ref) => {
|
|
54
51
|
const { [showAttribute]: show = true, ...instanceProps } = (0, import_props.useInstanceProps)(
|
|
55
52
|
instance.id
|
|
56
53
|
);
|
|
@@ -67,9 +64,28 @@ const WebstudioComponent = ({
|
|
|
67
64
|
if (Component === void 0) {
|
|
68
65
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, {});
|
|
69
66
|
}
|
|
70
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Component, { ...props, children: renderWebstudioComponentChildren(children) });
|
|
71
|
-
};
|
|
67
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Component, { ...props, ref, children: renderWebstudioComponentChildren(children) });
|
|
68
|
+
});
|
|
72
69
|
const idAttribute = "data-ws-id";
|
|
70
|
+
const selectorIdAttribute = "data-ws-selector";
|
|
73
71
|
const componentAttribute = "data-ws-component";
|
|
74
72
|
const showAttribute = "data-ws-show";
|
|
73
|
+
const indexAttribute = "data-ws-index";
|
|
75
74
|
const collapsedAttribute = "data-ws-collapsed";
|
|
75
|
+
const splitPropsWithWebstudioAttributes = ({
|
|
76
|
+
[idAttribute]: idAttributeValue,
|
|
77
|
+
[componentAttribute]: componentAttributeValue,
|
|
78
|
+
[showAttribute]: showAttributeValue,
|
|
79
|
+
[collapsedAttribute]: collapsedAttributeValue,
|
|
80
|
+
[selectorIdAttribute]: parentIdAttributeValue,
|
|
81
|
+
...props
|
|
82
|
+
}) => [
|
|
83
|
+
{
|
|
84
|
+
[idAttribute]: idAttributeValue,
|
|
85
|
+
[componentAttribute]: componentAttributeValue,
|
|
86
|
+
[showAttribute]: showAttributeValue,
|
|
87
|
+
[collapsedAttribute]: collapsedAttributeValue,
|
|
88
|
+
[selectorIdAttribute]: parentIdAttributeValue
|
|
89
|
+
},
|
|
90
|
+
props
|
|
91
|
+
];
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { getStyleDeclKey } from "@webstudio-is/project-build";
|
|
3
|
+
import { generateDataFromEmbedTemplate } from "./embed-template";
|
|
4
|
+
import { generateCssText } from "./css";
|
|
5
|
+
import { InstanceRoot, WebstudioComponent } from "./tree";
|
|
6
|
+
import {
|
|
7
|
+
decodeVariablesMap,
|
|
8
|
+
encodeDataSourceVariable,
|
|
9
|
+
encodeVariablesMap,
|
|
10
|
+
executeComputingExpressions,
|
|
11
|
+
executeEffectfulExpression
|
|
12
|
+
} from "./expression";
|
|
13
|
+
import { getIndexesWithinAncestors } from "./instance-utils";
|
|
14
|
+
const renderComponentTemplate = ({
|
|
15
|
+
name,
|
|
16
|
+
metas: metasRecord,
|
|
17
|
+
components
|
|
18
|
+
}) => {
|
|
19
|
+
const metas = new Map(Object.entries(metasRecord));
|
|
20
|
+
const data = generateDataFromEmbedTemplate(
|
|
21
|
+
metas.get(name)?.template ?? [
|
|
22
|
+
{
|
|
23
|
+
type: "instance",
|
|
24
|
+
component: name,
|
|
25
|
+
children: []
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"base"
|
|
29
|
+
);
|
|
30
|
+
const instances = [
|
|
31
|
+
[
|
|
32
|
+
"root",
|
|
33
|
+
{
|
|
34
|
+
type: "instance",
|
|
35
|
+
id: "root",
|
|
36
|
+
component: "Box",
|
|
37
|
+
children: data.children
|
|
38
|
+
}
|
|
39
|
+
],
|
|
40
|
+
...data.instances.map(
|
|
41
|
+
(instance) => [instance.id, instance]
|
|
42
|
+
)
|
|
43
|
+
];
|
|
44
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
45
|
+
/* @__PURE__ */ jsx("style", { children: generateCssText(
|
|
46
|
+
{
|
|
47
|
+
assets: [],
|
|
48
|
+
breakpoints: [["base", { id: "base", label: "base" }]],
|
|
49
|
+
styles: data.styles.map((item) => [getStyleDeclKey(item), item]),
|
|
50
|
+
styleSourceSelections: data.styleSourceSelections.map((item) => [
|
|
51
|
+
item.instanceId,
|
|
52
|
+
item
|
|
53
|
+
]),
|
|
54
|
+
componentMetas: metas
|
|
55
|
+
},
|
|
56
|
+
{ assetBaseUrl: "/" }
|
|
57
|
+
) }),
|
|
58
|
+
/* @__PURE__ */ jsx(
|
|
59
|
+
InstanceRoot,
|
|
60
|
+
{
|
|
61
|
+
data: {
|
|
62
|
+
page: {
|
|
63
|
+
path: "",
|
|
64
|
+
id: "",
|
|
65
|
+
name: "",
|
|
66
|
+
title: "",
|
|
67
|
+
meta: {},
|
|
68
|
+
rootInstanceId: "root"
|
|
69
|
+
},
|
|
70
|
+
pages: [],
|
|
71
|
+
assets: [],
|
|
72
|
+
build: {
|
|
73
|
+
instances,
|
|
74
|
+
props: data.props.map((prop) => [prop.id, prop]),
|
|
75
|
+
dataSources: data.dataSources.map((dataSource) => [
|
|
76
|
+
dataSource.id,
|
|
77
|
+
dataSource
|
|
78
|
+
])
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
executeComputingExpressions: (values) => {
|
|
82
|
+
const expressions = /* @__PURE__ */ new Map();
|
|
83
|
+
for (const dataSource of data.dataSources) {
|
|
84
|
+
const name2 = encodeDataSourceVariable(dataSource.id);
|
|
85
|
+
if (dataSource.type === "expression") {
|
|
86
|
+
expressions.set(name2, dataSource.code);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return decodeVariablesMap(
|
|
90
|
+
executeComputingExpressions(expressions, encodeVariablesMap(values))
|
|
91
|
+
);
|
|
92
|
+
},
|
|
93
|
+
executeEffectfulExpression: (code, args, values) => {
|
|
94
|
+
return decodeVariablesMap(
|
|
95
|
+
executeEffectfulExpression(code, args, encodeVariablesMap(values))
|
|
96
|
+
);
|
|
97
|
+
},
|
|
98
|
+
Component: WebstudioComponent,
|
|
99
|
+
components: new Map(Object.entries(components)),
|
|
100
|
+
indexesWithinAncestors: getIndexesWithinAncestors(
|
|
101
|
+
metas,
|
|
102
|
+
new Map(instances),
|
|
103
|
+
["root"]
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
)
|
|
107
|
+
] });
|
|
108
|
+
};
|
|
109
|
+
export {
|
|
110
|
+
renderComponentTemplate
|
|
111
|
+
};
|
|
@@ -11,6 +11,7 @@ const componentCategories = [
|
|
|
11
11
|
"text",
|
|
12
12
|
"media",
|
|
13
13
|
"forms",
|
|
14
|
+
"radix",
|
|
14
15
|
"hidden"
|
|
15
16
|
];
|
|
16
17
|
const stateCategories = ["states", "component-states"];
|
|
@@ -35,7 +36,16 @@ const WsComponentMeta = z.object({
|
|
|
35
36
|
type: z.enum(["container", "control", "embed", "rich-text-child"]),
|
|
36
37
|
requiredAncestors: z.optional(z.array(z.string())),
|
|
37
38
|
invalidAncestors: z.optional(z.array(z.string())),
|
|
39
|
+
// when this field is specified component receives
|
|
40
|
+
// prop with index of same components withiin specified ancestor
|
|
41
|
+
// important to automatically enumerate collections without
|
|
42
|
+
// naming every item manually
|
|
43
|
+
indexWithinAncestor: z.optional(z.string()),
|
|
38
44
|
stylable: z.optional(z.boolean()),
|
|
45
|
+
// specifies whether the instance can be deleted,
|
|
46
|
+
// copied or dragged out of its parent instance
|
|
47
|
+
// true by default
|
|
48
|
+
detachable: z.optional(z.boolean()),
|
|
39
49
|
label: z.string(),
|
|
40
50
|
description: z.string().optional(),
|
|
41
51
|
icon: z.string(),
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import { componentAttribute, idAttribute } from "../tree";
|
package/lib/context.js
CHANGED
package/lib/css/index.js
CHANGED
package/lib/css/style-rules.js
CHANGED
|
@@ -49,7 +49,7 @@ const getPresetStyleRules = (component, presetStyle) => {
|
|
|
49
49
|
const presetStyleRules = /* @__PURE__ */ new Map();
|
|
50
50
|
for (const [tag, styles] of Object.entries(presetStyle)) {
|
|
51
51
|
for (const styleDecl of styles) {
|
|
52
|
-
const selector = `${tag}:where([${componentAttribute}
|
|
52
|
+
const selector = `${tag}:where([${componentAttribute}="${component}"])${styleDecl.state ?? ""}`;
|
|
53
53
|
let rule = presetStyleRules.get(selector);
|
|
54
54
|
if (rule === void 0) {
|
|
55
55
|
rule = {};
|
package/lib/embed-template.js
CHANGED
|
@@ -1,46 +1,59 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { nanoid } from "nanoid";
|
|
3
|
+
import {
|
|
4
|
+
Instance,
|
|
5
|
+
PropsList,
|
|
6
|
+
StyleSourceSelectionsList,
|
|
7
|
+
StyleSourcesList,
|
|
8
|
+
StylesList,
|
|
9
|
+
Breakpoint,
|
|
10
|
+
DataSource
|
|
11
|
+
} from "@webstudio-is/project-build";
|
|
3
12
|
import { StyleValue } from "@webstudio-is/css-data";
|
|
4
13
|
import { encodeDataSourceVariable, validateExpression } from "./expression";
|
|
5
14
|
const EmbedTemplateText = z.object({
|
|
6
15
|
type: z.literal("text"),
|
|
7
16
|
value: z.string()
|
|
8
17
|
});
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
18
|
+
const EmbedTemplateDataSource = z.union([
|
|
19
|
+
z.object({
|
|
20
|
+
type: z.literal("variable"),
|
|
21
|
+
initialValue: z.union([
|
|
22
|
+
z.string(),
|
|
23
|
+
z.number(),
|
|
24
|
+
z.boolean(),
|
|
25
|
+
z.array(z.string())
|
|
26
|
+
])
|
|
27
|
+
}),
|
|
15
28
|
z.object({
|
|
16
29
|
type: z.literal("expression"),
|
|
17
|
-
name: z.string(),
|
|
18
30
|
code: z.string()
|
|
19
31
|
})
|
|
20
32
|
]);
|
|
21
33
|
const EmbedTemplateProp = z.union([
|
|
34
|
+
z.object({
|
|
35
|
+
type: z.literal("dataSource"),
|
|
36
|
+
name: z.string(),
|
|
37
|
+
dataSourceName: z.string()
|
|
38
|
+
}),
|
|
22
39
|
z.object({
|
|
23
40
|
type: z.literal("number"),
|
|
24
41
|
name: z.string(),
|
|
25
|
-
dataSourceRef: z.optional(DataSourceRef),
|
|
26
42
|
value: z.number()
|
|
27
43
|
}),
|
|
28
44
|
z.object({
|
|
29
45
|
type: z.literal("string"),
|
|
30
46
|
name: z.string(),
|
|
31
|
-
dataSourceRef: z.optional(DataSourceRef),
|
|
32
47
|
value: z.string()
|
|
33
48
|
}),
|
|
34
49
|
z.object({
|
|
35
50
|
type: z.literal("boolean"),
|
|
36
51
|
name: z.string(),
|
|
37
|
-
dataSourceRef: z.optional(DataSourceRef),
|
|
38
52
|
value: z.boolean()
|
|
39
53
|
}),
|
|
40
54
|
z.object({
|
|
41
55
|
type: z.literal("string[]"),
|
|
42
56
|
name: z.string(),
|
|
43
|
-
dataSourceRef: z.optional(DataSourceRef),
|
|
44
57
|
value: z.array(z.string())
|
|
45
58
|
}),
|
|
46
59
|
z.object({
|
|
@@ -49,6 +62,7 @@ const EmbedTemplateProp = z.union([
|
|
|
49
62
|
value: z.array(
|
|
50
63
|
z.object({
|
|
51
64
|
type: z.literal("execute"),
|
|
65
|
+
args: z.optional(z.array(z.string())),
|
|
52
66
|
code: z.string()
|
|
53
67
|
})
|
|
54
68
|
)
|
|
@@ -66,6 +80,7 @@ const EmbedTemplateInstance = z.lazy(
|
|
|
66
80
|
type: z.literal("instance"),
|
|
67
81
|
component: z.string(),
|
|
68
82
|
label: z.optional(z.string()),
|
|
83
|
+
dataSources: z.optional(z.record(z.string(), EmbedTemplateDataSource)),
|
|
69
84
|
props: z.optional(z.array(EmbedTemplateProp)),
|
|
70
85
|
styles: z.optional(z.array(EmbedTemplateStyleDecl)),
|
|
71
86
|
children: WsEmbedTemplate
|
|
@@ -74,11 +89,58 @@ const EmbedTemplateInstance = z.lazy(
|
|
|
74
89
|
const WsEmbedTemplate = z.lazy(
|
|
75
90
|
() => z.array(z.union([EmbedTemplateInstance, EmbedTemplateText]))
|
|
76
91
|
);
|
|
92
|
+
const getDataSourceValue = (value) => {
|
|
93
|
+
if (typeof value === "string") {
|
|
94
|
+
return { type: "string", value };
|
|
95
|
+
}
|
|
96
|
+
if (typeof value === "number") {
|
|
97
|
+
return { type: "number", value };
|
|
98
|
+
}
|
|
99
|
+
if (typeof value === "boolean") {
|
|
100
|
+
return { type: "boolean", value };
|
|
101
|
+
}
|
|
102
|
+
if (Array.isArray(value)) {
|
|
103
|
+
return { type: "string[]", value };
|
|
104
|
+
}
|
|
105
|
+
value;
|
|
106
|
+
throw Error("Impossible case");
|
|
107
|
+
};
|
|
77
108
|
const createInstancesFromTemplate = (treeTemplate, instances, props, dataSourceByRef, styleSourceSelections, styleSources, styles, defaultBreakpointId) => {
|
|
78
109
|
const parentChildren = [];
|
|
79
110
|
for (const item of treeTemplate) {
|
|
80
111
|
if (item.type === "instance") {
|
|
81
112
|
const instanceId = nanoid();
|
|
113
|
+
if (item.dataSources) {
|
|
114
|
+
for (const [name, dataSource] of Object.entries(item.dataSources)) {
|
|
115
|
+
if (dataSourceByRef.has(name)) {
|
|
116
|
+
throw Error(`${name} data source already defined`);
|
|
117
|
+
}
|
|
118
|
+
if (dataSource.type === "variable") {
|
|
119
|
+
dataSourceByRef.set(name, {
|
|
120
|
+
type: "variable",
|
|
121
|
+
id: nanoid(),
|
|
122
|
+
scopeInstanceId: instanceId,
|
|
123
|
+
name,
|
|
124
|
+
value: getDataSourceValue(dataSource.initialValue)
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
if (dataSource.type === "expression") {
|
|
128
|
+
dataSourceByRef.set(name, {
|
|
129
|
+
type: "expression",
|
|
130
|
+
id: nanoid(),
|
|
131
|
+
scopeInstanceId: instanceId,
|
|
132
|
+
name,
|
|
133
|
+
// replace all references with variable names
|
|
134
|
+
code: validateExpression(dataSource.code, {
|
|
135
|
+
transformIdentifier: (ref) => {
|
|
136
|
+
const id = dataSourceByRef.get(ref)?.id ?? ref;
|
|
137
|
+
return encodeDataSourceVariable(id);
|
|
138
|
+
}
|
|
139
|
+
})
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
82
144
|
if (item.props) {
|
|
83
145
|
for (const prop of item.props) {
|
|
84
146
|
const propId = nanoid();
|
|
@@ -89,12 +151,17 @@ const createInstancesFromTemplate = (treeTemplate, instances, props, dataSourceB
|
|
|
89
151
|
type: "action",
|
|
90
152
|
name: prop.name,
|
|
91
153
|
value: prop.value.map((value) => {
|
|
154
|
+
const args = value.args ?? [];
|
|
92
155
|
return {
|
|
93
156
|
type: "execute",
|
|
157
|
+
args,
|
|
94
158
|
// replace all references with variable names
|
|
95
159
|
code: validateExpression(value.code, {
|
|
96
160
|
effectful: true,
|
|
97
161
|
transformIdentifier: (ref) => {
|
|
162
|
+
if (args.includes(ref)) {
|
|
163
|
+
return ref;
|
|
164
|
+
}
|
|
98
165
|
const id = dataSourceByRef.get(ref)?.id ?? ref;
|
|
99
166
|
return encodeDataSourceVariable(id);
|
|
100
167
|
}
|
|
@@ -104,51 +171,21 @@ const createInstancesFromTemplate = (treeTemplate, instances, props, dataSourceB
|
|
|
104
171
|
});
|
|
105
172
|
continue;
|
|
106
173
|
}
|
|
107
|
-
if (prop.
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
let dataSource = dataSourceByRef.get(prop.dataSourceRef.name);
|
|
112
|
-
if (dataSource === void 0) {
|
|
113
|
-
const id = nanoid();
|
|
114
|
-
const { name: propName, dataSourceRef, ...rest } = prop;
|
|
115
|
-
if (dataSourceRef.type === "variable") {
|
|
116
|
-
dataSource = {
|
|
117
|
-
type: "variable",
|
|
118
|
-
id,
|
|
119
|
-
// the first instance where data source is appeared in becomes its scope
|
|
120
|
-
scopeInstanceId: instanceId,
|
|
121
|
-
name: dataSourceRef.name,
|
|
122
|
-
value: rest
|
|
123
|
-
};
|
|
124
|
-
dataSourceByRef.set(dataSourceRef.name, dataSource);
|
|
125
|
-
} else if (dataSourceRef.type === "expression") {
|
|
126
|
-
dataSource = {
|
|
127
|
-
type: "expression",
|
|
128
|
-
id,
|
|
129
|
-
scopeInstanceId: instanceId,
|
|
130
|
-
name: dataSourceRef.name,
|
|
131
|
-
// replace all references with variable names
|
|
132
|
-
code: validateExpression(dataSourceRef.code, {
|
|
133
|
-
transformIdentifier: (ref) => {
|
|
134
|
-
const id2 = dataSourceByRef.get(ref)?.id ?? ref;
|
|
135
|
-
return encodeDataSourceVariable(id2);
|
|
136
|
-
}
|
|
137
|
-
})
|
|
138
|
-
};
|
|
139
|
-
dataSourceByRef.set(dataSourceRef.name, dataSource);
|
|
140
|
-
} else {
|
|
141
|
-
dataSourceRef;
|
|
142
|
-
continue;
|
|
174
|
+
if (prop.type === "dataSource") {
|
|
175
|
+
const dataSource = dataSourceByRef.get(prop.dataSourceName);
|
|
176
|
+
if (dataSource === void 0) {
|
|
177
|
+
throw Error(`${prop.dataSourceName} data source is not defined`);
|
|
143
178
|
}
|
|
179
|
+
props.push({
|
|
180
|
+
id: propId,
|
|
181
|
+
instanceId,
|
|
182
|
+
type: "dataSource",
|
|
183
|
+
name: prop.name,
|
|
184
|
+
value: dataSource.id
|
|
185
|
+
});
|
|
186
|
+
continue;
|
|
144
187
|
}
|
|
145
|
-
props.push({
|
|
146
|
-
id: propId,
|
|
147
|
-
instanceId,
|
|
148
|
-
type: "dataSource",
|
|
149
|
-
name: prop.name,
|
|
150
|
-
value: dataSource.id
|
|
151
|
-
});
|
|
188
|
+
props.push({ id: propId, instanceId, ...prop });
|
|
152
189
|
}
|
|
153
190
|
}
|
|
154
191
|
if (item.styles) {
|
|
@@ -230,9 +267,55 @@ const generateDataFromEmbedTemplate = (treeTemplate, defaultBreakpointId) => {
|
|
|
230
267
|
styles
|
|
231
268
|
};
|
|
232
269
|
};
|
|
270
|
+
const namespaceEmbedTemplateComponents = (template, namespace, components) => {
|
|
271
|
+
return template.map((item) => {
|
|
272
|
+
if (item.type === "text") {
|
|
273
|
+
return item;
|
|
274
|
+
}
|
|
275
|
+
if (item.type === "instance") {
|
|
276
|
+
const prefix = components.has(item.component) ? `${namespace}:` : "";
|
|
277
|
+
return {
|
|
278
|
+
...item,
|
|
279
|
+
component: `${prefix}${item.component}`,
|
|
280
|
+
children: namespaceEmbedTemplateComponents(
|
|
281
|
+
item.children,
|
|
282
|
+
namespace,
|
|
283
|
+
components
|
|
284
|
+
)
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
item;
|
|
288
|
+
throw Error("Impossible case");
|
|
289
|
+
});
|
|
290
|
+
};
|
|
291
|
+
const namespaceMeta = (meta, namespace, components) => {
|
|
292
|
+
const newMeta = { ...meta };
|
|
293
|
+
if (newMeta.requiredAncestors) {
|
|
294
|
+
newMeta.requiredAncestors = newMeta.requiredAncestors.map(
|
|
295
|
+
(component) => components.has(component) ? `${namespace}:${component}` : component
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
if (newMeta.invalidAncestors) {
|
|
299
|
+
newMeta.invalidAncestors = newMeta.invalidAncestors.map(
|
|
300
|
+
(component) => components.has(component) ? `${namespace}:${component}` : component
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
if (newMeta.indexWithinAncestor) {
|
|
304
|
+
newMeta.indexWithinAncestor = components.has(newMeta.indexWithinAncestor) ? `${namespace}:${newMeta.indexWithinAncestor}` : newMeta.indexWithinAncestor;
|
|
305
|
+
}
|
|
306
|
+
if (newMeta.template) {
|
|
307
|
+
newMeta.template = namespaceEmbedTemplateComponents(
|
|
308
|
+
newMeta.template,
|
|
309
|
+
namespace,
|
|
310
|
+
components
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
return newMeta;
|
|
314
|
+
};
|
|
233
315
|
export {
|
|
234
316
|
EmbedTemplateInstance,
|
|
235
317
|
EmbedTemplateStyleDecl,
|
|
236
318
|
WsEmbedTemplate,
|
|
237
|
-
generateDataFromEmbedTemplate
|
|
319
|
+
generateDataFromEmbedTemplate,
|
|
320
|
+
namespaceMeta
|
|
238
321
|
};
|