@webstudio-is/react-sdk 0.87.1 → 0.88.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.
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { Breakpoint } from "@webstudio-is/project-build";
2
+ import { Instance, Breakpoint } from "@webstudio-is/project-build";
3
3
  import { type StyleProperty } from "@webstudio-is/css-data";
4
4
  import type { Simplify } from "type-fest";
5
5
  import type { WsComponentMeta } from "./components/component-meta";
@@ -2177,6 +2177,7 @@ export type EmbedTemplateInstance = {
2177
2177
  label?: string;
2178
2178
  dataSources?: Record<string, EmbedTemplateDataSource>;
2179
2179
  props?: EmbedTemplateProp[];
2180
+ tokens?: string[];
2180
2181
  styles?: EmbedTemplateStyleDecl[];
2181
2182
  children: Array<EmbedTemplateInstance | EmbedTemplateText>;
2182
2183
  };
@@ -2195,7 +2196,7 @@ export type WsEmbedTemplate = z.infer<typeof WsEmbedTemplate>;
2195
2196
  export declare const generateDataFromEmbedTemplate: (treeTemplate: ({
2196
2197
  type: "text";
2197
2198
  value: string;
2198
- } | EmbedTemplateInstance)[], defaultBreakpointId: Breakpoint["id"]) => {
2199
+ } | EmbedTemplateInstance)[], metas: Map<Instance["component"], WsComponentMeta>, defaultBreakpointId: Breakpoint["id"]) => {
2199
2200
  children: ({
2200
2201
  type: "text";
2201
2202
  value: string;
@@ -2553,6 +2554,222 @@ export declare const namespaceMeta: (meta: WsComponentMeta, namespace: string, c
2553
2554
  stylable?: boolean | undefined;
2554
2555
  detachable?: boolean | undefined;
2555
2556
  icon: string;
2557
+ presetTokens?: Record<string, {
2558
+ styles: {
2559
+ value: {
2560
+ type: "unit";
2561
+ value: number;
2562
+ unit: "number" | "%" | "deg" | "grad" | "rad" | "turn" | "db" | "fr" | "hz" | "khz" | "cm" | "mm" | "q" | "in" | "pt" | "pc" | "px" | "em" | "rem" | "ex" | "rex" | "cap" | "rcap" | "ch" | "rch" | "ic" | "ric" | "lh" | "rlh" | "vw" | "svw" | "lvw" | "dvw" | "vh" | "svh" | "lvh" | "dvh" | "vi" | "svi" | "lvi" | "dvi" | "vb" | "svb" | "lvb" | "dvb" | "vmin" | "svmin" | "lvmin" | "dvmin" | "vmax" | "svmax" | "lvmax" | "dvmax" | "cqw" | "cqh" | "cqi" | "cqb" | "cqmin" | "cqmax" | "dpi" | "dpcm" | "dppx" | "x" | "st" | "s" | "ms";
2563
+ } | {
2564
+ type: "keyword";
2565
+ value: string;
2566
+ } | {
2567
+ type: "unparsed";
2568
+ value: string;
2569
+ hidden?: boolean | undefined;
2570
+ } | {
2571
+ type: "fontFamily";
2572
+ value: string[];
2573
+ } | {
2574
+ type: "rgb";
2575
+ alpha: number;
2576
+ r: number;
2577
+ g: number;
2578
+ b: number;
2579
+ } | {
2580
+ type: "image";
2581
+ value: {
2582
+ type: "asset";
2583
+ value: string;
2584
+ } | {
2585
+ type: "url";
2586
+ url: string;
2587
+ };
2588
+ hidden?: boolean | undefined;
2589
+ } | {
2590
+ type: "invalid";
2591
+ value: string;
2592
+ } | {
2593
+ type: "unset";
2594
+ value: "";
2595
+ } | {
2596
+ type: "tuple";
2597
+ value: ({
2598
+ type: "unit";
2599
+ value: number;
2600
+ unit: "number" | "%" | "deg" | "grad" | "rad" | "turn" | "db" | "fr" | "hz" | "khz" | "cm" | "mm" | "q" | "in" | "pt" | "pc" | "px" | "em" | "rem" | "ex" | "rex" | "cap" | "rcap" | "ch" | "rch" | "ic" | "ric" | "lh" | "rlh" | "vw" | "svw" | "lvw" | "dvw" | "vh" | "svh" | "lvh" | "dvh" | "vi" | "svi" | "lvi" | "dvi" | "vb" | "svb" | "lvb" | "dvb" | "vmin" | "svmin" | "lvmin" | "dvmin" | "vmax" | "svmax" | "lvmax" | "dvmax" | "cqw" | "cqh" | "cqi" | "cqb" | "cqmin" | "cqmax" | "dpi" | "dpcm" | "dppx" | "x" | "st" | "s" | "ms";
2601
+ } | {
2602
+ type: "keyword";
2603
+ value: string;
2604
+ } | {
2605
+ type: "unparsed";
2606
+ value: string;
2607
+ hidden?: boolean | undefined;
2608
+ } | {
2609
+ type: "rgb";
2610
+ alpha: number;
2611
+ r: number;
2612
+ g: number;
2613
+ b: number;
2614
+ })[];
2615
+ hidden?: boolean | undefined;
2616
+ } | {
2617
+ type: "layers";
2618
+ value: ({
2619
+ type: "unit";
2620
+ value: number;
2621
+ unit: "number" | "%" | "deg" | "grad" | "rad" | "turn" | "db" | "fr" | "hz" | "khz" | "cm" | "mm" | "q" | "in" | "pt" | "pc" | "px" | "em" | "rem" | "ex" | "rex" | "cap" | "rcap" | "ch" | "rch" | "ic" | "ric" | "lh" | "rlh" | "vw" | "svw" | "lvw" | "dvw" | "vh" | "svh" | "lvh" | "dvh" | "vi" | "svi" | "lvi" | "dvi" | "vb" | "svb" | "lvb" | "dvb" | "vmin" | "svmin" | "lvmin" | "dvmin" | "vmax" | "svmax" | "lvmax" | "dvmax" | "cqw" | "cqh" | "cqi" | "cqb" | "cqmin" | "cqmax" | "dpi" | "dpcm" | "dppx" | "x" | "st" | "s" | "ms";
2622
+ } | {
2623
+ type: "keyword";
2624
+ value: string;
2625
+ } | {
2626
+ type: "unparsed";
2627
+ value: string;
2628
+ hidden?: boolean | undefined;
2629
+ } | {
2630
+ type: "image";
2631
+ value: {
2632
+ type: "asset";
2633
+ value: string;
2634
+ } | {
2635
+ type: "url";
2636
+ url: string;
2637
+ };
2638
+ hidden?: boolean | undefined;
2639
+ } | {
2640
+ type: "invalid";
2641
+ value: string;
2642
+ } | {
2643
+ type: "tuple";
2644
+ value: ({
2645
+ type: "unit";
2646
+ value: number;
2647
+ unit: "number" | "%" | "deg" | "grad" | "rad" | "turn" | "db" | "fr" | "hz" | "khz" | "cm" | "mm" | "q" | "in" | "pt" | "pc" | "px" | "em" | "rem" | "ex" | "rex" | "cap" | "rcap" | "ch" | "rch" | "ic" | "ric" | "lh" | "rlh" | "vw" | "svw" | "lvw" | "dvw" | "vh" | "svh" | "lvh" | "dvh" | "vi" | "svi" | "lvi" | "dvi" | "vb" | "svb" | "lvb" | "dvb" | "vmin" | "svmin" | "lvmin" | "dvmin" | "vmax" | "svmax" | "lvmax" | "dvmax" | "cqw" | "cqh" | "cqi" | "cqb" | "cqmin" | "cqmax" | "dpi" | "dpcm" | "dppx" | "x" | "st" | "s" | "ms";
2648
+ } | {
2649
+ type: "keyword";
2650
+ value: string;
2651
+ } | {
2652
+ type: "unparsed";
2653
+ value: string;
2654
+ hidden?: boolean | undefined;
2655
+ } | {
2656
+ type: "rgb";
2657
+ alpha: number;
2658
+ r: number;
2659
+ g: number;
2660
+ b: number;
2661
+ })[];
2662
+ hidden?: boolean | undefined;
2663
+ })[];
2664
+ } | {
2665
+ type: "var";
2666
+ value: string;
2667
+ fallbacks: ({
2668
+ type: "unit";
2669
+ value: number;
2670
+ unit: "number" | "%" | "deg" | "grad" | "rad" | "turn" | "db" | "fr" | "hz" | "khz" | "cm" | "mm" | "q" | "in" | "pt" | "pc" | "px" | "em" | "rem" | "ex" | "rex" | "cap" | "rcap" | "ch" | "rch" | "ic" | "ric" | "lh" | "rlh" | "vw" | "svw" | "lvw" | "dvw" | "vh" | "svh" | "lvh" | "dvh" | "vi" | "svi" | "lvi" | "dvi" | "vb" | "svb" | "lvb" | "dvb" | "vmin" | "svmin" | "lvmin" | "dvmin" | "vmax" | "svmax" | "lvmax" | "dvmax" | "cqw" | "cqh" | "cqi" | "cqb" | "cqmin" | "cqmax" | "dpi" | "dpcm" | "dppx" | "x" | "st" | "s" | "ms";
2671
+ } | {
2672
+ type: "keyword";
2673
+ value: string;
2674
+ } | {
2675
+ type: "unparsed";
2676
+ value: string;
2677
+ hidden?: boolean | undefined;
2678
+ } | {
2679
+ type: "fontFamily";
2680
+ value: string[];
2681
+ } | {
2682
+ type: "rgb";
2683
+ alpha: number;
2684
+ r: number;
2685
+ g: number;
2686
+ b: number;
2687
+ } | {
2688
+ type: "image";
2689
+ value: {
2690
+ type: "asset";
2691
+ value: string;
2692
+ } | {
2693
+ type: "url";
2694
+ url: string;
2695
+ };
2696
+ hidden?: boolean | undefined;
2697
+ } | {
2698
+ type: "tuple";
2699
+ value: ({
2700
+ type: "unit";
2701
+ value: number;
2702
+ unit: "number" | "%" | "deg" | "grad" | "rad" | "turn" | "db" | "fr" | "hz" | "khz" | "cm" | "mm" | "q" | "in" | "pt" | "pc" | "px" | "em" | "rem" | "ex" | "rex" | "cap" | "rcap" | "ch" | "rch" | "ic" | "ric" | "lh" | "rlh" | "vw" | "svw" | "lvw" | "dvw" | "vh" | "svh" | "lvh" | "dvh" | "vi" | "svi" | "lvi" | "dvi" | "vb" | "svb" | "lvb" | "dvb" | "vmin" | "svmin" | "lvmin" | "dvmin" | "vmax" | "svmax" | "lvmax" | "dvmax" | "cqw" | "cqh" | "cqi" | "cqb" | "cqmin" | "cqmax" | "dpi" | "dpcm" | "dppx" | "x" | "st" | "s" | "ms";
2703
+ } | {
2704
+ type: "keyword";
2705
+ value: string;
2706
+ } | {
2707
+ type: "unparsed";
2708
+ value: string;
2709
+ hidden?: boolean | undefined;
2710
+ } | {
2711
+ type: "rgb";
2712
+ alpha: number;
2713
+ r: number;
2714
+ g: number;
2715
+ b: number;
2716
+ })[];
2717
+ hidden?: boolean | undefined;
2718
+ } | {
2719
+ type: "layers";
2720
+ value: ({
2721
+ type: "unit";
2722
+ value: number;
2723
+ unit: "number" | "%" | "deg" | "grad" | "rad" | "turn" | "db" | "fr" | "hz" | "khz" | "cm" | "mm" | "q" | "in" | "pt" | "pc" | "px" | "em" | "rem" | "ex" | "rex" | "cap" | "rcap" | "ch" | "rch" | "ic" | "ric" | "lh" | "rlh" | "vw" | "svw" | "lvw" | "dvw" | "vh" | "svh" | "lvh" | "dvh" | "vi" | "svi" | "lvi" | "dvi" | "vb" | "svb" | "lvb" | "dvb" | "vmin" | "svmin" | "lvmin" | "dvmin" | "vmax" | "svmax" | "lvmax" | "dvmax" | "cqw" | "cqh" | "cqi" | "cqb" | "cqmin" | "cqmax" | "dpi" | "dpcm" | "dppx" | "x" | "st" | "s" | "ms";
2724
+ } | {
2725
+ type: "keyword";
2726
+ value: string;
2727
+ } | {
2728
+ type: "unparsed";
2729
+ value: string;
2730
+ hidden?: boolean | undefined;
2731
+ } | {
2732
+ type: "image";
2733
+ value: {
2734
+ type: "asset";
2735
+ value: string;
2736
+ } | {
2737
+ type: "url";
2738
+ url: string;
2739
+ };
2740
+ hidden?: boolean | undefined;
2741
+ } | {
2742
+ type: "invalid";
2743
+ value: string;
2744
+ } | {
2745
+ type: "tuple";
2746
+ value: ({
2747
+ type: "unit";
2748
+ value: number;
2749
+ unit: "number" | "%" | "deg" | "grad" | "rad" | "turn" | "db" | "fr" | "hz" | "khz" | "cm" | "mm" | "q" | "in" | "pt" | "pc" | "px" | "em" | "rem" | "ex" | "rex" | "cap" | "rcap" | "ch" | "rch" | "ic" | "ric" | "lh" | "rlh" | "vw" | "svw" | "lvw" | "dvw" | "vh" | "svh" | "lvh" | "dvh" | "vi" | "svi" | "lvi" | "dvi" | "vb" | "svb" | "lvb" | "dvb" | "vmin" | "svmin" | "lvmin" | "dvmin" | "vmax" | "svmax" | "lvmax" | "dvmax" | "cqw" | "cqh" | "cqi" | "cqb" | "cqmin" | "cqmax" | "dpi" | "dpcm" | "dppx" | "x" | "st" | "s" | "ms";
2750
+ } | {
2751
+ type: "keyword";
2752
+ value: string;
2753
+ } | {
2754
+ type: "unparsed";
2755
+ value: string;
2756
+ hidden?: boolean | undefined;
2757
+ } | {
2758
+ type: "rgb";
2759
+ alpha: number;
2760
+ r: number;
2761
+ g: number;
2762
+ b: number;
2763
+ })[];
2764
+ hidden?: boolean | undefined;
2765
+ })[];
2766
+ })[];
2767
+ };
2768
+ state?: string | undefined;
2769
+ property: StyleProperty;
2770
+ }[];
2771
+ variant?: string | undefined;
2772
+ }> | undefined;
2556
2773
  states?: {
2557
2774
  label: string;
2558
2775
  selector: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webstudio-is/react-sdk",
3
- "version": "0.87.1",
3
+ "version": "0.88.0",
4
4
  "description": "Webstudio JavaScript / TypeScript API",
5
5
  "author": "Webstudio <github@webstudio.is>",
6
6
  "homepage": "https://webstudio.is",
@@ -34,12 +34,14 @@
34
34
  "nanoevents": "^8.0.0",
35
35
  "nanoid": "^4.0.2",
36
36
  "nanostores": "^0.9.3",
37
- "@webstudio-is/asset-uploader": "^0.87.1",
38
- "@webstudio-is/css-data": "^0.87.1",
39
- "@webstudio-is/css-engine": "^0.87.1",
40
- "@webstudio-is/fonts": "^0.87.1",
41
- "@webstudio-is/generate-arg-types": "^0.87.1",
42
- "@webstudio-is/project-build": "^0.87.1"
37
+ "no-case": "^3.0.4",
38
+ "title-case": "^3.0.3",
39
+ "@webstudio-is/asset-uploader": "^0.88.0",
40
+ "@webstudio-is/css-data": "^0.88.0",
41
+ "@webstudio-is/css-engine": "^0.88.0",
42
+ "@webstudio-is/fonts": "^0.88.0",
43
+ "@webstudio-is/generate-arg-types": "^0.88.0",
44
+ "@webstudio-is/project-build": "^0.88.0"
43
45
  },
44
46
  "exports": {
45
47
  ".": {
@@ -56,7 +56,7 @@ export const renderComponentTemplate = ({
56
56
  });
57
57
  }
58
58
 
59
- const data = generateDataFromEmbedTemplate(template, "base");
59
+ const data = generateDataFromEmbedTemplate(template, metas, "base");
60
60
 
61
61
  const instances: [Instance["id"], Instance][] = [
62
62
  [
@@ -36,6 +36,11 @@ export const ComponentState = z.object({
36
36
 
37
37
  export type ComponentState = z.infer<typeof ComponentState>;
38
38
 
39
+ const ComponentToken = z.object({
40
+ variant: z.optional(z.string()),
41
+ styles: z.array(EmbedTemplateStyleDecl),
42
+ });
43
+
39
44
  export const defaultStates: ComponentState[] = [
40
45
  { selector: ":hover", label: "Hover" },
41
46
  { selector: ":active", label: "Active" },
@@ -67,6 +72,7 @@ const WsComponentMeta = z.object({
67
72
  description: z.string().optional(),
68
73
  icon: z.string(),
69
74
  presetStyle: z.optional(z.record(z.string(), EmbedTemplateStyleDecl)),
75
+ presetTokens: z.optional(z.record(z.string(), ComponentToken)),
70
76
  states: z.optional(z.array(ComponentState)),
71
77
  template: z.optional(WsEmbedTemplate),
72
78
  order: z.number().optional(),
@@ -1,6 +1,7 @@
1
1
  import { expect, test } from "@jest/globals";
2
2
  import { generateDataFromEmbedTemplate, namespaceMeta } from "./embed-template";
3
3
  import { showAttribute } from "./tree";
4
+ import type { WsComponentMeta } from "./components/component-meta";
4
5
 
5
6
  const expectString = expect.any(String);
6
7
 
@@ -20,6 +21,7 @@ test("generate data for embedding from instances and text", () => {
20
21
  ],
21
22
  },
22
23
  ],
24
+ new Map(),
23
25
  defaultBreakpointId
24
26
  )
25
27
  ).toEqual({
@@ -73,6 +75,7 @@ test("generate data for embedding from props", () => {
73
75
  ],
74
76
  },
75
77
  ],
78
+ new Map(),
76
79
  defaultBreakpointId
77
80
  )
78
81
  ).toEqual({
@@ -147,6 +150,7 @@ test("generate data for embedding from styles", () => {
147
150
  ],
148
151
  },
149
152
  ],
153
+ new Map(),
150
154
  defaultBreakpointId
151
155
  )
152
156
  ).toEqual({
@@ -245,6 +249,7 @@ test("generate data for embedding from props bound to data source variables", ()
245
249
  children: [],
246
250
  },
247
251
  ],
252
+ new Map(),
248
253
  defaultBreakpointId
249
254
  )
250
255
  ).toEqual({
@@ -326,6 +331,7 @@ test("generate data for embedding from props bound to data source expressions",
326
331
  children: [],
327
332
  },
328
333
  ],
334
+ new Map(),
329
335
  defaultBreakpointId
330
336
  )
331
337
  ).toEqual({
@@ -422,6 +428,7 @@ test("generate data for embedding from action props", () => {
422
428
  ],
423
429
  },
424
430
  ],
431
+ new Map(),
425
432
  defaultBreakpointId
426
433
  )
427
434
  ).toEqual({
@@ -488,6 +495,93 @@ test("generate data for embedding from action props", () => {
488
495
  });
489
496
  });
490
497
 
498
+ test("generate styles from tokens", () => {
499
+ const presetTokens: WsComponentMeta["presetTokens"] = {
500
+ box: {
501
+ styles: [
502
+ {
503
+ property: "width",
504
+ value: { type: "keyword", value: "max-content" },
505
+ },
506
+ {
507
+ property: "height",
508
+ value: { type: "keyword", value: "max-content" },
509
+ },
510
+ ],
511
+ },
512
+ boxBright: {
513
+ styles: [
514
+ {
515
+ property: "color",
516
+ value: { type: "keyword", value: "red" },
517
+ },
518
+ {
519
+ property: "backgroundColor",
520
+ value: { type: "keyword", value: "pink" },
521
+ },
522
+ ],
523
+ },
524
+ boxNone: {
525
+ styles: [
526
+ {
527
+ property: "color",
528
+ value: { type: "keyword", value: "transparent" },
529
+ },
530
+ {
531
+ property: "backgroundColor",
532
+ value: { type: "keyword", value: "transparent" },
533
+ },
534
+ ],
535
+ },
536
+ };
537
+ const { styleSourceSelections, styleSources, styles } =
538
+ generateDataFromEmbedTemplate(
539
+ [
540
+ {
541
+ type: "instance",
542
+ component: "Box",
543
+ tokens: ["box", "boxBright"],
544
+ children: [],
545
+ },
546
+ ],
547
+ new Map([["Box", { type: "container", icon: "", presetTokens }]]),
548
+ defaultBreakpointId
549
+ );
550
+ expect(styleSources).toEqual([
551
+ { id: "Box:box", name: "Box", type: "token" },
552
+ { id: "Box:boxBright", name: "Box Bright", type: "token" },
553
+ ]);
554
+ expect(styleSourceSelections).toEqual([
555
+ { instanceId: expectString, values: ["Box:box", "Box:boxBright"] },
556
+ ]);
557
+ expect(styles).toEqual([
558
+ {
559
+ breakpointId: "base",
560
+ property: "width",
561
+ styleSourceId: "Box:box",
562
+ value: { type: "keyword", value: "max-content" },
563
+ },
564
+ {
565
+ breakpointId: "base",
566
+ property: "height",
567
+ styleSourceId: "Box:box",
568
+ value: { type: "keyword", value: "max-content" },
569
+ },
570
+ {
571
+ breakpointId: "base",
572
+ property: "color",
573
+ styleSourceId: "Box:boxBright",
574
+ value: { type: "keyword", value: "red" },
575
+ },
576
+ {
577
+ breakpointId: "base",
578
+ property: "backgroundColor",
579
+ styleSourceId: "Box:boxBright",
580
+ value: { type: "keyword", value: "pink" },
581
+ },
582
+ ]);
583
+ });
584
+
491
585
  test("add namespace to selected components in embed template", () => {
492
586
  expect(
493
587
  namespaceMeta(
@@ -498,10 +592,16 @@ test("add namespace to selected components in embed template", () => {
498
592
  requiredAncestors: ["Button", "Box"],
499
593
  invalidAncestors: ["Tooltip"],
500
594
  indexWithinAncestor: "Tooltip",
595
+ presetTokens: {
596
+ base: { styles: [] },
597
+ small: { styles: [] },
598
+ large: { styles: [] },
599
+ },
501
600
  template: [
502
601
  {
503
602
  type: "instance",
504
603
  component: "Tooltip",
604
+ tokens: ["base", "small"],
505
605
  children: [
506
606
  { type: "text", value: "Some text" },
507
607
  {
@@ -529,10 +629,16 @@ test("add namespace to selected components in embed template", () => {
529
629
  requiredAncestors: ["my-namespace:Button", "Box"],
530
630
  invalidAncestors: ["my-namespace:Tooltip"],
531
631
  indexWithinAncestor: "my-namespace:Tooltip",
632
+ presetTokens: {
633
+ base: { styles: [] },
634
+ small: { styles: [] },
635
+ large: { styles: [] },
636
+ },
532
637
  template: [
533
638
  {
534
639
  type: "instance",
535
640
  component: "my-namespace:Tooltip",
641
+ tokens: ["base", "small"],
536
642
  children: [
537
643
  { type: "text", value: "Some text" },
538
644
  {
@@ -1,5 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import { nanoid } from "nanoid";
3
+ import { titleCase } from "title-case";
4
+ import { noCase } from "no-case";
3
5
  import {
4
6
  Instance,
5
7
  type InstancesList,
@@ -103,6 +105,7 @@ export type EmbedTemplateInstance = {
103
105
  label?: string;
104
106
  dataSources?: Record<string, EmbedTemplateDataSource>;
105
107
  props?: EmbedTemplateProp[];
108
+ tokens?: string[];
106
109
  styles?: EmbedTemplateStyleDecl[];
107
110
  children: Array<EmbedTemplateInstance | EmbedTemplateText>;
108
111
  };
@@ -115,6 +118,7 @@ export const EmbedTemplateInstance: z.ZodType<EmbedTemplateInstance> = z.lazy(
115
118
  label: z.optional(z.string()),
116
119
  dataSources: z.optional(z.record(z.string(), EmbedTemplateDataSource)),
117
120
  props: z.optional(z.array(EmbedTemplateProp)),
121
+ tokens: z.optional(z.array(z.string())),
118
122
  styles: z.optional(z.array(EmbedTemplateStyleDecl)),
119
123
  children: WsEmbedTemplate,
120
124
  })
@@ -153,6 +157,7 @@ const createInstancesFromTemplate = (
153
157
  styleSourceSelections: StyleSourceSelectionsList,
154
158
  styleSources: StyleSourcesList,
155
159
  styles: StylesList,
160
+ metas: Map<Instance["component"], WsComponentMeta>,
156
161
  defaultBreakpointId: Breakpoint["id"]
157
162
  ) => {
158
163
  const parentChildren: Instance["children"] = [];
@@ -243,6 +248,36 @@ const createInstancesFromTemplate = (
243
248
  }
244
249
  }
245
250
 
251
+ const styleSourceIds: string[] = [];
252
+
253
+ // convert tokens into style sources and styles
254
+ if (item.tokens) {
255
+ const meta = metas.get(item.component);
256
+ if (meta?.presetTokens) {
257
+ for (const name of item.tokens) {
258
+ const tokenValue = meta.presetTokens[name];
259
+ if (tokenValue) {
260
+ const styleSourceId = `${item.component}:${name}`;
261
+ styleSourceIds.push(styleSourceId);
262
+ styleSources.push({
263
+ type: "token",
264
+ id: styleSourceId,
265
+ name: titleCase(noCase(name)),
266
+ });
267
+ for (const styleDecl of tokenValue.styles) {
268
+ styles.push({
269
+ breakpointId: defaultBreakpointId,
270
+ styleSourceId,
271
+ state: styleDecl.state,
272
+ property: styleDecl.property,
273
+ value: styleDecl.value,
274
+ });
275
+ }
276
+ }
277
+ }
278
+ }
279
+ }
280
+
246
281
  // populate styles
247
282
  if (item.styles) {
248
283
  const styleSourceId = nanoid();
@@ -250,10 +285,7 @@ const createInstancesFromTemplate = (
250
285
  type: "local",
251
286
  id: styleSourceId,
252
287
  });
253
- styleSourceSelections.push({
254
- instanceId,
255
- values: [styleSourceId],
256
- });
288
+ styleSourceIds.push(styleSourceId);
257
289
  for (const styleDecl of item.styles) {
258
290
  styles.push({
259
291
  breakpointId: defaultBreakpointId,
@@ -265,6 +297,13 @@ const createInstancesFromTemplate = (
265
297
  }
266
298
  }
267
299
 
300
+ if (styleSourceIds.length > 0) {
301
+ styleSourceSelections.push({
302
+ instanceId,
303
+ values: styleSourceIds,
304
+ });
305
+ }
306
+
268
307
  // populate instances
269
308
  const instance: Instance = {
270
309
  type: "instance",
@@ -283,6 +322,7 @@ const createInstancesFromTemplate = (
283
322
  styleSourceSelections,
284
323
  styleSources,
285
324
  styles,
325
+ metas,
286
326
  defaultBreakpointId
287
327
  );
288
328
  parentChildren.push({
@@ -303,6 +343,7 @@ const createInstancesFromTemplate = (
303
343
 
304
344
  export const generateDataFromEmbedTemplate = (
305
345
  treeTemplate: WsEmbedTemplate,
346
+ metas: Map<Instance["component"], WsComponentMeta>,
306
347
  defaultBreakpointId: Breakpoint["id"]
307
348
  ) => {
308
349
  const instances: InstancesList = [];
@@ -320,6 +361,7 @@ export const generateDataFromEmbedTemplate = (
320
361
  styleSourceSelections,
321
362
  styleSources,
322
363
  styles,
364
+ metas,
323
365
  defaultBreakpointId
324
366
  );
325
367
 
package/src/props.test.ts CHANGED
@@ -87,6 +87,24 @@ describe("resolveUrlProp", () => {
87
87
  value: unique(),
88
88
  };
89
89
 
90
+ const duplicatePropName = unique();
91
+
92
+ const duplicateUrlPropFirst: Prop = {
93
+ type: "string",
94
+ id: unique(),
95
+ instanceId,
96
+ name: duplicatePropName,
97
+ value: unique(),
98
+ };
99
+
100
+ const duplicateUrlPropSecond: Prop = {
101
+ type: "string",
102
+ id: unique(),
103
+ instanceId,
104
+ name: duplicatePropName,
105
+ value: unique(),
106
+ };
107
+
90
108
  const props: PropsByInstanceId = new Map([
91
109
  [
92
110
  instanceId,
@@ -96,6 +114,8 @@ describe("resolveUrlProp", () => {
96
114
  arbitraryUrlProp,
97
115
  assetProp,
98
116
  pageSectionProp,
117
+ duplicateUrlPropFirst,
118
+ duplicateUrlPropSecond,
99
119
  ],
100
120
  ],
101
121
  [instnaceIdProp.instanceId, [instnaceIdProp]],
@@ -156,4 +176,13 @@ describe("resolveUrlProp", () => {
156
176
  url: arbitraryUrlProp.value,
157
177
  });
158
178
  });
179
+
180
+ // We had a bug that some props were duplicated https://github.com/webstudio-is/webstudio-builder/pull/2170
181
+ // Use the latest prop to ensure consistency with the builder settings panel.
182
+ test("duplicate prop name", () => {
183
+ expect(resolveUrlProp(instanceId, duplicatePropName, stores)).toEqual({
184
+ type: "string",
185
+ url: duplicateUrlPropSecond.value,
186
+ });
187
+ });
159
188
  });