@webstudio-is/react-sdk 0.83.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/lib/cjs/component-renderer.js +125 -0
- package/lib/cjs/components/component-meta.js +5 -0
- package/lib/cjs/context.js +2 -1
- package/lib/cjs/css/style-rules.js +1 -1
- package/lib/cjs/embed-template.js +101 -55
- package/lib/cjs/hook.js +34 -0
- package/lib/cjs/index.js +6 -0
- package/lib/cjs/instance-utils.js +65 -0
- package/lib/cjs/props.js +12 -2
- package/lib/cjs/tree/create-elements-tree.js +5 -4
- package/lib/cjs/tree/root.js +6 -2
- package/lib/cjs/tree/webstudio-component.js +2 -0
- package/lib/component-renderer.js +111 -0
- package/lib/components/component-meta.js +5 -0
- package/lib/context.js +2 -1
- package/lib/css/style-rules.js +1 -1
- package/lib/embed-template.js +101 -55
- package/lib/hook.js +14 -0
- package/lib/index.js +8 -1
- package/lib/instance-utils.js +45 -0
- package/lib/props.js +13 -3
- package/lib/tree/create-elements-tree.js +5 -4
- package/lib/tree/root.js +6 -2
- package/lib/tree/webstudio-component.js +2 -0
- package/lib/types/component-renderer.d.ts +8 -0
- package/lib/types/components/component-meta.d.ts +9 -6
- package/lib/types/context.d.ts +2 -0
- package/lib/types/css/css.d.ts +19 -19
- package/lib/types/css/global-rules.d.ts +19 -19
- package/lib/types/css/normalize.d.ts +47 -47
- package/lib/types/embed-template.d.ts +291 -181
- package/lib/types/hook.d.ts +31 -0
- package/lib/types/index.d.ts +4 -1
- 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 +47 -46
- package/lib/types/tree/create-elements-tree.d.ts +5 -2
- package/lib/types/tree/root.d.ts +5 -2
- package/lib/types/tree/webstudio-component.d.ts +1 -0
- package/package.json +11 -11
- package/src/component-renderer.tsx +117 -0
- package/src/components/component-meta.ts +5 -0
- package/src/context.tsx +3 -0
- package/src/css/style-rules.ts +1 -1
- package/src/embed-template.test.ts +81 -70
- package/src/embed-template.ts +116 -56
- package/src/hook.ts +42 -0
- package/src/index.ts +4 -0
- package/src/instance-utils.test.ts +89 -0
- package/src/instance-utils.ts +65 -0
- package/src/props.ts +13 -1
- package/src/tree/create-elements-tree.tsx +8 -3
- package/src/tree/root.ts +8 -0
- package/src/tree/webstudio-component.tsx +1 -0
|
@@ -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
|
+
};
|
|
@@ -36,6 +36,11 @@ const WsComponentMeta = z.object({
|
|
|
36
36
|
type: z.enum(["container", "control", "embed", "rich-text-child"]),
|
|
37
37
|
requiredAncestors: z.optional(z.array(z.string())),
|
|
38
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()),
|
|
39
44
|
stylable: z.optional(z.boolean()),
|
|
40
45
|
// specifies whether the instance can be deleted,
|
|
41
46
|
// copied or dragged out of its parent instance
|
package/lib/context.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
|
@@ -15,41 +15,45 @@ const EmbedTemplateText = z.object({
|
|
|
15
15
|
type: z.literal("text"),
|
|
16
16
|
value: z.string()
|
|
17
17
|
});
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
+
}),
|
|
24
28
|
z.object({
|
|
25
29
|
type: z.literal("expression"),
|
|
26
|
-
name: z.string(),
|
|
27
30
|
code: z.string()
|
|
28
31
|
})
|
|
29
32
|
]);
|
|
30
33
|
const EmbedTemplateProp = z.union([
|
|
34
|
+
z.object({
|
|
35
|
+
type: z.literal("dataSource"),
|
|
36
|
+
name: z.string(),
|
|
37
|
+
dataSourceName: z.string()
|
|
38
|
+
}),
|
|
31
39
|
z.object({
|
|
32
40
|
type: z.literal("number"),
|
|
33
41
|
name: z.string(),
|
|
34
|
-
dataSourceRef: z.optional(DataSourceRef),
|
|
35
42
|
value: z.number()
|
|
36
43
|
}),
|
|
37
44
|
z.object({
|
|
38
45
|
type: z.literal("string"),
|
|
39
46
|
name: z.string(),
|
|
40
|
-
dataSourceRef: z.optional(DataSourceRef),
|
|
41
47
|
value: z.string()
|
|
42
48
|
}),
|
|
43
49
|
z.object({
|
|
44
50
|
type: z.literal("boolean"),
|
|
45
51
|
name: z.string(),
|
|
46
|
-
dataSourceRef: z.optional(DataSourceRef),
|
|
47
52
|
value: z.boolean()
|
|
48
53
|
}),
|
|
49
54
|
z.object({
|
|
50
55
|
type: z.literal("string[]"),
|
|
51
56
|
name: z.string(),
|
|
52
|
-
dataSourceRef: z.optional(DataSourceRef),
|
|
53
57
|
value: z.array(z.string())
|
|
54
58
|
}),
|
|
55
59
|
z.object({
|
|
@@ -76,6 +80,7 @@ const EmbedTemplateInstance = z.lazy(
|
|
|
76
80
|
type: z.literal("instance"),
|
|
77
81
|
component: z.string(),
|
|
78
82
|
label: z.optional(z.string()),
|
|
83
|
+
dataSources: z.optional(z.record(z.string(), EmbedTemplateDataSource)),
|
|
79
84
|
props: z.optional(z.array(EmbedTemplateProp)),
|
|
80
85
|
styles: z.optional(z.array(EmbedTemplateStyleDecl)),
|
|
81
86
|
children: WsEmbedTemplate
|
|
@@ -84,11 +89,58 @@ const EmbedTemplateInstance = z.lazy(
|
|
|
84
89
|
const WsEmbedTemplate = z.lazy(
|
|
85
90
|
() => z.array(z.union([EmbedTemplateInstance, EmbedTemplateText]))
|
|
86
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
|
+
};
|
|
87
108
|
const createInstancesFromTemplate = (treeTemplate, instances, props, dataSourceByRef, styleSourceSelections, styleSources, styles, defaultBreakpointId) => {
|
|
88
109
|
const parentChildren = [];
|
|
89
110
|
for (const item of treeTemplate) {
|
|
90
111
|
if (item.type === "instance") {
|
|
91
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
|
+
}
|
|
92
144
|
if (item.props) {
|
|
93
145
|
for (const prop of item.props) {
|
|
94
146
|
const propId = nanoid();
|
|
@@ -119,51 +171,21 @@ const createInstancesFromTemplate = (treeTemplate, instances, props, dataSourceB
|
|
|
119
171
|
});
|
|
120
172
|
continue;
|
|
121
173
|
}
|
|
122
|
-
if (prop.
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
let dataSource = dataSourceByRef.get(prop.dataSourceRef.name);
|
|
127
|
-
if (dataSource === void 0) {
|
|
128
|
-
const id = nanoid();
|
|
129
|
-
const { name: propName, dataSourceRef, ...rest } = prop;
|
|
130
|
-
if (dataSourceRef.type === "variable") {
|
|
131
|
-
dataSource = {
|
|
132
|
-
type: "variable",
|
|
133
|
-
id,
|
|
134
|
-
// the first instance where data source is appeared in becomes its scope
|
|
135
|
-
scopeInstanceId: instanceId,
|
|
136
|
-
name: dataSourceRef.name,
|
|
137
|
-
value: rest
|
|
138
|
-
};
|
|
139
|
-
dataSourceByRef.set(dataSourceRef.name, dataSource);
|
|
140
|
-
} else if (dataSourceRef.type === "expression") {
|
|
141
|
-
dataSource = {
|
|
142
|
-
type: "expression",
|
|
143
|
-
id,
|
|
144
|
-
scopeInstanceId: instanceId,
|
|
145
|
-
name: dataSourceRef.name,
|
|
146
|
-
// replace all references with variable names
|
|
147
|
-
code: validateExpression(dataSourceRef.code, {
|
|
148
|
-
transformIdentifier: (ref) => {
|
|
149
|
-
const id2 = dataSourceByRef.get(ref)?.id ?? ref;
|
|
150
|
-
return encodeDataSourceVariable(id2);
|
|
151
|
-
}
|
|
152
|
-
})
|
|
153
|
-
};
|
|
154
|
-
dataSourceByRef.set(dataSourceRef.name, dataSource);
|
|
155
|
-
} else {
|
|
156
|
-
dataSourceRef;
|
|
157
|
-
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`);
|
|
158
178
|
}
|
|
179
|
+
props.push({
|
|
180
|
+
id: propId,
|
|
181
|
+
instanceId,
|
|
182
|
+
type: "dataSource",
|
|
183
|
+
name: prop.name,
|
|
184
|
+
value: dataSource.id
|
|
185
|
+
});
|
|
186
|
+
continue;
|
|
159
187
|
}
|
|
160
|
-
props.push({
|
|
161
|
-
id: propId,
|
|
162
|
-
instanceId,
|
|
163
|
-
type: "dataSource",
|
|
164
|
-
name: prop.name,
|
|
165
|
-
value: dataSource.id
|
|
166
|
-
});
|
|
188
|
+
props.push({ id: propId, instanceId, ...prop });
|
|
167
189
|
}
|
|
168
190
|
}
|
|
169
191
|
if (item.styles) {
|
|
@@ -266,10 +288,34 @@ const namespaceEmbedTemplateComponents = (template, namespace, components) => {
|
|
|
266
288
|
throw Error("Impossible case");
|
|
267
289
|
});
|
|
268
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
|
+
};
|
|
269
315
|
export {
|
|
270
316
|
EmbedTemplateInstance,
|
|
271
317
|
EmbedTemplateStyleDecl,
|
|
272
318
|
WsEmbedTemplate,
|
|
273
319
|
generateDataFromEmbedTemplate,
|
|
274
|
-
|
|
320
|
+
namespaceMeta
|
|
275
321
|
};
|
package/lib/hook.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const getClosestInstance = (instanceSelection, currentInstance, closestComponent) => {
|
|
2
|
+
let matched = false;
|
|
3
|
+
for (const instance of instanceSelection) {
|
|
4
|
+
if (currentInstance === instance) {
|
|
5
|
+
matched = true;
|
|
6
|
+
}
|
|
7
|
+
if (matched && instance.component === closestComponent) {
|
|
8
|
+
return instance;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
export {
|
|
13
|
+
getClosestInstance
|
|
14
|
+
};
|
package/lib/index.js
CHANGED
|
@@ -13,7 +13,8 @@ import {
|
|
|
13
13
|
useInstanceProps,
|
|
14
14
|
usePropUrl,
|
|
15
15
|
usePropAsset,
|
|
16
|
-
getInstanceIdFromComponentProps
|
|
16
|
+
getInstanceIdFromComponentProps,
|
|
17
|
+
getIndexWithinAncestorFromComponentProps
|
|
17
18
|
} from "./props";
|
|
18
19
|
import { ReactSdkContext } from "./context";
|
|
19
20
|
import {
|
|
@@ -28,6 +29,9 @@ import {
|
|
|
28
29
|
decodeDataSourceVariable,
|
|
29
30
|
decodeVariablesMap
|
|
30
31
|
} from "./expression";
|
|
32
|
+
import { renderComponentTemplate } from "./component-renderer";
|
|
33
|
+
import { getIndexesWithinAncestors } from "./instance-utils";
|
|
34
|
+
export * from "./hook";
|
|
31
35
|
export {
|
|
32
36
|
ReactSdkContext,
|
|
33
37
|
componentCategories,
|
|
@@ -41,7 +45,10 @@ export {
|
|
|
41
45
|
executeEffectfulExpression,
|
|
42
46
|
generateComputingExpressions,
|
|
43
47
|
generateEffectfulExpression,
|
|
48
|
+
getIndexWithinAncestorFromComponentProps,
|
|
49
|
+
getIndexesWithinAncestors,
|
|
44
50
|
getInstanceIdFromComponentProps,
|
|
51
|
+
renderComponentTemplate,
|
|
45
52
|
stateCategories,
|
|
46
53
|
useInstanceProps,
|
|
47
54
|
usePropAsset,
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
const getIndexesWithinAncestors = (metas, instances, rootIds) => {
|
|
2
|
+
const ancestors = /* @__PURE__ */ new Set();
|
|
3
|
+
for (const meta of metas.values()) {
|
|
4
|
+
if (meta.indexWithinAncestor !== void 0) {
|
|
5
|
+
ancestors.add(meta.indexWithinAncestor);
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
const indexes = /* @__PURE__ */ new Map();
|
|
9
|
+
const traverseInstances = (instances2, instanceId, latestIndexes2 = /* @__PURE__ */ new Map()) => {
|
|
10
|
+
const instance = instances2.get(instanceId);
|
|
11
|
+
if (instance === void 0) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
const meta = metas.get(instance.component);
|
|
15
|
+
if (meta === void 0) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
if (ancestors.has(instance.component)) {
|
|
19
|
+
latestIndexes2 = new Map(latestIndexes2);
|
|
20
|
+
latestIndexes2.set(instance.component, /* @__PURE__ */ new Map());
|
|
21
|
+
}
|
|
22
|
+
if (meta.indexWithinAncestor !== void 0) {
|
|
23
|
+
const ancestorIndexes = latestIndexes2.get(meta.indexWithinAncestor);
|
|
24
|
+
if (ancestorIndexes !== void 0) {
|
|
25
|
+
let index = ancestorIndexes.get(instance.component) ?? -1;
|
|
26
|
+
index += 1;
|
|
27
|
+
ancestorIndexes.set(instance.component, index);
|
|
28
|
+
indexes.set(instance.id, index);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
for (const child of instance.children) {
|
|
32
|
+
if (child.type === "id") {
|
|
33
|
+
traverseInstances(instances2, child.value, latestIndexes2);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
const latestIndexes = /* @__PURE__ */ new Map();
|
|
38
|
+
for (const instanceId of rootIds) {
|
|
39
|
+
traverseInstances(instances, instanceId, latestIndexes);
|
|
40
|
+
}
|
|
41
|
+
return indexes;
|
|
42
|
+
};
|
|
43
|
+
export {
|
|
44
|
+
getIndexesWithinAncestors
|
|
45
|
+
};
|
package/lib/props.js
CHANGED
|
@@ -2,7 +2,7 @@ import { useContext, useMemo } from "react";
|
|
|
2
2
|
import { computed } from "nanostores";
|
|
3
3
|
import { useStore } from "@nanostores/react";
|
|
4
4
|
import { ReactSdkContext } from "./context";
|
|
5
|
-
import { idAttribute } from "./tree/webstudio-component";
|
|
5
|
+
import { idAttribute, indexAttribute } from "./tree/webstudio-component";
|
|
6
6
|
const getPropsByInstanceId = (props) => {
|
|
7
7
|
const propsByInstanceId = /* @__PURE__ */ new Map();
|
|
8
8
|
for (const prop of props.values()) {
|
|
@@ -21,13 +21,18 @@ const useInstanceProps = (instanceId) => {
|
|
|
21
21
|
dataSourceValuesStore,
|
|
22
22
|
executeEffectfulExpression,
|
|
23
23
|
setDataSourceValues,
|
|
24
|
-
renderer
|
|
24
|
+
renderer,
|
|
25
|
+
indexesWithinAncestors
|
|
25
26
|
} = useContext(ReactSdkContext);
|
|
27
|
+
const index = indexesWithinAncestors.get(instanceId);
|
|
26
28
|
const instancePropsObjectStore = useMemo(() => {
|
|
27
29
|
return computed(
|
|
28
30
|
[propsByInstanceIdStore, dataSourceValuesStore],
|
|
29
31
|
(propsByInstanceId, dataSourceValues) => {
|
|
30
32
|
const instancePropsObject2 = {};
|
|
33
|
+
if (index !== void 0) {
|
|
34
|
+
instancePropsObject2[indexAttribute] = index.toString();
|
|
35
|
+
}
|
|
31
36
|
const instanceProps = propsByInstanceId.get(instanceId);
|
|
32
37
|
if (instanceProps === void 0) {
|
|
33
38
|
return instancePropsObject2;
|
|
@@ -77,7 +82,8 @@ const useInstanceProps = (instanceId) => {
|
|
|
77
82
|
instanceId,
|
|
78
83
|
renderer,
|
|
79
84
|
executeEffectfulExpression,
|
|
80
|
-
setDataSourceValues
|
|
85
|
+
setDataSourceValues,
|
|
86
|
+
index
|
|
81
87
|
]);
|
|
82
88
|
const instancePropsObject = useStore(instancePropsObjectStore);
|
|
83
89
|
return instancePropsObject;
|
|
@@ -164,7 +170,11 @@ const usePropUrl = (instanceId, name) => {
|
|
|
164
170
|
const getInstanceIdFromComponentProps = (props) => {
|
|
165
171
|
return props[idAttribute];
|
|
166
172
|
};
|
|
173
|
+
const getIndexWithinAncestorFromComponentProps = (props) => {
|
|
174
|
+
return props[indexAttribute];
|
|
175
|
+
};
|
|
167
176
|
export {
|
|
177
|
+
getIndexWithinAncestorFromComponentProps,
|
|
168
178
|
getInstanceIdFromComponentProps,
|
|
169
179
|
getPropsByInstanceId,
|
|
170
180
|
resolveUrlProp,
|
|
@@ -2,7 +2,6 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import {
|
|
3
3
|
Fragment
|
|
4
4
|
} from "react";
|
|
5
|
-
import { Scripts, ScrollRestoration } from "@remix-run/react";
|
|
6
5
|
import {
|
|
7
6
|
ReactSdkContext
|
|
8
7
|
} from "../context";
|
|
@@ -18,8 +17,10 @@ const createElementsTree = ({
|
|
|
18
17
|
dataSourceValuesStore,
|
|
19
18
|
executeEffectfulExpression,
|
|
20
19
|
onDataSourceUpdate,
|
|
20
|
+
indexesWithinAncestors,
|
|
21
21
|
Component,
|
|
22
|
-
components
|
|
22
|
+
components,
|
|
23
|
+
scripts
|
|
23
24
|
}) => {
|
|
24
25
|
const rootInstance = instances.get(rootInstanceId);
|
|
25
26
|
if (rootInstance === void 0) {
|
|
@@ -40,8 +41,7 @@ const createElementsTree = ({
|
|
|
40
41
|
children: [
|
|
41
42
|
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
42
43
|
children,
|
|
43
|
-
|
|
44
|
-
/* @__PURE__ */ jsx(Scripts, {})
|
|
44
|
+
scripts
|
|
45
45
|
] }, "children")
|
|
46
46
|
],
|
|
47
47
|
components
|
|
@@ -57,6 +57,7 @@ const createElementsTree = ({
|
|
|
57
57
|
renderer,
|
|
58
58
|
imageBaseUrl,
|
|
59
59
|
assetBaseUrl,
|
|
60
|
+
indexesWithinAncestors,
|
|
60
61
|
executeEffectfulExpression,
|
|
61
62
|
setDataSourceValues: onDataSourceUpdate,
|
|
62
63
|
setBoundDataSourceValue: (instanceId, propName, value) => {
|
package/lib/tree/root.js
CHANGED
|
@@ -14,10 +14,12 @@ import {
|
|
|
14
14
|
import { getPropsByInstanceId } from "../props";
|
|
15
15
|
const InstanceRoot = ({
|
|
16
16
|
data,
|
|
17
|
+
indexesWithinAncestors,
|
|
17
18
|
executeComputingExpressions,
|
|
18
19
|
executeEffectfulExpression,
|
|
19
20
|
Component,
|
|
20
|
-
components
|
|
21
|
+
components,
|
|
22
|
+
scripts
|
|
21
23
|
}) => {
|
|
22
24
|
const dataSourceVariablesStoreRef = useRef(void 0);
|
|
23
25
|
if (dataSourceVariablesStoreRef.current === void 0) {
|
|
@@ -69,11 +71,13 @@ const InstanceRoot = ({
|
|
|
69
71
|
),
|
|
70
72
|
assetsStore: atom(new Map(data.assets.map((asset) => [asset.id, asset]))),
|
|
71
73
|
pagesStore: atom(new Map(data.pages.map((page) => [page.id, page]))),
|
|
74
|
+
indexesWithinAncestors,
|
|
72
75
|
executeEffectfulExpression,
|
|
73
76
|
dataSourceValuesStore,
|
|
74
77
|
onDataSourceUpdate,
|
|
75
78
|
Component: Component ?? WebstudioComponent,
|
|
76
|
-
components
|
|
79
|
+
components,
|
|
80
|
+
scripts
|
|
77
81
|
});
|
|
78
82
|
};
|
|
79
83
|
export {
|
|
@@ -39,6 +39,7 @@ const idAttribute = "data-ws-id";
|
|
|
39
39
|
const selectorIdAttribute = "data-ws-selector";
|
|
40
40
|
const componentAttribute = "data-ws-component";
|
|
41
41
|
const showAttribute = "data-ws-show";
|
|
42
|
+
const indexAttribute = "data-ws-index";
|
|
42
43
|
const collapsedAttribute = "data-ws-collapsed";
|
|
43
44
|
const splitPropsWithWebstudioAttributes = ({
|
|
44
45
|
[idAttribute]: idAttributeValue,
|
|
@@ -62,6 +63,7 @@ export {
|
|
|
62
63
|
collapsedAttribute,
|
|
63
64
|
componentAttribute,
|
|
64
65
|
idAttribute,
|
|
66
|
+
indexAttribute,
|
|
65
67
|
renderWebstudioComponentChildren,
|
|
66
68
|
selectorIdAttribute,
|
|
67
69
|
showAttribute,
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ExoticComponent } from "react";
|
|
2
|
+
import type { Instance } from "@webstudio-is/project-build";
|
|
3
|
+
import type { WsComponentMeta } from "./components/component-meta";
|
|
4
|
+
export declare const renderComponentTemplate: ({ name, metas: metasRecord, components, }: {
|
|
5
|
+
name: Instance["component"];
|
|
6
|
+
metas: Record<string, WsComponentMeta>;
|
|
7
|
+
components: Record<string, ExoticComponent<any>>;
|
|
8
|
+
}) => import("react/jsx-runtime").JSX.Element;
|