@webstudio-is/react-sdk 0.91.0 → 0.93.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.
Files changed (108) hide show
  1. package/lib/app/index.js +1 -0
  2. package/lib/app/root.js +2 -4
  3. package/lib/component-renderer.js +3 -5
  4. package/lib/components/component-meta.js +6 -11
  5. package/lib/components/components-utils.js +1 -0
  6. package/lib/context.js +2 -4
  7. package/lib/css/css.js +4 -9
  8. package/lib/css/global-rules.js +3 -5
  9. package/lib/css/index.js +1 -0
  10. package/lib/css/normalize-type-check.js +1 -0
  11. package/lib/css/normalize.js +48 -96
  12. package/lib/css/presets.js +3 -6
  13. package/lib/css/style-rules.js +3 -6
  14. package/{src/css/style-rules.test.ts → lib/css/style-rules.test.js} +23 -28
  15. package/lib/embed-template.js +7 -22
  16. package/{src/embed-template.test.ts → lib/embed-template.test.js} +165 -176
  17. package/lib/expression.js +11 -22
  18. package/{src/expression.test.ts → lib/expression.test.js} +55 -83
  19. package/lib/generator.js +2 -4
  20. package/{src/generator.test.ts → lib/generator.test.js} +28 -31
  21. package/lib/hook.js +2 -4
  22. package/{src/hook.test.ts → lib/hook.test.js} +4 -4
  23. package/lib/index.js +9 -31
  24. package/lib/instance-utils.js +2 -4
  25. package/{src/instance-utils.test.ts → lib/instance-utils.test.js} +19 -43
  26. package/lib/prop-meta.js +150 -0
  27. package/lib/props.js +8 -16
  28. package/{src/props.test.ts → lib/props.test.js} +39 -68
  29. package/lib/pubsub/create.js +2 -4
  30. package/lib/pubsub/index.js +1 -0
  31. package/lib/pubsub/raf-queue.js +2 -4
  32. package/lib/tree/create-elements-tree.js +2 -4
  33. package/lib/tree/index.js +1 -0
  34. package/lib/tree/root.js +2 -5
  35. package/lib/tree/webstudio-component.js +10 -20
  36. package/lib/types/component-renderer.d.ts +1 -1
  37. package/lib/types/components/component-meta.d.ts +526 -526
  38. package/lib/types/context.d.ts +1 -2
  39. package/lib/types/css/css.d.ts +22 -23
  40. package/lib/types/css/global-rules.d.ts +19 -19
  41. package/lib/types/css/normalize.d.ts +2444 -2444
  42. package/lib/types/css/style-rules.d.ts +2 -2
  43. package/lib/types/embed-template.d.ts +648 -648
  44. package/lib/types/generator.d.ts +1 -1
  45. package/lib/types/hook.d.ts +3 -3
  46. package/lib/types/index.d.ts +1 -0
  47. package/lib/types/instance-utils.d.ts +3 -3
  48. package/lib/types/prop-meta.d.ts +396 -0
  49. package/lib/types/props.d.ts +52 -53
  50. package/lib/types/tree/create-elements-tree.d.ts +3 -4
  51. package/lib/types/tree/root.d.ts +8 -8
  52. package/lib/types/tree/webstudio-component.d.ts +1 -1
  53. package/package.json +14 -22
  54. package/lib/cjs/app/index.js +0 -18
  55. package/lib/cjs/app/root.js +0 -40
  56. package/lib/cjs/component-renderer.js +0 -143
  57. package/lib/cjs/components/component-meta.js +0 -87
  58. package/lib/cjs/components/components-utils.js +0 -17
  59. package/lib/cjs/context.js +0 -43
  60. package/lib/cjs/css/css.js +0 -84
  61. package/lib/cjs/css/global-rules.js +0 -37
  62. package/lib/cjs/css/index.js +0 -20
  63. package/lib/cjs/css/normalize-type-check.js +0 -26
  64. package/lib/cjs/css/normalize.js +0 -349
  65. package/lib/cjs/css/presets.js +0 -48
  66. package/lib/cjs/css/style-rules.js +0 -86
  67. package/lib/cjs/embed-template.js +0 -368
  68. package/lib/cjs/expression.js +0 -371
  69. package/lib/cjs/generator.js +0 -128
  70. package/lib/cjs/hook.js +0 -34
  71. package/lib/cjs/index.js +0 -59
  72. package/lib/cjs/instance-utils.js +0 -65
  73. package/lib/cjs/package.json +0 -1
  74. package/lib/cjs/props.js +0 -204
  75. package/lib/cjs/pubsub/create.js +0 -78
  76. package/lib/cjs/pubsub/index.js +0 -18
  77. package/lib/cjs/pubsub/raf-queue.js +0 -42
  78. package/lib/cjs/tree/create-elements-tree.js +0 -152
  79. package/lib/cjs/tree/index.js +0 -20
  80. package/lib/cjs/tree/root.js +0 -100
  81. package/lib/cjs/tree/webstudio-component.js +0 -91
  82. package/src/app/index.ts +0 -1
  83. package/src/app/root.tsx +0 -25
  84. package/src/component-renderer.tsx +0 -146
  85. package/src/components/component-meta.ts +0 -86
  86. package/src/components/components-utils.ts +0 -13
  87. package/src/context.tsx +0 -73
  88. package/src/css/css.ts +0 -88
  89. package/src/css/global-rules.ts +0 -26
  90. package/src/css/index.ts +0 -3
  91. package/src/css/normalize-type-check.ts +0 -13
  92. package/src/css/normalize.ts +0 -507
  93. package/src/css/presets.ts +0 -27
  94. package/src/css/style-rules.ts +0 -101
  95. package/src/embed-template.ts +0 -438
  96. package/src/expression.ts +0 -401
  97. package/src/generator.ts +0 -147
  98. package/src/hook.ts +0 -52
  99. package/src/index.ts +0 -39
  100. package/src/instance-utils.ts +0 -65
  101. package/src/props.ts +0 -231
  102. package/src/pubsub/create.ts +0 -77
  103. package/src/pubsub/index.ts +0 -1
  104. package/src/pubsub/raf-queue.ts +0 -25
  105. package/src/tree/create-elements-tree.tsx +0 -186
  106. package/src/tree/index.ts +0 -3
  107. package/src/tree/root.ts +0 -131
  108. package/src/tree/webstudio-component.tsx +0 -97
package/src/props.ts DELETED
@@ -1,231 +0,0 @@
1
- import { useContext, useMemo } from "react";
2
- import { computed } from "nanostores";
3
- import { useStore } from "@nanostores/react";
4
- import type { Instance, Page, Prop, Props } from "@webstudio-is/project-build";
5
- import type { Asset, Assets } from "@webstudio-is/asset-uploader";
6
- import { ReactSdkContext } from "./context";
7
- import { idAttribute, indexAttribute } from "./tree/webstudio-component";
8
-
9
- export type PropsByInstanceId = Map<Instance["id"], Prop[]>;
10
-
11
- export type Pages = Map<Page["id"], Page>;
12
-
13
- export const getPropsByInstanceId = (props: Props) => {
14
- const propsByInstanceId: PropsByInstanceId = new Map();
15
- for (const prop of props.values()) {
16
- let instanceProps = propsByInstanceId.get(prop.instanceId);
17
- if (instanceProps === undefined) {
18
- instanceProps = [];
19
- propsByInstanceId.set(prop.instanceId, instanceProps);
20
- }
21
- instanceProps.push(prop);
22
- }
23
- return propsByInstanceId;
24
- };
25
-
26
- // this utility is be used only for preview with static props
27
- // so there is no need to use computed to optimize rerenders
28
- export const useInstanceProps = (instanceId: Instance["id"]) => {
29
- const {
30
- propsByInstanceIdStore,
31
- dataSourceValuesStore,
32
- executeEffectfulExpression,
33
- setDataSourceValues,
34
- indexesWithinAncestors,
35
- } = useContext(ReactSdkContext);
36
- const index = indexesWithinAncestors.get(instanceId);
37
- const instancePropsObjectStore = useMemo(() => {
38
- return computed(
39
- [propsByInstanceIdStore, dataSourceValuesStore],
40
- (propsByInstanceId, dataSourceValues) => {
41
- const instancePropsObject: Record<Prop["name"], unknown> = {};
42
- if (index !== undefined) {
43
- instancePropsObject[indexAttribute] = index.toString();
44
- }
45
- const instanceProps = propsByInstanceId.get(instanceId);
46
- if (instanceProps === undefined) {
47
- return instancePropsObject;
48
- }
49
- for (const prop of instanceProps) {
50
- if (prop.type === "asset" || prop.type === "page") {
51
- continue;
52
- }
53
- if (prop.type === "dataSource") {
54
- const dataSourceId = prop.value;
55
- const value = dataSourceValues.get(dataSourceId);
56
- if (value !== undefined) {
57
- instancePropsObject[prop.name] = value;
58
- }
59
- continue;
60
- }
61
- if (prop.type === "action") {
62
- instancePropsObject[prop.name] = (...args: unknown[]) => {
63
- for (const value of prop.value) {
64
- if (value.type === "execute") {
65
- const argsMap = new Map<string, unknown>();
66
- for (const [i, name] of value.args.entries()) {
67
- argsMap.set(name, args[i]);
68
- }
69
- const newValues = executeEffectfulExpression(
70
- value.code,
71
- argsMap,
72
- dataSourceValues
73
- );
74
- setDataSourceValues(newValues);
75
- }
76
- }
77
- };
78
- continue;
79
- }
80
- instancePropsObject[prop.name] = prop.value;
81
- }
82
- return instancePropsObject;
83
- }
84
- );
85
- }, [
86
- propsByInstanceIdStore,
87
- dataSourceValuesStore,
88
- instanceId,
89
- executeEffectfulExpression,
90
- setDataSourceValues,
91
- index,
92
- ]);
93
- const instancePropsObject = useStore(instancePropsObjectStore);
94
- return instancePropsObject;
95
- };
96
-
97
- // this utility is used for image component in both builder and preview
98
- // so need to optimize rerenders with computed
99
- export const usePropAsset = (instanceId: Instance["id"], name: string) => {
100
- const { propsByInstanceIdStore, assetsStore } = useContext(ReactSdkContext);
101
- const assetStore = useMemo(() => {
102
- return computed(
103
- [propsByInstanceIdStore, assetsStore],
104
- (propsByInstanceId, assets) => {
105
- const instanceProps = propsByInstanceId.get(instanceId);
106
- if (instanceProps === undefined) {
107
- return;
108
- }
109
- for (const prop of instanceProps) {
110
- if (prop.type === "asset" && prop.name === name) {
111
- const assetId = prop.value;
112
- return assets.get(assetId);
113
- }
114
- }
115
- }
116
- );
117
- }, [propsByInstanceIdStore, assetsStore, instanceId, name]);
118
- const asset = useStore(assetStore);
119
- return asset;
120
- };
121
-
122
- export const resolveUrlProp = (
123
- instanceId: Instance["id"],
124
- name: string,
125
- {
126
- props,
127
- pages,
128
- assets,
129
- }: { props: PropsByInstanceId; pages: Pages; assets: Assets }
130
- ):
131
- | {
132
- type: "page";
133
- page: Page;
134
- instanceId?: Instance["id"];
135
- hash?: string;
136
- }
137
- | { type: "asset"; asset: Asset }
138
- | { type: "string"; url: string }
139
- | undefined => {
140
- const instanceProps = props.get(instanceId);
141
- if (instanceProps === undefined) {
142
- return;
143
- }
144
-
145
- let prop = undefined;
146
-
147
- // We had a bug that some props were duplicated https://github.com/webstudio-is/webstudio-builder/pull/2170
148
- // Use the latest prop to ensure consistency with the builder settings panel.
149
- for (const intanceProp of instanceProps) {
150
- if (intanceProp.name !== name) {
151
- continue;
152
- }
153
- prop = intanceProp;
154
- }
155
-
156
- if (prop === undefined) {
157
- return;
158
- }
159
-
160
- if (prop.type === "page") {
161
- if (typeof prop.value === "string") {
162
- const page = pages.get(prop.value);
163
- return page && { type: "page", page };
164
- }
165
-
166
- const { instanceId, pageId } = prop.value;
167
-
168
- const page = pages.get(pageId);
169
-
170
- if (page === undefined) {
171
- return;
172
- }
173
-
174
- const idProp = props.get(instanceId)?.find((prop) => prop.name === "id");
175
-
176
- return {
177
- type: "page",
178
- page,
179
- instanceId,
180
- hash:
181
- idProp === undefined || idProp.type !== "string"
182
- ? undefined
183
- : idProp.value,
184
- };
185
- }
186
-
187
- if (prop.type === "string") {
188
- for (const page of pages.values()) {
189
- if (page.path === prop.value) {
190
- return { type: "page", page };
191
- }
192
- }
193
- return { type: "string", url: prop.value };
194
- }
195
-
196
- if (prop.type === "asset") {
197
- const asset = assets.get(prop.value);
198
- return asset && { type: "asset", asset };
199
- }
200
-
201
- return;
202
- };
203
-
204
- // this utility is used for link component in both builder and preview
205
- // so need to optimize rerenders with computed
206
- export const usePropUrl = (instanceId: Instance["id"], name: string) => {
207
- const { propsByInstanceIdStore, pagesStore, assetsStore } =
208
- useContext(ReactSdkContext);
209
- const store = useMemo(
210
- () =>
211
- computed(
212
- [propsByInstanceIdStore, pagesStore, assetsStore],
213
- (props, pages, assets) =>
214
- resolveUrlProp(instanceId, name, { props, pages, assets })
215
- ),
216
- [propsByInstanceIdStore, pagesStore, assetsStore, instanceId, name]
217
- );
218
- return useStore(store);
219
- };
220
-
221
- export const getInstanceIdFromComponentProps = (
222
- props: Record<string, unknown>
223
- ) => {
224
- return props[idAttribute] as string;
225
- };
226
-
227
- export const getIndexWithinAncestorFromComponentProps = (
228
- props: Record<string, unknown>
229
- ) => {
230
- return props[indexAttribute] as string | undefined;
231
- };
@@ -1,77 +0,0 @@
1
- import { createNanoEvents } from "nanoevents";
2
- import { useCallback, useEffect, useRef } from "react";
3
- import { batchUpdate } from "./raf-queue";
4
-
5
- export const createPubsub = <PublishMap>() => {
6
- type Action<Type extends keyof PublishMap> =
7
- undefined extends PublishMap[Type]
8
- ? { type: Type; payload?: PublishMap[Type] }
9
- : { type: Type; payload: PublishMap[Type] };
10
-
11
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
12
- const emitter = createNanoEvents<Record<any, any>>();
13
-
14
- if (typeof window === "object") {
15
- window.addEventListener(
16
- "message",
17
- (event: MessageEvent) => {
18
- // @todo this has no type safety built in, could be anything from any source.
19
- // we could potentially maintain a list of valid event types at runtime
20
- // at the very least we could add a brand property or something to our events
21
- if (typeof event.data?.type === "string") {
22
- // Execute all updates within a single batch to improve performance
23
- batchUpdate(() => emitter.emit(event.data.type, event.data.payload));
24
- }
25
- },
26
- false
27
- );
28
- }
29
-
30
- return {
31
- /**
32
- * To publish a postMessage event on the current window and parent window from the iframe.
33
- */
34
- publish<Type extends keyof PublishMap>(action: Action<Type>) {
35
- window.parent.postMessage(action, "*");
36
- window.postMessage(action, "*");
37
- },
38
-
39
- /**
40
- * To publish a postMessage event on the iframe and parent window from the parent window.
41
- */
42
- usePublish() {
43
- const iframeRef = useRef<HTMLIFrameElement | null>(null);
44
- const publishCallback = useCallback(
45
- <Type extends keyof PublishMap>(action: Action<Type>) => {
46
- const element = iframeRef.current;
47
- if (element?.contentWindow == null) {
48
- return;
49
- }
50
- element.contentWindow.postMessage(action, "*");
51
- window.postMessage(action, "*");
52
- },
53
- [iframeRef]
54
- );
55
- return [publishCallback, iframeRef] as const;
56
- },
57
-
58
- /**
59
- * To subscribe a message event on the current window.
60
- */
61
- useSubscribe<Type extends keyof PublishMap>(
62
- type: Type,
63
- onAction: (payload: PublishMap[Type]) => void
64
- ) {
65
- useEffect(() => {
66
- return emitter.on(type, onAction);
67
- }, [type, onAction]);
68
- },
69
-
70
- subscribe<Type extends keyof PublishMap>(
71
- type: Type,
72
- onAction: (payload: PublishMap[Type]) => void
73
- ) {
74
- return emitter.on(type, onAction);
75
- },
76
- };
77
- };
@@ -1 +0,0 @@
1
- export * from "./create";
@@ -1,25 +0,0 @@
1
- type Task = () => void;
2
-
3
- let handle: ReturnType<typeof requestAnimationFrame> | undefined;
4
- let updateQueue: Task[] = [];
5
-
6
- const processUpdates = (updates: Task[]) => {
7
- for (const update of updates) {
8
- update();
9
- }
10
- };
11
-
12
- export const batchUpdate = (update: () => void) => {
13
- updateQueue.push(update);
14
-
15
- if (handle !== undefined) {
16
- return;
17
- }
18
-
19
- handle = requestAnimationFrame(() => {
20
- const updates = updateQueue;
21
- updateQueue = [];
22
- handle = undefined;
23
- processUpdates(updates);
24
- });
25
- };
@@ -1,186 +0,0 @@
1
- import {
2
- Fragment,
3
- type ForwardRefExoticComponent,
4
- type RefAttributes,
5
- type ReactNode,
6
- } from "react";
7
- import type { ReadableAtom } from "nanostores";
8
- import type { Assets } from "@webstudio-is/asset-uploader";
9
- import type { Instance, Instances } from "@webstudio-is/project-build";
10
- import type { Components } from "../components/components-utils";
11
- import {
12
- type Params,
13
- type DataSourceValues,
14
- ReactSdkContext,
15
- } from "../context";
16
- import type { Pages, PropsByInstanceId } from "../props";
17
- import type { WebstudioComponentProps } from "./webstudio-component";
18
- import type { IndexesWithinAncestors } from "../instance-utils";
19
-
20
- type InstanceSelector = Instance["id"][];
21
-
22
- export const createElementsTree = ({
23
- renderer,
24
- imageBaseUrl,
25
- assetBaseUrl,
26
- instances,
27
- rootInstanceId,
28
- propsByInstanceIdStore,
29
- assetsStore,
30
- pagesStore,
31
- dataSourceValuesStore,
32
- executeEffectfulExpression,
33
- onDataSourceUpdate,
34
- indexesWithinAncestors,
35
- Component,
36
- components,
37
- scripts,
38
- }: Params & {
39
- instances: Instances;
40
- rootInstanceId: Instance["id"];
41
- propsByInstanceIdStore: ReadableAtom<PropsByInstanceId>;
42
- assetsStore: ReadableAtom<Assets>;
43
- pagesStore: ReadableAtom<Pages>;
44
- executeEffectfulExpression: (
45
- expression: string,
46
- args: DataSourceValues,
47
- values: DataSourceValues
48
- ) => DataSourceValues;
49
- dataSourceValuesStore: ReadableAtom<DataSourceValues>;
50
- onDataSourceUpdate: (newValues: DataSourceValues) => void;
51
- indexesWithinAncestors: IndexesWithinAncestors;
52
-
53
- Component: ForwardRefExoticComponent<
54
- WebstudioComponentProps & RefAttributes<HTMLElement>
55
- >;
56
- components: Components;
57
- scripts?: ReactNode;
58
- }) => {
59
- const rootInstance = instances.get(rootInstanceId);
60
- if (rootInstance === undefined) {
61
- return null;
62
- }
63
-
64
- const rootInstanceSelector = [rootInstanceId];
65
- const children = createInstanceChildrenElements({
66
- instances,
67
- instanceSelector: rootInstanceSelector,
68
- Component,
69
- children: rootInstance.children,
70
- components,
71
- });
72
- const root = createInstanceElement({
73
- Component,
74
- instance: rootInstance,
75
- instanceSelector: rootInstanceSelector,
76
- children: [
77
- <Fragment key="children">
78
- {children}
79
- {scripts}
80
- </Fragment>,
81
- ],
82
- components,
83
- });
84
- return (
85
- <ReactSdkContext.Provider
86
- value={{
87
- propsByInstanceIdStore,
88
- assetsStore,
89
- pagesStore,
90
- dataSourceValuesStore,
91
- renderer,
92
- imageBaseUrl,
93
- assetBaseUrl,
94
- indexesWithinAncestors,
95
- executeEffectfulExpression,
96
- setDataSourceValues: onDataSourceUpdate,
97
- setBoundDataSourceValue: (instanceId, propName, value) => {
98
- const propsByInstanceId = propsByInstanceIdStore.get();
99
- const props = propsByInstanceId.get(instanceId);
100
- const prop = props?.find((prop) => prop.name === propName);
101
- if (prop?.type !== "dataSource") {
102
- throw Error(`${propName} is not data source`);
103
- }
104
- const dataSourceId = prop.value;
105
- const newValues = new Map();
106
- newValues.set(dataSourceId, value);
107
- onDataSourceUpdate(newValues);
108
- },
109
- }}
110
- >
111
- {root}
112
- </ReactSdkContext.Provider>
113
- );
114
- };
115
-
116
- const createInstanceChildrenElements = ({
117
- instances,
118
- instanceSelector,
119
- children,
120
- Component,
121
- components,
122
- }: {
123
- instances: Instances;
124
- instanceSelector: InstanceSelector;
125
- children: Instance["children"];
126
- Component: ForwardRefExoticComponent<
127
- WebstudioComponentProps & RefAttributes<HTMLElement>
128
- >;
129
- components: Components;
130
- }) => {
131
- const elements = [];
132
- for (const child of children) {
133
- if (child.type === "text") {
134
- elements.push(child.value);
135
- continue;
136
- }
137
- const childInstance = instances.get(child.value);
138
- if (childInstance === undefined) {
139
- continue;
140
- }
141
- const childInstanceSelector = [child.value, ...instanceSelector];
142
- const children = createInstanceChildrenElements({
143
- instances,
144
- instanceSelector: childInstanceSelector,
145
- children: childInstance.children,
146
- Component,
147
- components,
148
- });
149
- const element = createInstanceElement({
150
- instance: childInstance,
151
- instanceSelector: childInstanceSelector,
152
- Component,
153
- children,
154
- components,
155
- });
156
- elements.push(element);
157
- }
158
- return elements;
159
- };
160
-
161
- const createInstanceElement = ({
162
- Component,
163
- instance,
164
- instanceSelector,
165
- children = [],
166
- components,
167
- }: {
168
- instance: Instance;
169
- instanceSelector: InstanceSelector;
170
- Component: ForwardRefExoticComponent<
171
- WebstudioComponentProps & RefAttributes<HTMLElement>
172
- >;
173
- children?: Array<JSX.Element | string>;
174
- components: Components;
175
- }) => {
176
- return (
177
- <Component
178
- key={instance.id}
179
- instance={instance}
180
- instanceSelector={instanceSelector}
181
- components={components}
182
- >
183
- {children}
184
- </Component>
185
- );
186
- };
package/src/tree/index.ts DELETED
@@ -1,3 +0,0 @@
1
- export * from "./create-elements-tree";
2
- export * from "./root";
3
- export * from "./webstudio-component";
package/src/tree/root.ts DELETED
@@ -1,131 +0,0 @@
1
- import {
2
- useRef,
3
- useCallback,
4
- type ForwardRefExoticComponent,
5
- type RefAttributes,
6
- type ReactNode,
7
- } from "react";
8
- import {
9
- atom,
10
- computed,
11
- type ReadableAtom,
12
- type WritableAtom,
13
- } from "nanostores";
14
- import { type Build, type Page } from "@webstudio-is/project-build";
15
- import type { Asset } from "@webstudio-is/asset-uploader";
16
- import { createElementsTree } from "./create-elements-tree";
17
- import {
18
- WebstudioComponent,
19
- type WebstudioComponentProps,
20
- } from "./webstudio-component";
21
- import { getPropsByInstanceId } from "../props";
22
- import type { Components } from "../components/components-utils";
23
- import type { Params, DataSourceValues } from "../context";
24
- import type { GeneratedUtils } from "../generator";
25
-
26
- export type Data = {
27
- page: Page;
28
- pages: Array<Page>;
29
- build: Build;
30
- assets: Array<Asset>;
31
- params?: Params;
32
- };
33
-
34
- export type RootPropsData = Omit<Data, "build"> & {
35
- build: Pick<Data["build"], "instances" | "props" | "dataSources">;
36
- };
37
-
38
- type RootProps = {
39
- data: RootPropsData;
40
- utils: GeneratedUtils;
41
- Component?: ForwardRefExoticComponent<
42
- WebstudioComponentProps & RefAttributes<HTMLElement>
43
- >;
44
- components: Components;
45
- scripts?: ReactNode;
46
- };
47
-
48
- export const InstanceRoot = ({
49
- data,
50
- utils,
51
- Component,
52
- components,
53
- scripts,
54
- }: RootProps): JSX.Element | null => {
55
- const {
56
- indexesWithinAncestors,
57
- executeComputingExpressions,
58
- executeEffectfulExpression,
59
- } = utils;
60
- const dataSourceVariablesStoreRef = useRef<
61
- undefined | WritableAtom<DataSourceValues>
62
- >(undefined);
63
- if (dataSourceVariablesStoreRef.current === undefined) {
64
- dataSourceVariablesStoreRef.current = atom(new Map());
65
- }
66
- const dataSourceVariablesStore = dataSourceVariablesStoreRef.current;
67
-
68
- const dataSourceValuesStoreRef = useRef<
69
- undefined | ReadableAtom<DataSourceValues>
70
- >(undefined);
71
- if (dataSourceValuesStoreRef.current === undefined) {
72
- dataSourceValuesStoreRef.current = computed(
73
- dataSourceVariablesStore,
74
- (dataSourceVariables) => {
75
- // set vriables with defaults
76
- const dataSourceValues: DataSourceValues = new Map();
77
- for (const [dataSourceId, dataSource] of data.build.dataSources) {
78
- if (dataSource.type === "variable") {
79
- const value =
80
- dataSourceVariables.get(dataSourceId) ?? dataSource.value.value;
81
- dataSourceValues.set(dataSourceId, value);
82
- }
83
- }
84
-
85
- // set expression values
86
- try {
87
- const result = executeComputingExpressions(dataSourceValues);
88
- for (const [id, value] of result) {
89
- dataSourceValues.set(id, value);
90
- }
91
- } catch (error) {
92
- // eslint-disable-next-line no-console
93
- console.error(error);
94
- }
95
-
96
- return dataSourceValues;
97
- }
98
- );
99
- }
100
- const dataSourceValuesStore = dataSourceValuesStoreRef.current;
101
-
102
- const onDataSourceUpdate = useCallback(
103
- (newValues: DataSourceValues) => {
104
- const dataSourceVariables = new Map(dataSourceVariablesStore.get());
105
- for (const [dataSourceId, value] of newValues) {
106
- dataSourceVariables.set(dataSourceId, value);
107
- }
108
- dataSourceVariablesStore.set(dataSourceVariables);
109
- },
110
- [dataSourceVariablesStore]
111
- );
112
-
113
- return createElementsTree({
114
- imageBaseUrl: data.params?.imageBaseUrl ?? "/",
115
- assetBaseUrl: data.params?.assetBaseUrl ?? "/",
116
- instances: new Map(data.build.instances),
117
- rootInstanceId: data.page.rootInstanceId,
118
- propsByInstanceIdStore: atom(
119
- getPropsByInstanceId(new Map(data.build.props))
120
- ),
121
- assetsStore: atom(new Map(data.assets.map((asset) => [asset.id, asset]))),
122
- pagesStore: atom(new Map(data.pages.map((page) => [page.id, page]))),
123
- indexesWithinAncestors,
124
- executeEffectfulExpression,
125
- dataSourceValuesStore,
126
- onDataSourceUpdate,
127
- Component: Component ?? WebstudioComponent,
128
- components,
129
- scripts,
130
- });
131
- };