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