@webstudio-is/react-sdk 0.68.0 → 0.69.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 (184) hide show
  1. package/lib/cjs/components/__generated__/image.props.js +6 -3
  2. package/lib/cjs/components/__generated__/text-block.props.js +7 -0
  3. package/lib/cjs/components/blockquote.ws.js +9 -2
  4. package/lib/cjs/components/box.ws.js +2 -1
  5. package/lib/cjs/components/button.ws.js +3 -1
  6. package/lib/cjs/components/checkbox-field.ws.js +12 -6
  7. package/lib/cjs/components/checkbox.ws.js +1 -0
  8. package/lib/cjs/components/code-text.ws.js +8 -1
  9. package/lib/cjs/components/component-meta.js +6 -3
  10. package/lib/cjs/components/components-utils.js +0 -28
  11. package/lib/cjs/components/form.ws.js +32 -25
  12. package/lib/cjs/components/fragment.ws.js +2 -1
  13. package/lib/cjs/components/heading.ws.js +10 -3
  14. package/lib/cjs/components/html-embed.ws.js +3 -1
  15. package/lib/cjs/components/image.js +27 -19
  16. package/lib/cjs/components/image.ws.js +4 -2
  17. package/lib/cjs/components/index.js +1 -29
  18. package/lib/cjs/components/input.ws.js +1 -0
  19. package/lib/cjs/components/label.ws.js +8 -1
  20. package/lib/cjs/components/link-block.ws.js +2 -1
  21. package/lib/cjs/components/link.ws.js +8 -1
  22. package/lib/cjs/components/list-item.ws.js +11 -4
  23. package/lib/cjs/components/list.ws.js +2 -2
  24. package/lib/cjs/components/paragraph.ws.js +10 -3
  25. package/lib/cjs/components/radio-button-field.ws.js +12 -6
  26. package/lib/cjs/components/radio-button.ws.js +1 -0
  27. package/lib/cjs/components/rich-text-link.ws.js +1 -1
  28. package/lib/cjs/components/separator.ws.js +1 -1
  29. package/lib/cjs/components/slot.ws.js +3 -1
  30. package/lib/cjs/components/text-block.js +5 -2
  31. package/lib/cjs/components/text-block.ws.js +11 -3
  32. package/lib/cjs/components/textarea.ws.js +1 -0
  33. package/lib/cjs/embed-template.js +2 -1
  34. package/lib/cjs/index.js +4 -5
  35. package/lib/cjs/tree/create-elements-tree.js +8 -8
  36. package/lib/cjs/tree/root.js +2 -6
  37. package/lib/cjs/tree/webstudio-component.js +2 -2
  38. package/lib/components/__generated__/image.props.js +6 -3
  39. package/lib/components/__generated__/text-block.props.js +7 -0
  40. package/lib/components/blockquote.ws.js +9 -2
  41. package/lib/components/box.ws.js +2 -1
  42. package/lib/components/button.ws.js +3 -1
  43. package/lib/components/checkbox-field.ws.js +12 -6
  44. package/lib/components/checkbox.ws.js +1 -0
  45. package/lib/components/code-text.ws.js +8 -1
  46. package/lib/components/component-meta.js +6 -3
  47. package/lib/components/components-utils.js +0 -14
  48. package/lib/components/form.ws.js +32 -25
  49. package/lib/components/fragment.ws.js +2 -1
  50. package/lib/components/heading.ws.js +10 -3
  51. package/lib/components/html-embed.ws.js +3 -1
  52. package/lib/components/image.js +34 -20
  53. package/lib/components/image.ws.js +4 -2
  54. package/lib/components/index.js +1 -29
  55. package/lib/components/input.ws.js +1 -0
  56. package/lib/components/label.ws.js +8 -1
  57. package/lib/components/link-block.ws.js +2 -1
  58. package/lib/components/link.ws.js +8 -1
  59. package/lib/components/list-item.ws.js +11 -4
  60. package/lib/components/list.ws.js +2 -2
  61. package/lib/components/paragraph.ws.js +10 -3
  62. package/lib/components/radio-button-field.ws.js +12 -6
  63. package/lib/components/radio-button.ws.js +1 -0
  64. package/lib/components/rich-text-link.ws.js +1 -1
  65. package/lib/components/separator.ws.js +1 -1
  66. package/lib/components/slot.ws.js +3 -1
  67. package/lib/components/text-block.js +9 -3
  68. package/lib/components/text-block.ws.js +11 -3
  69. package/lib/components/textarea.ws.js +1 -0
  70. package/lib/embed-template.js +2 -1
  71. package/lib/index.js +4 -9
  72. package/lib/tree/create-elements-tree.js +8 -8
  73. package/lib/tree/root.js +2 -6
  74. package/lib/tree/webstudio-component.js +2 -2
  75. package/lib/types/components/component-meta.d.ts +363 -1356
  76. package/lib/types/components/components-utils.d.ts +2 -17
  77. package/lib/types/components/image.d.ts +5 -1
  78. package/lib/types/components/image.stories.d.ts +10 -2
  79. package/lib/types/components/index.d.ts +0 -15
  80. package/lib/types/components/text-block.d.ts +6 -2
  81. package/lib/types/components/text-block.stories.d.ts +6 -2
  82. package/lib/types/css/css.d.ts +14 -4
  83. package/lib/types/css/global-rules.d.ts +14 -4
  84. package/lib/types/css/normalize.d.ts +611 -611
  85. package/lib/types/css/style-rules.d.ts +2 -187
  86. package/lib/types/embed-template.d.ts +543 -167
  87. package/lib/types/index.d.ts +2 -2
  88. package/lib/types/props.d.ts +44 -18
  89. package/lib/types/tree/create-elements-tree.d.ts +4 -4
  90. package/lib/types/tree/root.d.ts +3 -5
  91. package/lib/types/tree/webstudio-component.d.ts +3 -3
  92. package/package.json +24 -13
  93. package/src/components/__generated__/image.props.ts +5 -2
  94. package/src/components/__generated__/text-block.props.ts +7 -0
  95. package/src/components/blockquote.ws.tsx +9 -2
  96. package/src/components/box.tsx +1 -1
  97. package/src/components/box.ws.ts +1 -0
  98. package/src/components/button.ws.tsx +2 -0
  99. package/src/components/checkbox-field.ws.tsx +12 -6
  100. package/src/components/checkbox.ws.tsx +1 -0
  101. package/src/components/code-text.ws.tsx +8 -1
  102. package/src/components/component-meta.ts +6 -3
  103. package/src/components/components-utils.ts +2 -31
  104. package/src/components/form.ws.tsx +32 -25
  105. package/src/components/fragment.ws.ts +1 -0
  106. package/src/components/heading.tsx +1 -1
  107. package/src/components/heading.ws.tsx +9 -2
  108. package/src/components/html-embed.ws.ts +2 -0
  109. package/src/components/image.tsx +54 -26
  110. package/src/components/image.ws.tsx +5 -1
  111. package/src/components/index.ts +0 -48
  112. package/src/components/input.ws.tsx +1 -0
  113. package/src/components/label.ws.tsx +8 -1
  114. package/src/components/link-block.ws.tsx +1 -0
  115. package/src/components/link.ws.tsx +8 -1
  116. package/src/components/list-item.ws.tsx +10 -3
  117. package/src/components/list.ws.tsx +2 -2
  118. package/src/components/paragraph.ws.tsx +9 -2
  119. package/src/components/radio-button-field.ws.tsx +12 -6
  120. package/src/components/radio-button.ws.tsx +1 -0
  121. package/src/components/rich-text-link.ws.tsx +1 -1
  122. package/src/components/separator.ws.tsx +1 -1
  123. package/src/components/slot.ws.ts +2 -0
  124. package/src/components/text-block.tsx +16 -5
  125. package/src/components/text-block.ws.tsx +10 -2
  126. package/src/components/textarea.ws.tsx +1 -0
  127. package/src/embed-template.ts +11 -3
  128. package/src/index.ts +2 -5
  129. package/src/props.test.ts +0 -1
  130. package/src/tree/create-elements-tree.tsx +12 -12
  131. package/src/tree/root.ts +4 -9
  132. package/src/tree/webstudio-component.tsx +4 -4
  133. package/lib/app/custom-components/__generated__/form.props.js +0 -411
  134. package/lib/app/custom-components/__generated__/image.props.js +0 -442
  135. package/lib/app/custom-components/__generated__/link-block.props.js +0 -432
  136. package/lib/app/custom-components/__generated__/link.props.js +0 -432
  137. package/lib/app/custom-components/__generated__/rich-text-link.props.js +0 -432
  138. package/lib/app/custom-components/form.js +0 -65
  139. package/lib/app/custom-components/form.ws.js +0 -81
  140. package/lib/app/custom-components/image.js +0 -40
  141. package/lib/app/custom-components/index.js +0 -29
  142. package/lib/app/custom-components/link-block.js +0 -6
  143. package/lib/app/custom-components/link.js +0 -6
  144. package/lib/app/custom-components/rich-text-link.js +0 -6
  145. package/lib/app/custom-components/shared/remix-link.js +0 -22
  146. package/lib/cjs/app/custom-components/__generated__/form.props.js +0 -431
  147. package/lib/cjs/app/custom-components/__generated__/image.props.js +0 -462
  148. package/lib/cjs/app/custom-components/__generated__/link-block.props.js +0 -452
  149. package/lib/cjs/app/custom-components/__generated__/link.props.js +0 -452
  150. package/lib/cjs/app/custom-components/__generated__/rich-text-link.props.js +0 -452
  151. package/lib/cjs/app/custom-components/form.js +0 -81
  152. package/lib/cjs/app/custom-components/form.ws.js +0 -101
  153. package/lib/cjs/app/custom-components/image.js +0 -54
  154. package/lib/cjs/app/custom-components/index.js +0 -49
  155. package/lib/cjs/app/custom-components/link-block.js +0 -26
  156. package/lib/cjs/app/custom-components/link.js +0 -26
  157. package/lib/cjs/app/custom-components/rich-text-link.js +0 -26
  158. package/lib/cjs/app/custom-components/shared/remix-link.js +0 -42
  159. package/lib/types/app/custom-components/__generated__/form.props.d.ts +0 -2
  160. package/lib/types/app/custom-components/__generated__/image.props.d.ts +0 -2
  161. package/lib/types/app/custom-components/__generated__/link-block.props.d.ts +0 -2
  162. package/lib/types/app/custom-components/__generated__/link.props.d.ts +0 -2
  163. package/lib/types/app/custom-components/__generated__/rich-text-link.props.d.ts +0 -2
  164. package/lib/types/app/custom-components/form.d.ts +0 -5
  165. package/lib/types/app/custom-components/form.ws.d.ts +0 -3
  166. package/lib/types/app/custom-components/image.d.ts +0 -6
  167. package/lib/types/app/custom-components/index.d.ts +0 -31
  168. package/lib/types/app/custom-components/link-block.d.ts +0 -6
  169. package/lib/types/app/custom-components/link.d.ts +0 -6
  170. package/lib/types/app/custom-components/rich-text-link.d.ts +0 -6
  171. package/lib/types/app/custom-components/shared/remix-link.d.ts +0 -10
  172. package/src/app/custom-components/__generated__/form.props.ts +0 -456
  173. package/src/app/custom-components/__generated__/image.props.ts +0 -487
  174. package/src/app/custom-components/__generated__/link-block.props.ts +0 -477
  175. package/src/app/custom-components/__generated__/link.props.ts +0 -477
  176. package/src/app/custom-components/__generated__/rich-text-link.props.ts +0 -477
  177. package/src/app/custom-components/form.tsx +0 -111
  178. package/src/app/custom-components/form.ws.tsx +0 -86
  179. package/src/app/custom-components/image.tsx +0 -55
  180. package/src/app/custom-components/index.ts +0 -28
  181. package/src/app/custom-components/link-block.tsx +0 -4
  182. package/src/app/custom-components/link.tsx +0 -4
  183. package/src/app/custom-components/rich-text-link.tsx +0 -4
  184. package/src/app/custom-components/shared/remix-link.tsx +0 -28
@@ -1,32 +1,18 @@
1
- import { forwardRef, type ElementRef, type ComponentProps } from "react";
1
+ import {
2
+ type ComponentPropsWithoutRef,
3
+ type ElementRef,
4
+ forwardRef,
5
+ useMemo,
6
+ } from "react";
7
+ import {
8
+ Image as WebstudioImage,
9
+ createImageLoader,
10
+ } from "@webstudio-is/image";
11
+ import { usePropAsset, getInstanceIdFromComponentProps } from "../props";
12
+ import { getParams } from "../app/params";
2
13
 
3
14
  export const defaultTag = "img";
4
15
 
5
- // quality and optimize can be overwritten and used by asset transform
6
- // Or we need and additional way to pass them upper level
7
- type ImageProps = ComponentProps<typeof defaultTag>;
8
-
9
- export const Image = forwardRef<ElementRef<typeof defaultTag>, ImageProps>(
10
- (imageProps, ref) => {
11
- return (
12
- <img
13
- {...imageProps}
14
- src={imageProps.src || imagePlaceholderSvg}
15
- ref={ref}
16
- />
17
- );
18
- }
19
- );
20
-
21
- Image.defaultProps = {
22
- src: "",
23
- width: "",
24
- height: "",
25
- alt: "",
26
- };
27
-
28
- Image.displayName = "Image";
29
-
30
16
  const imagePlaceholderSvg = `data:image/svg+xml;base64,${btoa(`<svg
31
17
  width="140"
32
18
  height="140"
@@ -50,3 +36,45 @@ const imagePlaceholderSvg = `data:image/svg+xml;base64,${btoa(`<svg
50
36
  fill="#A2A2A2"
51
37
  />
52
38
  </svg>`)}`;
39
+
40
+ type Props = ComponentPropsWithoutRef<typeof WebstudioImage>;
41
+
42
+ export const Image = forwardRef<ElementRef<typeof defaultTag>, Props>(
43
+ (props, ref) => {
44
+ const asset = usePropAsset(getInstanceIdFromComponentProps(props), "src");
45
+
46
+ const loader = useMemo(() => {
47
+ const params = getParams();
48
+ return createImageLoader({ imageBaseUrl: params.imageBaseUrl });
49
+ }, []);
50
+
51
+ const src = asset?.name ?? props.src;
52
+
53
+ if (asset == null || loader == null) {
54
+ return (
55
+ <img key={src} {...props} src={src || imagePlaceholderSvg} ref={ref} />
56
+ );
57
+ }
58
+
59
+ return (
60
+ <WebstudioImage
61
+ /**
62
+ * `key` is needed to recreate the image in case of asset change in builder,
63
+ * this gives immediate feedback when an asset is changed.
64
+ * Also, it visually fixes image distortion when another asset has a seriously different aspectRatio
65
+ * (we change aspectRatio CSS prop on asset change)
66
+ *
67
+ * In non-builder mode, key on images are usually also a good idea,
68
+ * prevents showing outdated images on route change.
69
+ **/
70
+ key={src}
71
+ {...props}
72
+ loader={loader}
73
+ src={src}
74
+ ref={ref}
75
+ />
76
+ );
77
+ }
78
+ );
79
+
80
+ Image.displayName = "Image";
@@ -34,11 +34,15 @@ export const meta: WsComponentMeta = {
34
34
  icon: ImageIcon,
35
35
  states: defaultStates,
36
36
  presetStyle,
37
+ order: 0,
37
38
  };
38
39
 
40
+ // "loader" is our internal prop not intended to show up in the props panel
41
+ const { loader, ...publicProps } = props;
42
+
39
43
  export const propsMeta: WsComponentPropsMeta = {
40
44
  props: {
41
- ...props,
45
+ ...publicProps,
42
46
  src: {
43
47
  type: "string",
44
48
  control: "file",
@@ -1,5 +1,4 @@
1
1
  import type { WsComponentMeta, WsComponentPropsMeta } from "./component-meta";
2
- import type { ComponentName } from "./components-utils";
3
2
  import { meta as SlotMeta } from "./slot.ws";
4
3
  import { meta as FragmentMeta } from "./fragment.ws";
5
4
  import { meta as HtmlEmbedMeta } from "./html-embed.ws";
@@ -106,22 +105,6 @@ export const defaultMetas: Record<string, WsComponentMeta> = {
106
105
  Checkbox: CheckboxMeta,
107
106
  };
108
107
 
109
- let currentMetas = defaultMetas;
110
-
111
- export const getComponentMeta = (name: string): WsComponentMeta | undefined => {
112
- return currentMetas[name];
113
- };
114
-
115
- export const registerComponentMetas = (
116
- overrides: Record<string, Partial<WsComponentMeta>>
117
- ) => {
118
- const result: typeof currentMetas = {};
119
- for (const name of Object.keys(defaultMetas)) {
120
- result[name] = { ...defaultMetas[name], ...overrides[name] };
121
- }
122
- currentMetas = result;
123
- };
124
-
125
108
  // @todo this list should not be hardcoded!
126
109
  export const defaultPropsMetas: Record<string, WsComponentPropsMeta> = {
127
110
  Slot: SlotMetaPropsMeta,
@@ -158,34 +141,3 @@ export const defaultPropsMetas: Record<string, WsComponentPropsMeta> = {
158
141
  CheckboxField: CheckboxFieldPropsMeta,
159
142
  Checkbox: CheckboxPropsMeta,
160
143
  };
161
-
162
- type RegisteredComponents = Partial<{
163
- // eslint-disable-next-line @typescript-eslint/ban-types
164
- [name in ComponentName]: {};
165
- }>;
166
-
167
- export let registeredComponents: RegisteredComponents | undefined;
168
-
169
- /**
170
- * @todo: Allow register any component.
171
- * Now we can register only existings Components, as all our type system would
172
- * break otherwise, see getComponent etc. So its overwriteComponent now
173
- **/
174
- export const registerComponents = (components: RegisteredComponents) => {
175
- registeredComponents = components;
176
- };
177
-
178
- export const canAcceptComponent = (
179
- parentComponent: string,
180
- childComponent: string
181
- ) => {
182
- const parentMeta = getComponentMeta(parentComponent);
183
- const childMeta = getComponentMeta(childComponent);
184
- if (parentMeta?.type !== "container" || childMeta === undefined) {
185
- return false;
186
- }
187
- return (
188
- childMeta.acceptedParents === undefined ||
189
- childMeta.acceptedParents.includes(parentComponent)
190
- );
191
- };
@@ -19,6 +19,7 @@ export const meta: WsComponentMeta = {
19
19
  label: "Text Input",
20
20
  icon: FormTextFieldIcon,
21
21
  presetStyle,
22
+ order: 3,
22
23
  states: [
23
24
  ...defaultStates,
24
25
  { selector: "::placeholder", label: "Placeholder" },
@@ -23,7 +23,14 @@ export const meta: WsComponentMeta = {
23
23
  icon: TextBlockIcon,
24
24
  states: defaultStates,
25
25
  presetStyle,
26
- children: [{ type: "text", value: "Form Label" }],
26
+ order: 2,
27
+ template: [
28
+ {
29
+ type: "instance",
30
+ component: "Label",
31
+ children: [{ type: "text", value: "Form Label" }],
32
+ },
33
+ ],
27
34
  };
28
35
 
29
36
  export const propsMeta: WsComponentPropsMeta = {
@@ -26,6 +26,7 @@ export const meta: WsComponentMeta = {
26
26
  icon: LinkBlockIcon,
27
27
  states: linkMeta.states,
28
28
  presetStyle,
29
+ order: 2,
29
30
  };
30
31
 
31
32
  export const propsMeta: WsComponentPropsMeta = {
@@ -29,6 +29,7 @@ export const meta: WsComponentMeta = {
29
29
  label: "Link Text",
30
30
  icon: LinkIcon,
31
31
  presetStyle,
32
+ order: 1,
32
33
  states: [
33
34
  ...defaultStates,
34
35
  {
@@ -41,7 +42,13 @@ export const meta: WsComponentMeta = {
41
42
  label: "Current page",
42
43
  },
43
44
  ],
44
- children: [{ type: "text", value: "Link text you can edit" }],
45
+ template: [
46
+ {
47
+ type: "instance",
48
+ component: "Link",
49
+ children: [{ type: "text", value: "Link text you can edit" }],
50
+ },
51
+ ],
45
52
  };
46
53
 
47
54
  export const propsMeta: WsComponentPropsMeta = {
@@ -14,14 +14,21 @@ const presetStyle = {
14
14
  } satisfies PresetStyle<typeof defaultTag>;
15
15
 
16
16
  export const meta: WsComponentMeta = {
17
- category: "typography",
17
+ category: "general",
18
18
  type: "rich-text",
19
- acceptedParents: ["List"],
19
+ requiredAncestors: ["List"],
20
20
  label: "List Item",
21
21
  icon: ListItemIcon,
22
- children: [{ type: "text", value: "List Item you can edit" }],
23
22
  states: defaultStates,
24
23
  presetStyle,
24
+ template: [
25
+ {
26
+ type: "instance",
27
+ component: "ListItem",
28
+ children: [{ type: "text", value: "List Item you can edit" }],
29
+ },
30
+ ],
31
+ order: 4,
25
32
  };
26
33
 
27
34
  export const propsMeta: WsComponentPropsMeta = {
@@ -43,13 +43,13 @@ const presetStyle = {
43
43
  } satisfies PresetStyle<ListTag>;
44
44
 
45
45
  export const meta: WsComponentMeta = {
46
- category: "typography",
46
+ category: "general",
47
47
  type: "container",
48
48
  label: "List",
49
49
  icon: ListIcon,
50
50
  states: defaultStates,
51
51
  presetStyle,
52
- children: [],
52
+ order: 3,
53
53
  };
54
54
 
55
55
  export const propsMeta: WsComponentPropsMeta = {
@@ -14,13 +14,20 @@ const presetStyle = {
14
14
  } satisfies PresetStyle<typeof defaultTag>;
15
15
 
16
16
  export const meta: WsComponentMeta = {
17
- category: "typography",
17
+ category: "text",
18
18
  type: "rich-text",
19
19
  label: "Paragraph",
20
20
  icon: TextAlignLeftIcon,
21
- children: [{ type: "text", value: "Pragraph you can edit" }],
22
21
  states: defaultStates,
23
22
  presetStyle,
23
+ template: [
24
+ {
25
+ type: "instance",
26
+ component: "Paragraph",
27
+ children: [{ type: "text", value: "Pragraph you can edit" }],
28
+ },
29
+ ],
30
+ order: 2,
24
31
  };
25
32
 
26
33
  export const propsMeta: WsComponentPropsMeta = {
@@ -23,14 +23,20 @@ export const meta: WsComponentMeta = {
23
23
  icon: RadioCheckedIcon,
24
24
  states: defaultStates,
25
25
  presetStyle,
26
- children: [
27
- { type: "instance", component: "RadioButton", props: [], children: [] },
26
+ template: [
28
27
  {
29
28
  type: "instance",
30
- component: "TextBlock",
31
- label: "Radio Label",
32
- props: [],
33
- children: [{ type: "text", value: "Radio" }],
29
+ component: "RadioButtonField",
30
+ children: [
31
+ { type: "instance", component: "RadioButton", props: [], children: [] },
32
+ {
33
+ type: "instance",
34
+ component: "TextBlock",
35
+ label: "Radio Label",
36
+ props: [],
37
+ children: [{ type: "text", value: "Radio" }],
38
+ },
39
+ ],
34
40
  },
35
41
  ],
36
42
  };
@@ -24,6 +24,7 @@ export const meta: WsComponentMeta = {
24
24
  label: "Radio Input",
25
25
  icon: RadioCheckedIcon,
26
26
  presetStyle,
27
+ order: 5,
27
28
  states: [
28
29
  ...defaultStates,
29
30
  { selector: ":checked", label: "Checked" },
@@ -7,7 +7,7 @@ const { category, ...linkMetaRest } = linkMeta;
7
7
  export const meta: WsComponentMeta = {
8
8
  ...linkMetaRest,
9
9
  type: "rich-text-child",
10
- children: [],
10
+ template: [],
11
11
  };
12
12
 
13
13
  export const propsMeta: WsComponentPropsMeta = {
@@ -47,7 +47,7 @@ export const meta: WsComponentMeta = {
47
47
  icon: DashIcon,
48
48
  states: defaultStates,
49
49
  presetStyle,
50
- children: [],
50
+ order: 5,
51
51
  };
52
52
 
53
53
  export const propsMeta: WsComponentPropsMeta = {
@@ -6,6 +6,8 @@ export const meta: WsComponentMeta = {
6
6
  type: "container",
7
7
  label: "Slot",
8
8
  icon: SlotComponentIcon,
9
+ stylable: false,
10
+ order: 6,
9
11
  };
10
12
 
11
13
  export const propsMeta: WsComponentPropsMeta = {
@@ -1,10 +1,21 @@
1
- import { forwardRef, type ElementRef, type ComponentProps } from "react";
1
+ import {
2
+ createElement,
3
+ forwardRef,
4
+ type ElementRef,
5
+ type ComponentProps,
6
+ } from "react";
2
7
 
3
8
  export const defaultTag = "div";
4
9
 
5
- export const TextBlock = forwardRef<
6
- ElementRef<typeof defaultTag>,
7
- ComponentProps<typeof defaultTag>
8
- >((props, ref) => <div {...props} ref={ref} />);
10
+ // We don't want to enable all tags because Box is usually a container and we have specific components for many tags.
11
+ type Props = ComponentProps<typeof defaultTag> & {
12
+ tag?: "div" | "span" | "figcaption";
13
+ };
14
+
15
+ export const TextBlock = forwardRef<ElementRef<typeof defaultTag>, Props>(
16
+ ({ tag = defaultTag, ...props }, ref) => {
17
+ return createElement(tag, { ...props, ref });
18
+ }
19
+ );
9
20
 
10
21
  TextBlock.displayName = "TextBlock";
@@ -20,15 +20,23 @@ const presetStyle = {
20
20
  } satisfies PresetStyle<typeof defaultTag>;
21
21
 
22
22
  export const meta: WsComponentMeta = {
23
- category: "typography",
23
+ category: "text",
24
24
  type: "rich-text",
25
25
  label: "Text Block",
26
26
  icon: TextBlockIcon,
27
27
  states: defaultStates,
28
28
  presetStyle,
29
- children: [{ type: "text", value: "Block of text you can edit" }],
29
+ template: [
30
+ {
31
+ type: "instance",
32
+ component: "TextBlock",
33
+ children: [{ type: "text", value: "Block of text you can edit" }],
34
+ },
35
+ ],
36
+ order: 0,
30
37
  };
31
38
 
32
39
  export const propsMeta: WsComponentPropsMeta = {
33
40
  props,
41
+ initialProps: ["tag"],
34
42
  };
@@ -23,6 +23,7 @@ export const meta: WsComponentMeta = {
23
23
  label: "Text Area",
24
24
  icon: FormTextAreaIcon,
25
25
  presetStyle,
26
+ order: 4,
26
27
  states: [
27
28
  ...defaultStates,
28
29
  { selector: "::placeholder", label: "Placeholder" },
@@ -10,6 +10,7 @@ import {
10
10
  Breakpoint,
11
11
  } from "@webstudio-is/project-build";
12
12
  import { StyleValue, type StyleProperty } from "@webstudio-is/css-data";
13
+ import type { Simplify } from "type-fest";
13
14
 
14
15
  const EmbedTemplateText = z.object({
15
16
  type: z.literal("text"),
@@ -43,13 +44,20 @@ const EmbedTemplateProp = z.union([
43
44
 
44
45
  type EmbedTemplateProp = z.infer<typeof EmbedTemplateProp>;
45
46
 
46
- export const EmbedTemplateStyleDecl = z.object({
47
+ const EmbedTemplateStyleDeclRaw = z.object({
47
48
  state: z.optional(z.string()),
48
- property: z.string() as z.ZodType<StyleProperty>,
49
+ property: z.string(),
49
50
  value: StyleValue,
50
51
  });
51
52
 
52
- export type EmbedTemplateStyleDecl = z.infer<typeof EmbedTemplateStyleDecl>;
53
+ export type EmbedTemplateStyleDecl = Simplify<
54
+ Omit<z.infer<typeof EmbedTemplateStyleDeclRaw>, "property"> & {
55
+ property: StyleProperty;
56
+ }
57
+ >;
58
+
59
+ export const EmbedTemplateStyleDecl =
60
+ EmbedTemplateStyleDeclRaw as z.ZodType<EmbedTemplateStyleDecl>;
53
61
 
54
62
  export type EmbedTemplateInstance = {
55
63
  type: "instance";
package/src/index.ts CHANGED
@@ -5,16 +5,13 @@ export * from "./pubsub";
5
5
  export * from "./app";
6
6
  export * from "./components/components";
7
7
  export * from "./components/components-utils";
8
- export {
9
- customComponents,
10
- customComponentMetas,
11
- customComponentPropsMetas,
12
- } from "./app/custom-components";
13
8
  export {
14
9
  type WsComponentPropsMeta,
15
10
  type WsComponentMeta,
16
11
  type ComponentState,
12
+ type PresetStyle,
17
13
  componentCategories,
18
14
  stateCategories,
19
15
  } from "./components/component-meta";
20
16
  export * from "./embed-template";
17
+ export { usePropUrl, getInstanceIdFromComponentProps } from "./props";
package/src/props.test.ts CHANGED
@@ -31,7 +31,6 @@ describe("resolveUrlProp", () => {
31
31
  id: unique(),
32
32
  name: unique(),
33
33
  type: "image",
34
- location: "REMOTE",
35
34
  projectId,
36
35
  format: "png",
37
36
  size: 100000,
@@ -3,7 +3,7 @@ import type { ReadableAtom } from "nanostores";
3
3
  import { Scripts, ScrollRestoration } from "@remix-run/react";
4
4
  import type { Assets } from "@webstudio-is/asset-uploader";
5
5
  import type { Instance, Instances } from "@webstudio-is/project-build";
6
- import type { GetComponent } from "../components/components-utils";
6
+ import type { Components } from "../components/components-utils";
7
7
  import { ReactSdkContext } from "../context";
8
8
  import type { Pages, PropsByInstanceId } from "../props";
9
9
  import type { WebstudioComponent } from "./webstudio-component";
@@ -18,7 +18,7 @@ export const createElementsTree = ({
18
18
  assetsStore,
19
19
  pagesStore,
20
20
  Component,
21
- getComponent,
21
+ components,
22
22
  }: {
23
23
  renderer?: "canvas";
24
24
  instances: Instances;
@@ -27,7 +27,7 @@ export const createElementsTree = ({
27
27
  assetsStore: ReadableAtom<Assets>;
28
28
  pagesStore: ReadableAtom<Pages>;
29
29
  Component: (props: ComponentProps<typeof WebstudioComponent>) => JSX.Element;
30
- getComponent: GetComponent;
30
+ components: Components;
31
31
  }) => {
32
32
  const rootInstance = instances.get(rootInstanceId);
33
33
  if (rootInstance === undefined) {
@@ -40,7 +40,7 @@ export const createElementsTree = ({
40
40
  instanceSelector: rootInstanceSelector,
41
41
  Component,
42
42
  children: rootInstance.children,
43
- getComponent,
43
+ components,
44
44
  });
45
45
  const root = createInstanceElement({
46
46
  Component,
@@ -53,7 +53,7 @@ export const createElementsTree = ({
53
53
  <Scripts />
54
54
  </Fragment>,
55
55
  ],
56
- getComponent,
56
+ components,
57
57
  });
58
58
  return (
59
59
  <ReactSdkContext.Provider
@@ -69,13 +69,13 @@ const createInstanceChildrenElements = ({
69
69
  instanceSelector,
70
70
  children,
71
71
  Component,
72
- getComponent,
72
+ components,
73
73
  }: {
74
74
  instances: Instances;
75
75
  instanceSelector: InstanceSelector;
76
76
  children: Instance["children"];
77
77
  Component: (props: ComponentProps<typeof WebstudioComponent>) => JSX.Element;
78
- getComponent: GetComponent;
78
+ components: Components;
79
79
  }) => {
80
80
  const elements = [];
81
81
  for (const child of children) {
@@ -93,14 +93,14 @@ const createInstanceChildrenElements = ({
93
93
  instanceSelector: childInstanceSelector,
94
94
  children: childInstance.children,
95
95
  Component,
96
- getComponent,
96
+ components,
97
97
  });
98
98
  const element = createInstanceElement({
99
99
  instance: childInstance,
100
100
  instanceSelector: childInstanceSelector,
101
101
  Component,
102
102
  children,
103
- getComponent,
103
+ components,
104
104
  });
105
105
  elements.push(element);
106
106
  }
@@ -112,20 +112,20 @@ const createInstanceElement = ({
112
112
  instance,
113
113
  instanceSelector,
114
114
  children = [],
115
- getComponent,
115
+ components,
116
116
  }: {
117
117
  instance: Instance;
118
118
  instanceSelector: InstanceSelector;
119
119
  Component: (props: ComponentProps<typeof WebstudioComponent>) => JSX.Element;
120
120
  children?: Array<JSX.Element | string>;
121
- getComponent: GetComponent;
121
+ components: Components;
122
122
  }) => {
123
123
  return (
124
124
  <Component
125
125
  key={instance.id}
126
126
  instance={instance}
127
127
  instanceSelector={instanceSelector}
128
- getComponent={getComponent}
128
+ components={components}
129
129
  >
130
130
  {children}
131
131
  </Component>
package/src/tree/root.ts CHANGED
@@ -4,11 +4,9 @@ import type { Build, Page } from "@webstudio-is/project-build";
4
4
  import type { Asset } from "@webstudio-is/asset-uploader";
5
5
  import { createElementsTree } from "./create-elements-tree";
6
6
  import { WebstudioComponent } from "./webstudio-component";
7
- import { registerComponents } from "../components";
8
- import { customComponents as defaultCustomComponents } from "../app/custom-components";
9
7
  import { setParams, type Params } from "../app/params";
10
8
  import { getPropsByInstanceId } from "../props";
11
- import type { GetComponent } from "../components/components-utils";
9
+ import type { Components } from "../components/components-utils";
12
10
 
13
11
  export type Data = {
14
12
  page: Page;
@@ -25,18 +23,15 @@ export type RootPropsData = Omit<Data, "build"> & {
25
23
  type RootProps = {
26
24
  data: RootPropsData;
27
25
  Component?: (props: ComponentProps<typeof WebstudioComponent>) => JSX.Element;
28
- customComponents?: Parameters<typeof registerComponents>[0];
29
- getComponent: GetComponent;
26
+ components: Components;
30
27
  };
31
28
 
32
29
  export const InstanceRoot = ({
33
30
  data,
34
31
  Component,
35
- customComponents = defaultCustomComponents,
36
- getComponent,
32
+ components,
37
33
  }: RootProps): JSX.Element | null => {
38
34
  setParams(data.params);
39
- registerComponents(customComponents);
40
35
  return createElementsTree({
41
36
  instances: new Map(data.build.instances),
42
37
  rootInstanceId: data.page.rootInstanceId,
@@ -46,6 +41,6 @@ export const InstanceRoot = ({
46
41
  assetsStore: atom(new Map(data.assets.map((asset) => [asset.id, asset]))),
47
42
  pagesStore: atom(new Map(data.pages.map((page) => [page.id, page]))),
48
43
  Component: Component ?? WebstudioComponent,
49
- getComponent,
44
+ components,
50
45
  });
51
46
  };
@@ -1,6 +1,6 @@
1
1
  import { Fragment } from "react";
2
2
  import type { Instance } from "@webstudio-is/project-build";
3
- import type { GetComponent } from "../components/components-utils";
3
+ import type { Components } from "../components/components-utils";
4
4
  import { useInstanceProps } from "../props";
5
5
 
6
6
  const renderText = (text: string): Array<JSX.Element> => {
@@ -30,14 +30,14 @@ type WebstudioComponentProps = {
30
30
  instance: Instance;
31
31
  instanceSelector: Instance["id"][];
32
32
  children: Array<JSX.Element | string>;
33
- getComponent: GetComponent;
33
+ components: Components;
34
34
  };
35
35
 
36
36
  export const WebstudioComponent = ({
37
37
  instance,
38
38
  instanceSelector,
39
39
  children,
40
- getComponent,
40
+ components,
41
41
  ...rest
42
42
  }: WebstudioComponentProps) => {
43
43
  const instanceProps = useInstanceProps(instance.id);
@@ -47,7 +47,7 @@ export const WebstudioComponent = ({
47
47
  [idAttribute]: instance.id,
48
48
  [componentAttribute]: instance.component,
49
49
  };
50
- const Component = getComponent(instance.component);
50
+ const Component = components.get(instance.component);
51
51
  if (Component === undefined) {
52
52
  return <></>;
53
53
  }