@webstudio-is/react-sdk 0.28.0 → 0.30.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 (123) hide show
  1. package/lib/app/custom-components/index.js +12 -6
  2. package/lib/app/custom-components/shared/remix-link.js +14 -8
  3. package/lib/app/root.js +0 -2
  4. package/lib/cjs/app/custom-components/index.cjs +12 -6
  5. package/lib/cjs/app/custom-components/shared/remix-link.cjs +14 -8
  6. package/lib/cjs/app/root.cjs +0 -2
  7. package/lib/cjs/components/__generated__/body.props.json +557 -305
  8. package/lib/cjs/components/__generated__/bold.props.json +557 -305
  9. package/lib/cjs/components/__generated__/box.props.json +577 -320
  10. package/lib/cjs/components/__generated__/button.props.json +616 -339
  11. package/lib/cjs/components/__generated__/form.props.json +597 -329
  12. package/lib/cjs/components/__generated__/heading.props.json +566 -309
  13. package/lib/cjs/components/__generated__/image.props.json +638 -352
  14. package/lib/cjs/components/__generated__/input.props.json +725 -405
  15. package/lib/cjs/components/__generated__/italic.props.json +557 -305
  16. package/lib/cjs/components/__generated__/link.props.json +616 -343
  17. package/lib/cjs/components/__generated__/paragraph.props.json +557 -305
  18. package/lib/cjs/components/__generated__/rich-text-link.props.json +616 -343
  19. package/lib/cjs/components/__generated__/span.props.json +557 -305
  20. package/lib/cjs/components/__generated__/subscript.props.json +557 -305
  21. package/lib/cjs/components/__generated__/superscript.props.json +557 -305
  22. package/lib/cjs/components/__generated__/text-block.props.json +557 -305
  23. package/lib/cjs/components/body.ws.cjs +6 -3
  24. package/lib/cjs/components/bold.ws.cjs +7 -4
  25. package/lib/cjs/components/box.ws.cjs +8 -4
  26. package/lib/cjs/components/button.ws.cjs +8 -4
  27. package/lib/cjs/components/component-type.cjs +21 -56
  28. package/lib/cjs/components/form.ws.cjs +7 -4
  29. package/lib/cjs/components/heading.ws.cjs +8 -4
  30. package/lib/cjs/components/image.ws.cjs +11 -5
  31. package/lib/cjs/components/index.cjs +165 -111
  32. package/lib/cjs/components/input.ws.cjs +7 -4
  33. package/lib/cjs/components/italic.ws.cjs +7 -4
  34. package/lib/cjs/components/link.ws.cjs +8 -4
  35. package/lib/cjs/components/paragraph.ws.cjs +7 -4
  36. package/lib/cjs/components/rich-text-link.ws.cjs +7 -4
  37. package/lib/cjs/components/span.ws.cjs +7 -4
  38. package/lib/cjs/components/subscript.ws.cjs +7 -4
  39. package/lib/cjs/components/superscript.ws.cjs +7 -4
  40. package/lib/cjs/components/text-block.ws.cjs +7 -4
  41. package/lib/cjs/index.cjs +3 -2
  42. package/lib/cjs/tree/session-storage-polyfill.cjs +1 -1
  43. package/lib/components/__generated__/body.props.json +557 -305
  44. package/lib/components/__generated__/bold.props.json +557 -305
  45. package/lib/components/__generated__/box.props.json +577 -320
  46. package/lib/components/__generated__/button.props.json +616 -339
  47. package/lib/components/__generated__/form.props.json +597 -329
  48. package/lib/components/__generated__/heading.props.json +566 -309
  49. package/lib/components/__generated__/image.props.json +638 -352
  50. package/lib/components/__generated__/input.props.json +725 -405
  51. package/lib/components/__generated__/italic.props.json +557 -305
  52. package/lib/components/__generated__/link.props.json +616 -343
  53. package/lib/components/__generated__/paragraph.props.json +557 -305
  54. package/lib/components/__generated__/rich-text-link.props.json +616 -343
  55. package/lib/components/__generated__/span.props.json +557 -305
  56. package/lib/components/__generated__/subscript.props.json +557 -305
  57. package/lib/components/__generated__/superscript.props.json +557 -305
  58. package/lib/components/__generated__/text-block.props.json +557 -305
  59. package/lib/components/body.ws.js +6 -3
  60. package/lib/components/bold.ws.js +7 -4
  61. package/lib/components/box.ws.js +8 -4
  62. package/lib/components/button.ws.js +8 -4
  63. package/lib/components/component-type.js +21 -56
  64. package/lib/components/form.ws.js +7 -4
  65. package/lib/components/heading.ws.js +8 -4
  66. package/lib/components/image.ws.js +11 -5
  67. package/lib/components/index.js +117 -57
  68. package/lib/components/input.ws.js +7 -4
  69. package/lib/components/italic.ws.js +7 -4
  70. package/lib/components/link.ws.js +8 -4
  71. package/lib/components/paragraph.ws.js +7 -4
  72. package/lib/components/rich-text-link.ws.js +7 -4
  73. package/lib/components/span.ws.js +7 -4
  74. package/lib/components/subscript.ws.js +7 -4
  75. package/lib/components/superscript.ws.js +7 -4
  76. package/lib/components/text-block.ws.js +7 -4
  77. package/lib/index.js +5 -3
  78. package/lib/tree/session-storage-polyfill.js +1 -1
  79. package/package.json +8 -8
  80. package/src/app/custom-components/image.tsx +2 -2
  81. package/src/app/custom-components/index.ts +11 -5
  82. package/src/app/custom-components/shared/remix-link.tsx +26 -7
  83. package/src/app/root.tsx +0 -2
  84. package/src/components/__generated__/body.props.json +557 -305
  85. package/src/components/__generated__/bold.props.json +557 -305
  86. package/src/components/__generated__/box.props.json +577 -320
  87. package/src/components/__generated__/button.props.json +616 -339
  88. package/src/components/__generated__/form.props.json +597 -329
  89. package/src/components/__generated__/heading.props.json +566 -309
  90. package/src/components/__generated__/image.props.json +638 -352
  91. package/src/components/__generated__/input.props.json +725 -405
  92. package/src/components/__generated__/italic.props.json +557 -305
  93. package/src/components/__generated__/link.props.json +616 -343
  94. package/src/components/__generated__/paragraph.props.json +557 -305
  95. package/src/components/__generated__/rich-text-link.props.json +616 -343
  96. package/src/components/__generated__/span.props.json +557 -305
  97. package/src/components/__generated__/subscript.props.json +557 -305
  98. package/src/components/__generated__/superscript.props.json +557 -305
  99. package/src/components/__generated__/text-block.props.json +557 -305
  100. package/src/components/body.ws.tsx +5 -4
  101. package/src/components/bold.ws.tsx +5 -4
  102. package/src/components/box.ws.ts +6 -4
  103. package/src/components/button.ws.tsx +6 -4
  104. package/src/components/component-type.ts +23 -63
  105. package/src/components/form.ws.tsx +5 -4
  106. package/src/components/heading.ws.tsx +6 -4
  107. package/src/components/image.ws.tsx +9 -5
  108. package/src/components/index.test.ts +2 -24
  109. package/src/components/index.ts +155 -81
  110. package/src/components/input.ws.tsx +5 -4
  111. package/src/components/italic.ws.tsx +5 -4
  112. package/src/components/link.ws.tsx +6 -4
  113. package/src/components/paragraph.ws.tsx +5 -4
  114. package/src/components/rich-text-link.ws.tsx +5 -4
  115. package/src/components/span.ws.tsx +5 -4
  116. package/src/components/subscript.ws.tsx +5 -4
  117. package/src/components/superscript.ws.tsx +5 -4
  118. package/src/components/text-block.ws.tsx +5 -4
  119. package/src/css/breakpoints.ts +1 -1
  120. package/src/index.ts +6 -2
  121. package/src/props.ts +1 -1
  122. package/src/tree/create-elements-tree.tsx +3 -3
  123. package/src/tree/session-storage-polyfill.tsx +1 -1
@@ -1,5 +1,5 @@
1
1
  import { BodyIcon } from "@webstudio-is/icons";
2
- import type { WsComponentMeta, MetaProps } from "./component-type";
2
+ import { type WsComponentMeta, WsComponentPropsMeta } from "./component-type";
3
3
  import props from "./__generated__/body.props.json";
4
4
 
5
5
  const presetStyle = {
@@ -52,12 +52,13 @@ const presetStyle = {
52
52
  },
53
53
  } as const;
54
54
 
55
- const meta: WsComponentMeta = {
55
+ export const meta: WsComponentMeta = {
56
56
  type: "body",
57
57
  label: "Body",
58
58
  Icon: BodyIcon,
59
- props: props as MetaProps,
60
59
  presetStyle,
61
60
  };
62
61
 
63
- export default meta;
62
+ export const propsMeta = WsComponentPropsMeta.parse({
63
+ props,
64
+ });
@@ -1,12 +1,13 @@
1
1
  import { FontBoldIcon } from "@webstudio-is/icons";
2
- import type { WsComponentMeta, MetaProps } from "./component-type";
2
+ import { type WsComponentMeta, WsComponentPropsMeta } from "./component-type";
3
3
  import props from "./__generated__/bold.props.json";
4
4
 
5
- const meta: WsComponentMeta = {
5
+ export const meta: WsComponentMeta = {
6
6
  type: "rich-text-child",
7
7
  label: "Bold Text",
8
8
  Icon: FontBoldIcon,
9
- props: props as MetaProps,
10
9
  };
11
10
 
12
- export default meta;
11
+ export const propsMeta = WsComponentPropsMeta.parse({
12
+ props,
13
+ });
@@ -1,5 +1,5 @@
1
1
  import { SquareIcon } from "@webstudio-is/icons";
2
- import type { WsComponentMeta, MetaProps } from "./component-type";
2
+ import { type WsComponentMeta, WsComponentPropsMeta } from "./component-type";
3
3
  import props from "./__generated__/box.props.json";
4
4
 
5
5
  const presetStyle = {
@@ -9,12 +9,14 @@ const presetStyle = {
9
9
  },
10
10
  } as const;
11
11
 
12
- const meta: WsComponentMeta = {
12
+ export const meta: WsComponentMeta = {
13
13
  type: "container",
14
14
  label: "Box",
15
15
  Icon: SquareIcon,
16
16
  presetStyle,
17
- props: props as MetaProps,
18
17
  };
19
18
 
20
- export default meta;
19
+ export const propsMeta = WsComponentPropsMeta.parse({
20
+ props,
21
+ initialProps: ["tag"],
22
+ });
@@ -1,13 +1,15 @@
1
1
  import { ButtonIcon } from "@webstudio-is/icons";
2
- import type { WsComponentMeta, MetaProps } from "./component-type";
2
+ import { type WsComponentMeta, WsComponentPropsMeta } from "./component-type";
3
3
  import props from "./__generated__/button.props.json";
4
4
 
5
- const meta: WsComponentMeta = {
5
+ export const meta: WsComponentMeta = {
6
6
  type: "rich-text",
7
7
  label: "Button",
8
8
  Icon: ButtonIcon,
9
9
  children: ["Button text you can edit"],
10
- props: props as MetaProps,
11
10
  };
12
11
 
13
- export default meta;
12
+ export const propsMeta = WsComponentPropsMeta.parse({
13
+ props,
14
+ initialProps: ["type"],
15
+ });
@@ -2,8 +2,16 @@ import { z } from "zod";
2
2
  import type { FunctionComponent } from "react";
3
3
  import type { IconProps } from "@webstudio-is/icons";
4
4
  import type { Style } from "@webstudio-is/css-data";
5
+ import { PropMeta } from "@webstudio-is/generate-arg-types";
5
6
 
6
- export type MetaProps = Partial<z.infer<typeof Props>>;
7
+ // props are separated from the rest of the meta
8
+ // so they can be exported separately and potentially tree-shaken
9
+ export const WsComponentPropsMeta = z.object({
10
+ props: z.record(PropMeta),
11
+ initialProps: z.array(z.string()).optional(),
12
+ });
13
+
14
+ export type WsComponentPropsMeta = z.infer<typeof WsComponentPropsMeta>;
7
15
 
8
16
  export type WsComponentMeta = {
9
17
  /**
@@ -25,67 +33,19 @@ export type WsComponentMeta = {
25
33
  Icon: FunctionComponent<IconProps>;
26
34
  presetStyle?: Style;
27
35
  children?: Array<string>;
28
- props: MetaProps;
29
- initialProps?: Array<string>;
30
36
  };
31
37
 
32
- const Props = z.record(
33
- z.union([
34
- z.object({
35
- type: z.literal("number"),
36
- required: z.boolean(),
37
- defaultValue: z.number().nullable(),
38
- }),
39
-
40
- z.object({
41
- type: z.literal("text"),
42
- required: z.boolean(),
43
- defaultValue: z.string().nullable(),
44
- }),
45
-
46
- z.object({
47
- type: z.literal("color"),
48
- required: z.boolean(),
49
- defaultValue: z.string().nullable(),
50
- }),
51
-
52
- z.object({
53
- type: z.literal("boolean"),
54
- required: z.boolean(),
55
- defaultValue: z.boolean().nullable(),
56
- }),
57
-
58
- z.object({
59
- type: z.enum([
60
- "radio",
61
- "inline-radio",
62
- "check",
63
- "inline-check",
64
- "multi-select",
65
- "select",
66
- ]),
67
- required: z.boolean(),
68
- options: z.array(z.string()),
69
- defaultValue: z.string().nullable(),
70
- }),
71
- ])
72
- );
73
-
74
- export const WsComponentMeta = z.lazy(() =>
75
- z.object({
76
- type: z.enum([
77
- "body",
78
- "container",
79
- "control",
80
- "embed",
81
- "rich-text",
82
- "rich-text-child",
83
- ]),
84
- label: z.string(),
85
- Icon: z.any(),
86
- presetStyle: z.optional(z.any()),
87
- children: z.optional(z.array(z.string())),
88
- props: Props,
89
- initialProps: z.optional(z.array(z.string())),
90
- })
91
- );
38
+ export const WsComponentMeta = z.object({
39
+ type: z.enum([
40
+ "body",
41
+ "container",
42
+ "control",
43
+ "embed",
44
+ "rich-text",
45
+ "rich-text-child",
46
+ ]),
47
+ label: z.string(),
48
+ Icon: z.any(),
49
+ presetStyle: z.optional(z.any()),
50
+ children: z.optional(z.array(z.string())),
51
+ });
@@ -1,5 +1,5 @@
1
1
  import { FormIcon } from "@webstudio-is/icons";
2
- import type { WsComponentMeta, MetaProps } from "./component-type";
2
+ import { type WsComponentMeta, WsComponentPropsMeta } from "./component-type";
3
3
  import props from "./__generated__/form.props.json";
4
4
 
5
5
  const presetStyle = {
@@ -14,12 +14,13 @@ const presetStyle = {
14
14
  },
15
15
  } as const;
16
16
 
17
- const meta: WsComponentMeta = {
17
+ export const meta: WsComponentMeta = {
18
18
  type: "container",
19
19
  label: "Form",
20
20
  Icon: FormIcon,
21
21
  presetStyle,
22
- props: props as MetaProps,
23
22
  };
24
23
 
25
- export default meta;
24
+ export const propsMeta = WsComponentPropsMeta.parse({
25
+ props,
26
+ });
@@ -1,13 +1,15 @@
1
1
  import { HeadingIcon } from "@webstudio-is/icons";
2
- import type { WsComponentMeta, MetaProps } from "./component-type";
2
+ import { type WsComponentMeta, WsComponentPropsMeta } from "./component-type";
3
3
  import props from "./__generated__/heading.props.json";
4
4
 
5
- const meta: WsComponentMeta = {
5
+ export const meta: WsComponentMeta = {
6
6
  type: "rich-text",
7
7
  label: "Heading",
8
8
  Icon: HeadingIcon,
9
9
  children: ["Heading you can edit"],
10
- props: props as MetaProps,
11
10
  };
12
11
 
13
- export default meta;
12
+ export const propsMeta = WsComponentPropsMeta.parse({
13
+ props,
14
+ initialProps: ["tag"],
15
+ });
@@ -1,5 +1,5 @@
1
1
  import { ImageIcon } from "@webstudio-is/icons";
2
- import type { WsComponentMeta, MetaProps } from "./component-type";
2
+ import { type WsComponentMeta, WsComponentPropsMeta } from "./component-type";
3
3
  import props from "./__generated__/image.props.json";
4
4
 
5
5
  const presetStyle = {
@@ -17,13 +17,17 @@ const presetStyle = {
17
17
  },
18
18
  } as const;
19
19
 
20
- const meta: WsComponentMeta = {
20
+ export const meta: WsComponentMeta = {
21
21
  type: "embed",
22
22
  label: "Image",
23
23
  Icon: ImageIcon,
24
24
  presetStyle,
25
- props: props as MetaProps,
26
- initialProps: ["src", "width", "height", "alt", "loading"],
27
25
  };
28
26
 
29
- export default meta;
27
+ export const propsMeta = WsComponentPropsMeta.parse({
28
+ props: {
29
+ ...props,
30
+ src: { ...props.src, control: "file-image", name: "Source" },
31
+ },
32
+ initialProps: ["src", "width", "height", "alt", "loading"],
33
+ });
@@ -1,29 +1,7 @@
1
- import { test, expect } from "@jest/globals";
2
- import {
3
- getComponentNames,
4
- getComponentMeta,
5
- getComponentMetaProps,
6
- registerComponentsMeta,
7
- } from "./index";
1
+ import { test } from "@jest/globals";
2
+ import { getComponentNames, getComponentMeta } from "./index";
8
3
  import { WsComponentMeta } from "./component-type";
9
4
 
10
5
  test.each(getComponentNames())("validating meta definition of %s", (name) => {
11
6
  WsComponentMeta.parse(getComponentMeta(name));
12
7
  });
13
-
14
- test("defaultValue will be used from Native Component", () => {
15
- registerComponentsMeta({
16
- Image: {
17
- props: {
18
- src: {
19
- defaultValue: null,
20
- required: false,
21
- type: "text",
22
- },
23
- },
24
- },
25
- });
26
-
27
- const props = getComponentMetaProps("Image");
28
- expect(props?.src?.defaultValue).toEqual("");
29
- });
@@ -1,19 +1,40 @@
1
- import BodyMeta from "./body.ws";
2
- import BoxMeta from "./box.ws";
3
- import TextBlockMeta from "./text-block.ws";
4
- import HeadingMeta from "./heading.ws";
5
- import ParagraphMeta from "./paragraph.ws";
6
- import LinkMeta from "./link.ws";
7
- import RichTextLinkMeta from "./rich-text-link.ws";
8
- import SpanMeta from "./span.ws";
9
- import BoldMeta from "./bold.ws";
10
- import ItalicMeta from "./italic.ws";
11
- import SuperscriptMeta from "./superscript.ws";
12
- import SubscriptMeta from "./subscript.ws";
13
- import ButtonMeta from "./button.ws";
14
- import InputMeta from "./input.ws";
15
- import FormMeta from "./form.ws";
16
- import ImageMeta from "./image.ws";
1
+ import { PropMeta } from "@webstudio-is/generate-arg-types";
2
+ import type { WsComponentMeta, WsComponentPropsMeta } from "./component-type";
3
+
4
+ import { meta as BodyMeta } from "./body.ws";
5
+ import { meta as BoxMeta } from "./box.ws";
6
+ import { meta as TextBlockMeta } from "./text-block.ws";
7
+ import { meta as HeadingMeta } from "./heading.ws";
8
+ import { meta as ParagraphMeta } from "./paragraph.ws";
9
+ import { meta as LinkMeta } from "./link.ws";
10
+ import { meta as RichTextLinkMeta } from "./rich-text-link.ws";
11
+ import { meta as SpanMeta } from "./span.ws";
12
+ import { meta as BoldMeta } from "./bold.ws";
13
+ import { meta as ItalicMeta } from "./italic.ws";
14
+ import { meta as SuperscriptMeta } from "./superscript.ws";
15
+ import { meta as SubscriptMeta } from "./subscript.ws";
16
+ import { meta as ButtonMeta } from "./button.ws";
17
+ import { meta as InputMeta } from "./input.ws";
18
+ import { meta as FormMeta } from "./form.ws";
19
+ import { meta as ImageMeta } from "./image.ws";
20
+
21
+ // these are huge JSON objects that we want to be tree-shaken when not used!
22
+ import { propsMeta as BodyMetaPropsMeta } from "./body.ws";
23
+ import { propsMeta as BoxMetaPropsMeta } from "./box.ws";
24
+ import { propsMeta as TextBlockMetaPropsMeta } from "./text-block.ws";
25
+ import { propsMeta as HeadingMetaPropsMeta } from "./heading.ws";
26
+ import { propsMeta as ParagraphMetaPropsMeta } from "./paragraph.ws";
27
+ import { propsMeta as LinkMetaPropsMeta } from "./link.ws";
28
+ import { propsMeta as RichTextLinkMetaPropsMeta } from "./rich-text-link.ws";
29
+ import { propsMeta as SpanMetaPropsMeta } from "./span.ws";
30
+ import { propsMeta as BoldMetaPropsMeta } from "./bold.ws";
31
+ import { propsMeta as ItalicMetaPropsMeta } from "./italic.ws";
32
+ import { propsMeta as SuperscriptMetaPropsMeta } from "./superscript.ws";
33
+ import { propsMeta as SubscriptMetaPropsMeta } from "./subscript.ws";
34
+ import { propsMeta as ButtonMetaPropsMeta } from "./button.ws";
35
+ import { propsMeta as InputMetaPropsMeta } from "./input.ws";
36
+ import { propsMeta as FormMetaPropsMeta } from "./form.ws";
37
+ import { propsMeta as ImageMetaPropsMeta } from "./image.ws";
17
38
 
18
39
  import { Body } from "./body";
19
40
  import { Box } from "./box";
@@ -32,9 +53,7 @@ import { Input } from "./input";
32
53
  import { Form } from "./form";
33
54
  import { Image } from "./image";
34
55
 
35
- import type { WsComponentMeta, MetaProps } from "./component-type";
36
-
37
- const meta = {
56
+ const defaultMetas: Record<string, WsComponentMeta> = {
38
57
  Box: BoxMeta,
39
58
  Body: BodyMeta,
40
59
  TextBlock: TextBlockMeta,
@@ -51,9 +70,79 @@ const meta = {
51
70
  Input: InputMeta,
52
71
  Form: FormMeta,
53
72
  Image: ImageMeta,
54
- } as const;
73
+ };
74
+
75
+ let currentMetas = defaultMetas;
76
+
77
+ export const getComponentMeta = (name: string): WsComponentMeta | undefined => {
78
+ return currentMetas[name];
79
+ };
80
+
81
+ export const registerComponentMetas = (
82
+ overrides: Record<string, Partial<WsComponentMeta>>
83
+ ) => {
84
+ const result: typeof currentMetas = {};
85
+ for (const name of Object.keys(defaultMetas)) {
86
+ result[name] = { ...defaultMetas[name], ...overrides[name] };
87
+ }
88
+ currentMetas = result;
89
+ };
90
+
91
+ const defaultPropsMetas: Record<string, WsComponentPropsMeta> = {
92
+ Box: BoxMetaPropsMeta,
93
+ Body: BodyMetaPropsMeta,
94
+ TextBlock: TextBlockMetaPropsMeta,
95
+ Heading: HeadingMetaPropsMeta,
96
+ Paragraph: ParagraphMetaPropsMeta,
97
+ Link: LinkMetaPropsMeta,
98
+ RichTextLink: RichTextLinkMetaPropsMeta,
99
+ Span: SpanMetaPropsMeta,
100
+ Bold: BoldMetaPropsMeta,
101
+ Italic: ItalicMetaPropsMeta,
102
+ Superscript: SuperscriptMetaPropsMeta,
103
+ Subscript: SubscriptMetaPropsMeta,
104
+ Button: ButtonMetaPropsMeta,
105
+ Input: InputMetaPropsMeta,
106
+ Form: FormMetaPropsMeta,
107
+ Image: ImageMetaPropsMeta,
108
+ };
109
+
110
+ let registeredPropsMetas: Record<string, Partial<WsComponentPropsMeta>> = {};
111
+
112
+ // we start as `undefined` because pre-computing will likely kill tree-shaking
113
+ let currentPropsMetas: Record<string, WsComponentPropsMeta> | undefined =
114
+ undefined;
115
+
116
+ export const getComponentPropsMeta = (
117
+ name: string
118
+ ): WsComponentPropsMeta | undefined => {
119
+ if (currentPropsMetas === undefined) {
120
+ currentPropsMetas = {};
121
+ for (const name of Object.keys(defaultPropsMetas)) {
122
+ const props = computeProps(
123
+ defaultPropsMetas[name],
124
+ registeredPropsMetas[name] ?? {}
125
+ );
126
+ const initialProps = computeInitialProps(
127
+ props,
128
+ defaultPropsMetas[name],
129
+ registeredPropsMetas[name] ?? {}
130
+ );
131
+ currentPropsMetas[name] = { props, initialProps };
132
+ }
133
+ }
134
+
135
+ return currentPropsMetas[name];
136
+ };
55
137
 
56
- const components = {
138
+ export const registerComponentPropsMetas = (
139
+ metas: Record<string, WsComponentPropsMeta>
140
+ ) => {
141
+ registeredPropsMetas = metas;
142
+ currentPropsMetas = undefined;
143
+ };
144
+
145
+ const defaultComponents = {
57
146
  Box,
58
147
  Body,
59
148
  TextBlock,
@@ -72,20 +161,15 @@ const components = {
72
161
  Image,
73
162
  } as const;
74
163
 
75
- export type ComponentName = keyof typeof components;
164
+ export type ComponentName = keyof typeof defaultComponents;
76
165
  type RegisteredComponents = Partial<{
77
166
  // eslint-disable-next-line @typescript-eslint/ban-types
78
- [p in ComponentName]: {};
79
- }>;
80
-
81
- type RegisteredComponentsMeta = Partial<{
82
- [p in ComponentName]: Partial<WsComponentMeta>;
167
+ [name in ComponentName]: {};
83
168
  }>;
84
169
 
85
170
  let registeredComponents: RegisteredComponents | null = null;
86
- let registeredComponentsMeta: RegisteredComponentsMeta | null = null;
87
171
 
88
- const componentNames = Object.keys(components) as ComponentName[];
172
+ const componentNames = Object.keys(defaultComponents) as ComponentName[];
89
173
 
90
174
  export const getComponentNames = (): ComponentName[] => {
91
175
  const uniqueNames = new Set([
@@ -96,60 +180,14 @@ export const getComponentNames = (): ComponentName[] => {
96
180
  return [...uniqueNames.values()] as ComponentName[];
97
181
  };
98
182
 
99
- export const getComponentMeta = (name: string): undefined | WsComponentMeta => {
100
- const componentMeta = meta[name as ComponentName];
101
- if (registeredComponentsMeta != null && name in registeredComponentsMeta) {
102
- return {
103
- ...componentMeta,
104
- ...registeredComponentsMeta[name as ComponentName],
105
- };
106
- }
107
-
108
- return componentMeta;
109
- };
110
-
111
183
  export const getComponent = (
112
184
  name: string
113
- ): undefined | typeof components[ComponentName] => {
185
+ ): undefined | typeof defaultComponents[ComponentName] => {
114
186
  return registeredComponents != null && name in registeredComponents
115
187
  ? (registeredComponents[
116
188
  name as ComponentName
117
- ] as typeof components[ComponentName])
118
- : components[name as ComponentName];
119
- };
120
-
121
- export const getComponentMetaProps = (name: string): undefined | MetaProps => {
122
- const componentMeta = meta[name as ComponentName];
123
- if (registeredComponentsMeta != null && name in registeredComponentsMeta) {
124
- const registeredComponentMeta =
125
- registeredComponentsMeta[name as ComponentName];
126
- const allMetaPropKeys = new Set([
127
- ...Object.keys(componentMeta?.props ?? {}),
128
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
129
- ...Object.keys(registeredComponentMeta!.props!),
130
- ]);
131
-
132
- const props: MetaProps = {};
133
- /**
134
- * Merge props, taking non null defaultValue and required=true from meta
135
- **/
136
- for (const key of allMetaPropKeys.values()) {
137
- props[key] = {
138
- ...componentMeta?.props[key],
139
- ...registeredComponentMeta?.props?.[key],
140
- defaultValue:
141
- registeredComponentMeta?.props?.[key]?.defaultValue ??
142
- componentMeta?.props[key]?.defaultValue ??
143
- null,
144
- required:
145
- registeredComponentMeta?.props?.[key]?.required ||
146
- componentMeta?.props[key]?.required,
147
- } as MetaProps[string];
148
- }
149
- return props;
150
- }
151
-
152
- return componentMeta?.props;
189
+ ] as typeof defaultComponents[ComponentName])
190
+ : defaultComponents[name as ComponentName];
153
191
  };
154
192
 
155
193
  /**
@@ -161,8 +199,44 @@ export const registerComponents = (components: RegisteredComponents) => {
161
199
  registeredComponents = components;
162
200
  };
163
201
 
164
- export const registerComponentsMeta = (
165
- componentsMeta: RegisteredComponentsMeta
202
+ const computeProps = (
203
+ defaults: WsComponentPropsMeta,
204
+ overrides: Partial<WsComponentPropsMeta>
166
205
  ) => {
167
- registeredComponentsMeta = componentsMeta;
206
+ if (overrides) {
207
+ const allNames = new Set([
208
+ ...Object.keys(defaults.props ?? {}),
209
+ ...Object.keys(overrides?.props ?? {}),
210
+ ]).values();
211
+
212
+ const result: WsComponentPropsMeta["props"] = {};
213
+ for (const name of allNames) {
214
+ result[name] = PropMeta.parse({
215
+ ...defaults.props[name],
216
+ ...overrides?.props?.[name],
217
+ });
218
+ }
219
+ return result;
220
+ }
221
+
222
+ return defaults.props;
223
+ };
224
+
225
+ const computeInitialProps = (
226
+ props: WsComponentPropsMeta["props"],
227
+ defaults: WsComponentPropsMeta,
228
+ overrides: Partial<WsComponentPropsMeta>
229
+ ): Array<string> => {
230
+ const initialProps = overrides?.initialProps ?? defaults?.initialProps ?? [];
231
+ const requiredProps = props
232
+ ? Object.entries(props)
233
+ .filter(
234
+ ([name, value]) =>
235
+ value?.type.required && initialProps.includes(name) === false
236
+ )
237
+ .map(([name]) => name)
238
+ : [];
239
+
240
+ // order of initialProps must be preserved
241
+ return [...initialProps, ...requiredProps];
168
242
  };
@@ -1,12 +1,13 @@
1
1
  import { InputIcon } from "@webstudio-is/icons";
2
- import type { WsComponentMeta, MetaProps } from "./component-type";
2
+ import { type WsComponentMeta, WsComponentPropsMeta } from "./component-type";
3
3
  import props from "./__generated__/input.props.json";
4
4
 
5
- const meta: WsComponentMeta = {
5
+ export const meta: WsComponentMeta = {
6
6
  type: "control",
7
7
  label: "Input",
8
8
  Icon: InputIcon,
9
- props: props as MetaProps,
10
9
  };
11
10
 
12
- export default meta;
11
+ export const propsMeta = WsComponentPropsMeta.parse({
12
+ props,
13
+ });
@@ -1,5 +1,5 @@
1
1
  import { FontItalicIcon } from "@webstudio-is/icons";
2
- import type { WsComponentMeta, MetaProps } from "./component-type";
2
+ import { type WsComponentMeta, WsComponentPropsMeta } from "./component-type";
3
3
  import props from "./__generated__/italic.props.json";
4
4
 
5
5
  const presetStyle = {
@@ -9,12 +9,13 @@ const presetStyle = {
9
9
  },
10
10
  } as const;
11
11
 
12
- const meta: WsComponentMeta = {
12
+ export const meta: WsComponentMeta = {
13
13
  type: "rich-text-child",
14
14
  label: "Italic Text",
15
15
  Icon: FontItalicIcon,
16
16
  presetStyle,
17
- props: props as MetaProps,
18
17
  };
19
18
 
20
- export default meta;
19
+ export const propsMeta = WsComponentPropsMeta.parse({
20
+ props,
21
+ });
@@ -1,5 +1,5 @@
1
1
  import { Link2Icon } from "@webstudio-is/icons";
2
- import type { WsComponentMeta, MetaProps } from "./component-type";
2
+ import { type WsComponentMeta, WsComponentPropsMeta } from "./component-type";
3
3
  import props from "./__generated__/link.props.json";
4
4
 
5
5
  const presetStyle = {
@@ -14,13 +14,15 @@ const presetStyle = {
14
14
  },
15
15
  } as const;
16
16
 
17
- const meta: WsComponentMeta = {
17
+ export const meta: WsComponentMeta = {
18
18
  type: "rich-text",
19
19
  label: "Link",
20
20
  Icon: Link2Icon,
21
21
  presetStyle,
22
22
  children: ["Link text you can edit"],
23
- props: props as MetaProps,
24
23
  };
25
24
 
26
- export default meta;
25
+ export const propsMeta = WsComponentPropsMeta.parse({
26
+ props,
27
+ initialProps: ["href"],
28
+ });
@@ -1,13 +1,14 @@
1
1
  import { TextAlignLeftIcon } from "@webstudio-is/icons";
2
- import type { WsComponentMeta, MetaProps } from "./component-type";
2
+ import { type WsComponentMeta, WsComponentPropsMeta } from "./component-type";
3
3
  import props from "./__generated__/paragraph.props.json";
4
4
 
5
- const meta: WsComponentMeta = {
5
+ export const meta: WsComponentMeta = {
6
6
  type: "rich-text",
7
7
  label: "Paragraph",
8
8
  Icon: TextAlignLeftIcon,
9
9
  children: ["Pragraph you can edit"],
10
- props: props as MetaProps,
11
10
  };
12
11
 
13
- export default meta;
12
+ export const propsMeta = WsComponentPropsMeta.parse({
13
+ props,
14
+ });