@webiny/website-builder-react 6.6.0-alpha.0 → 6.6.0-alpha.2

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.
@@ -3,7 +3,7 @@ import { type DocumentElement } from "@webiny/website-builder-sdk";
3
3
  interface PreviewElementRendererProps {
4
4
  element: DocumentElement;
5
5
  }
6
- export declare const EditingElementRenderer: ((props: PreviewElementRendererProps) => React.JSX.Element | null) & {
7
- displayName: string;
6
+ export declare const EditingElementRenderer: ((props: PreviewElementRendererProps) => React.JSX.Element | null) & React.NamedExoticComponent<PreviewElementRendererProps> & {
7
+ readonly type: (props: PreviewElementRendererProps) => React.JSX.Element | null;
8
8
  };
9
9
  export {};
@@ -2,7 +2,7 @@ import React from "react";
2
2
  interface ElementRendererProps {
3
3
  id: string;
4
4
  }
5
- export declare const ElementRenderer: ((props: ElementRendererProps) => React.JSX.Element | null) & {
6
- displayName: string;
5
+ export declare const ElementRenderer: ((props: ElementRendererProps) => React.JSX.Element | null) & React.NamedExoticComponent<ElementRendererProps> & {
6
+ readonly type: (props: ElementRendererProps) => React.JSX.Element | null;
7
7
  };
8
8
  export {};
@@ -4,7 +4,7 @@ interface LiveElementRendererProps {
4
4
  element: DocumentElement;
5
5
  bindings?: DocumentElementBindings;
6
6
  }
7
- export declare const LiveElementRenderer: (({ element }: LiveElementRendererProps) => React.JSX.Element | null) & {
8
- displayName: string;
7
+ export declare const LiveElementRenderer: (({ element }: LiveElementRendererProps) => React.JSX.Element | null) & React.NamedExoticComponent<LiveElementRendererProps> & {
8
+ readonly type: ({ element }: LiveElementRendererProps) => React.JSX.Element | null;
9
9
  };
10
10
  export {};
@@ -1,3 +1 @@
1
- import type { Component, ComponentManifestInput } from "@webiny/website-builder-sdk";
2
- import type { ExtractInputs } from "./types.js";
3
- export declare function createComponent<TComponent extends (props: any) => any, TInputs extends ExtractInputs<Parameters<TComponent>[0]>>(component: TComponent, manifest: ComponentManifestInput<TInputs>): Component;
1
+ export { createComponent } from "@webiny/website-builder-sdk";
@@ -1,32 +1 @@
1
- import { createSlotInput } from "@webiny/website-builder-sdk";
2
- function createComponent(component, manifest) {
3
- const inputs = [];
4
- if (Array.isArray(manifest.inputs)) inputs.push(...manifest.inputs);
5
- else {
6
- const inputsObject = manifest.inputs ?? {};
7
- Object.keys(inputsObject).forEach((name)=>{
8
- inputs.push({
9
- ...inputsObject[name],
10
- name
11
- });
12
- });
13
- }
14
- const acceptsChildren = manifest.acceptsChildren;
15
- if (acceptsChildren) {
16
- const hasChildren = inputs.some((input)=>"children" === input.name);
17
- if (!hasChildren) inputs.push(createSlotInput({
18
- name: "children"
19
- }));
20
- }
21
- return {
22
- component,
23
- manifest: {
24
- ...manifest,
25
- tags: manifest.tags ?? [],
26
- inputs
27
- }
28
- };
29
- }
30
- export { createComponent };
31
-
32
- //# sourceMappingURL=createComponent.js.map
1
+ export { createComponent } from "@webiny/website-builder-sdk";
@@ -4,7 +4,7 @@ import { createTextInput } from "./index.js";
4
4
  import { createSlotInput } from "@webiny/website-builder-sdk";
5
5
  describe("Component Manifest", ()=>{
6
6
  it("should support input arrays and strict input objects", ()=>{
7
- const Button = (_)=>null;
7
+ const Button = ({})=>null;
8
8
  const button1 = createComponent(Button, {
9
9
  name: "Button",
10
10
  inputs: [
@@ -49,7 +49,7 @@ describe("Component Manifest", ()=>{
49
49
  expect(button2.manifest).toEqual(snapshot);
50
50
  });
51
51
  it("acceptsChildren should satisfy the `children` input requirement", ()=>{
52
- const Button = (_)=>null;
52
+ const Button = ({})=>null;
53
53
  const { manifest } = createComponent(Button, {
54
54
  name: "Button",
55
55
  acceptsChildren: true
@@ -70,7 +70,7 @@ describe("Component Manifest", ()=>{
70
70
  });
71
71
  });
72
72
  it("`acceptsChildren` should work alongside other inputs", ()=>{
73
- const Button = (_)=>null;
73
+ const Button = ({})=>null;
74
74
  const button1 = createComponent(Button, {
75
75
  name: "Button",
76
76
  acceptsChildren: true,
@@ -1 +1 @@
1
- {"version":3,"file":"createComponent.test.js","sources":["../src/createComponent.test.ts"],"sourcesContent":["import { describe, expect, it } from \"vitest\";\nimport type { ComponentProps, ExtractInputNames } from \"~/types.js\";\nimport { createComponent } from \"~/createComponent.js\";\nimport { createTextInput } from \"~/index.js\";\nimport { createSlotInput } from \"@webiny/website-builder-sdk\";\n\n/**\n * These tests are aimed at testing TS types rather than functionality itself.\n * // TODO: figure out how to enable typechecking for a single test. Currently it only typechecks at build time.\n */\n\ndescribe(\"Component Manifest\", () => {\n it(\"should support input arrays and strict input objects\", () => {\n const Button = (_: ComponentProps<{ title: string; children: React.ReactNode }>) => {\n return null;\n };\n\n type Inputs = ExtractInputNames<typeof Button>;\n\n const button1 = createComponent(Button, {\n name: \"Button\",\n inputs: [\n // Passing a generic narrows down the `name` property and provides autocomplete.\n createTextInput<Inputs>({\n name: \"title\",\n label: \"Title\"\n }),\n // Skipping the generic still performs typechecks, but doesn't provide autocomplete.\n createSlotInput({\n name: \"children\"\n })\n ]\n });\n\n const button2 = createComponent(Button, {\n name: \"Button\",\n inputs: {\n title: createTextInput({\n label: \"Title\"\n }),\n children: createSlotInput({})\n }\n });\n\n const snapshot = {\n name: \"Button\",\n tags: [],\n inputs: [\n {\n type: \"text\",\n label: \"Title\",\n renderer: \"Webiny/Input\",\n name: \"title\"\n },\n {\n type: \"slot\",\n renderer: \"Webiny/Slot\",\n name: \"children\",\n list: true,\n defaultValue: []\n }\n ]\n };\n\n expect(button1.manifest).toEqual(snapshot);\n expect(button2.manifest).toEqual(snapshot);\n });\n\n it(\"acceptsChildren should satisfy the `children` input requirement\", () => {\n const Button = (_: ComponentProps<{ children: React.ReactNode }>) => {\n return null;\n };\n\n const { manifest } = createComponent(Button, {\n name: \"Button\",\n acceptsChildren: true\n });\n\n expect(manifest).toEqual({\n name: \"Button\",\n acceptsChildren: true,\n tags: [],\n inputs: [\n {\n type: \"slot\",\n list: true,\n renderer: \"Webiny/Slot\",\n name: \"children\",\n defaultValue: []\n }\n ]\n });\n });\n\n it(\"`acceptsChildren` should work alongside other inputs\", () => {\n const Button = (_: ComponentProps<{ title: string; children: React.ReactNode }>) => {\n return null;\n };\n\n // Inputs as array\n const button1 = createComponent(Button, {\n name: \"Button\",\n acceptsChildren: true,\n inputs: [\n createTextInput({\n name: \"title\",\n label: \"Title\"\n })\n ]\n });\n\n // Inputs as object\n const button2 = createComponent(Button, {\n name: \"Button\",\n acceptsChildren: true,\n inputs: {\n title: createTextInput({\n label: \"Title\"\n })\n }\n });\n\n // Both must produce the same component manifest\n const snapshot = {\n name: \"Button\",\n acceptsChildren: true,\n tags: [],\n inputs: [\n {\n type: \"text\",\n renderer: \"Webiny/Input\",\n name: \"title\",\n label: \"Title\"\n },\n {\n type: \"slot\",\n renderer: \"Webiny/Slot\",\n name: \"children\",\n list: true,\n defaultValue: []\n }\n ]\n };\n\n expect(button1.manifest).toEqual(snapshot);\n expect(button2.manifest).toEqual(snapshot);\n });\n});\n"],"names":["describe","it","Button","_","button1","createComponent","createTextInput","createSlotInput","button2","snapshot","expect","manifest"],"mappings":";;;;AAWAA,SAAS,sBAAsB;IAC3BC,GAAG,wDAAwD;QACvD,MAAMC,SAAS,CAACC,IACL;QAKX,MAAMC,UAAUC,gBAAgBH,QAAQ;YACpC,MAAM;YACN,QAAQ;gBAEJI,gBAAwB;oBACpB,MAAM;oBACN,OAAO;gBACX;gBAEAC,gBAAgB;oBACZ,MAAM;gBACV;aACH;QACL;QAEA,MAAMC,UAAUH,gBAAgBH,QAAQ;YACpC,MAAM;YACN,QAAQ;gBACJ,OAAOI,gBAAgB;oBACnB,OAAO;gBACX;gBACA,UAAUC,gBAAgB,CAAC;YAC/B;QACJ;QAEA,MAAME,WAAW;YACb,MAAM;YACN,MAAM,EAAE;YACR,QAAQ;gBACJ;oBACI,MAAM;oBACN,OAAO;oBACP,UAAU;oBACV,MAAM;gBACV;gBACA;oBACI,MAAM;oBACN,UAAU;oBACV,MAAM;oBACN,MAAM;oBACN,cAAc,EAAE;gBACpB;aACH;QACL;QAEAC,OAAON,QAAQ,QAAQ,EAAE,OAAO,CAACK;QACjCC,OAAOF,QAAQ,QAAQ,EAAE,OAAO,CAACC;IACrC;IAEAR,GAAG,mEAAmE;QAClE,MAAMC,SAAS,CAACC,IACL;QAGX,MAAM,EAAEQ,QAAQ,EAAE,GAAGN,gBAAgBH,QAAQ;YACzC,MAAM;YACN,iBAAiB;QACrB;QAEAQ,OAAOC,UAAU,OAAO,CAAC;YACrB,MAAM;YACN,iBAAiB;YACjB,MAAM,EAAE;YACR,QAAQ;gBACJ;oBACI,MAAM;oBACN,MAAM;oBACN,UAAU;oBACV,MAAM;oBACN,cAAc,EAAE;gBACpB;aACH;QACL;IACJ;IAEAV,GAAG,wDAAwD;QACvD,MAAMC,SAAS,CAACC,IACL;QAIX,MAAMC,UAAUC,gBAAgBH,QAAQ;YACpC,MAAM;YACN,iBAAiB;YACjB,QAAQ;gBACJI,gBAAgB;oBACZ,MAAM;oBACN,OAAO;gBACX;aACH;QACL;QAGA,MAAME,UAAUH,gBAAgBH,QAAQ;YACpC,MAAM;YACN,iBAAiB;YACjB,QAAQ;gBACJ,OAAOI,gBAAgB;oBACnB,OAAO;gBACX;YACJ;QACJ;QAGA,MAAMG,WAAW;YACb,MAAM;YACN,iBAAiB;YACjB,MAAM,EAAE;YACR,QAAQ;gBACJ;oBACI,MAAM;oBACN,UAAU;oBACV,MAAM;oBACN,OAAO;gBACX;gBACA;oBACI,MAAM;oBACN,UAAU;oBACV,MAAM;oBACN,MAAM;oBACN,cAAc,EAAE;gBACpB;aACH;QACL;QAEAC,OAAON,QAAQ,QAAQ,EAAE,OAAO,CAACK;QACjCC,OAAOF,QAAQ,QAAQ,EAAE,OAAO,CAACC;IACrC;AACJ"}
1
+ {"version":3,"file":"createComponent.test.js","sources":["../src/createComponent.test.ts"],"sourcesContent":["import { describe, expect, it } from \"vitest\";\nimport type { ComponentProps, ExtractInputNames } from \"~/types.js\";\nimport { createComponent } from \"~/createComponent.js\";\nimport { createTextInput } from \"~/index.js\";\nimport { createSlotInput } from \"@webiny/website-builder-sdk\";\n\n/**\n * These tests are aimed at testing TS types rather than functionality itself.\n * // TODO: figure out how to enable typechecking for a single test. Currently it only typechecks at build time.\n */\n\ndescribe(\"Component Manifest\", () => {\n it(\"should support input arrays and strict input objects\", () => {\n const Button = ({}: ComponentProps<{ title: string; children: React.ReactNode }>) => {\n return null;\n };\n\n type Inputs = ExtractInputNames<typeof Button>;\n\n const button1 = createComponent(Button, {\n name: \"Button\",\n inputs: [\n // Passing a generic narrows down the `name` property and provides autocomplete.\n createTextInput<Inputs>({\n name: \"title\",\n label: \"Title\"\n }),\n // Skipping the generic still performs typechecks, but doesn't provide autocomplete.\n createSlotInput({\n name: \"children\"\n })\n ]\n });\n\n const button2 = createComponent(Button, {\n name: \"Button\",\n inputs: {\n title: createTextInput({\n label: \"Title\"\n }),\n children: createSlotInput({})\n }\n });\n\n const snapshot = {\n name: \"Button\",\n tags: [],\n inputs: [\n {\n type: \"text\",\n label: \"Title\",\n renderer: \"Webiny/Input\",\n name: \"title\"\n },\n {\n type: \"slot\",\n renderer: \"Webiny/Slot\",\n name: \"children\",\n list: true,\n defaultValue: []\n }\n ]\n };\n\n expect(button1.manifest).toEqual(snapshot);\n expect(button2.manifest).toEqual(snapshot);\n });\n\n it(\"acceptsChildren should satisfy the `children` input requirement\", () => {\n const Button = ({}: ComponentProps<{ children: React.ReactNode }>) => {\n return null;\n };\n\n const { manifest } = createComponent(Button, {\n name: \"Button\",\n acceptsChildren: true\n });\n\n expect(manifest).toEqual({\n name: \"Button\",\n acceptsChildren: true,\n tags: [],\n inputs: [\n {\n type: \"slot\",\n list: true,\n renderer: \"Webiny/Slot\",\n name: \"children\",\n defaultValue: []\n }\n ]\n });\n });\n\n it(\"`acceptsChildren` should work alongside other inputs\", () => {\n const Button = ({}: ComponentProps<{ title: string; children: React.ReactNode }>) => {\n return null;\n };\n\n // Inputs as array\n const button1 = createComponent(Button, {\n name: \"Button\",\n acceptsChildren: true,\n inputs: [\n createTextInput({\n name: \"title\",\n label: \"Title\"\n })\n ]\n });\n\n // Inputs as object\n const button2 = createComponent(Button, {\n name: \"Button\",\n acceptsChildren: true,\n inputs: {\n title: createTextInput({\n label: \"Title\"\n })\n }\n });\n\n // Both must produce the same component manifest\n const snapshot = {\n name: \"Button\",\n acceptsChildren: true,\n tags: [],\n inputs: [\n {\n type: \"text\",\n renderer: \"Webiny/Input\",\n name: \"title\",\n label: \"Title\"\n },\n {\n type: \"slot\",\n renderer: \"Webiny/Slot\",\n name: \"children\",\n list: true,\n defaultValue: []\n }\n ]\n };\n\n expect(button1.manifest).toEqual(snapshot);\n expect(button2.manifest).toEqual(snapshot);\n });\n});\n"],"names":["describe","it","Button","button1","createComponent","createTextInput","createSlotInput","button2","snapshot","expect","manifest"],"mappings":";;;;AAWAA,SAAS,sBAAsB;IAC3BC,GAAG,wDAAwD;QACvD,MAAMC,SAAS,CAAC,EAAgE,GACrE;QAKX,MAAMC,UAAUC,gBAAgBF,QAAQ;YACpC,MAAM;YACN,QAAQ;gBAEJG,gBAAwB;oBACpB,MAAM;oBACN,OAAO;gBACX;gBAEAC,gBAAgB;oBACZ,MAAM;gBACV;aACH;QACL;QAEA,MAAMC,UAAUH,gBAAgBF,QAAQ;YACpC,MAAM;YACN,QAAQ;gBACJ,OAAOG,gBAAgB;oBACnB,OAAO;gBACX;gBACA,UAAUC,gBAAgB,CAAC;YAC/B;QACJ;QAEA,MAAME,WAAW;YACb,MAAM;YACN,MAAM,EAAE;YACR,QAAQ;gBACJ;oBACI,MAAM;oBACN,OAAO;oBACP,UAAU;oBACV,MAAM;gBACV;gBACA;oBACI,MAAM;oBACN,UAAU;oBACV,MAAM;oBACN,MAAM;oBACN,cAAc,EAAE;gBACpB;aACH;QACL;QAEAC,OAAON,QAAQ,QAAQ,EAAE,OAAO,CAACK;QACjCC,OAAOF,QAAQ,QAAQ,EAAE,OAAO,CAACC;IACrC;IAEAP,GAAG,mEAAmE;QAClE,MAAMC,SAAS,CAAC,EAAiD,GACtD;QAGX,MAAM,EAAEQ,QAAQ,EAAE,GAAGN,gBAAgBF,QAAQ;YACzC,MAAM;YACN,iBAAiB;QACrB;QAEAO,OAAOC,UAAU,OAAO,CAAC;YACrB,MAAM;YACN,iBAAiB;YACjB,MAAM,EAAE;YACR,QAAQ;gBACJ;oBACI,MAAM;oBACN,MAAM;oBACN,UAAU;oBACV,MAAM;oBACN,cAAc,EAAE;gBACpB;aACH;QACL;IACJ;IAEAT,GAAG,wDAAwD;QACvD,MAAMC,SAAS,CAAC,EAAgE,GACrE;QAIX,MAAMC,UAAUC,gBAAgBF,QAAQ;YACpC,MAAM;YACN,iBAAiB;YACjB,QAAQ;gBACJG,gBAAgB;oBACZ,MAAM;oBACN,OAAO;gBACX;aACH;QACL;QAGA,MAAME,UAAUH,gBAAgBF,QAAQ;YACpC,MAAM;YACN,iBAAiB;YACjB,QAAQ;gBACJ,OAAOG,gBAAgB;oBACnB,OAAO;gBACX;YACJ;QACJ;QAGA,MAAMG,WAAW;YACb,MAAM;YACN,iBAAiB;YACjB,MAAM,EAAE;YACR,QAAQ;gBACJ;oBACI,MAAM;oBACN,UAAU;oBACV,MAAM;oBACN,OAAO;gBACX;gBACA;oBACI,MAAM;oBACN,UAAU;oBACV,MAAM;oBACN,MAAM;oBACN,cAAc,EAAE;gBACpB;aACH;QACL;QAEAC,OAAON,QAAQ,QAAQ,EAAE,OAAO,CAACK;QACjCC,OAAOF,QAAQ,QAAQ,EAAE,OAAO,CAACC;IACrC;AACJ"}
@@ -0,0 +1,33 @@
1
+ import React from "react";
2
+ import { type Asset } from "@webiny/website-builder-sdk";
3
+ export interface BackgroundImageProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "style"> {
4
+ /** The image value (unified `Asset` or a legacy value — both accepted). */
5
+ image: Asset;
6
+ /** Content rendered on top of the background (auto-stacked above the image). */
7
+ children?: React.ReactNode;
8
+ /** Class applied to the wrapper element. */
9
+ className?: string;
10
+ /** Styles merged into the wrapper. Give it a height (e.g. `minHeight`). */
11
+ style?: React.CSSProperties;
12
+ /** Class applied to the background `<img>`. */
13
+ imgClassName?: string;
14
+ /** Explicit alt text; falls back to the image's stored alt. Empty = decorative. */
15
+ alt?: string;
16
+ /** Delivery width requested for the background image. Defaults to 1920. */
17
+ width?: number;
18
+ /**
19
+ * Responsive URL builder — e.g. `({ src, width }) => \`${src}?width=${width}&format=auto\``.
20
+ * When provided, a `srcSet` is generated from `widths`.
21
+ */
22
+ loader?: (params: {
23
+ src: string;
24
+ width: number;
25
+ }) => string;
26
+ /** Candidate widths for the generated `srcSet`. */
27
+ widths?: number[];
28
+ /** The `sizes` attribute (defaults to `100vw`, since backgrounds are usually full-bleed). */
29
+ sizes?: string;
30
+ /** Native loading strategy for the background image. */
31
+ loading?: "eager" | "lazy";
32
+ }
33
+ export declare function BackgroundImage({ image, children, className, style, imgClassName, alt, width, loader, widths, sizes, loading, ...rest }: BackgroundImageProps): React.JSX.Element;
@@ -0,0 +1,61 @@
1
+ import react from "react";
2
+ import { normalizeToAsset } from "@webiny/website-builder-sdk";
3
+ const DEFAULT_WIDTHS = [
4
+ 640,
5
+ 750,
6
+ 828,
7
+ 1080,
8
+ 1200,
9
+ 1920,
10
+ 2048
11
+ ];
12
+ function BackgroundImage({ image, children, className, style, imgClassName, alt, width = 1920, loader, widths = DEFAULT_WIDTHS, sizes = "100vw", loading, ...rest }) {
13
+ const asset = normalizeToAsset(image);
14
+ const src = asset?.src ?? "";
15
+ const focalPoint = asset?.image?.focalPoint ?? {
16
+ x: 0.5,
17
+ y: 0.5
18
+ };
19
+ const resolvedAlt = alt ?? asset?.image?.alt ?? "";
20
+ const resolvedSrc = loader ? loader({
21
+ src,
22
+ width
23
+ }) : src;
24
+ const srcSet = loader ? widths.map((w)=>`${loader({
25
+ src,
26
+ width: w
27
+ })} ${w}w`).join(", ") || void 0 : void 0;
28
+ return /*#__PURE__*/ react.createElement("div", {
29
+ ...rest,
30
+ className: className,
31
+ style: {
32
+ position: "relative",
33
+ overflow: "hidden",
34
+ ...style
35
+ }
36
+ }, /*#__PURE__*/ react.createElement("img", {
37
+ className: imgClassName,
38
+ src: resolvedSrc,
39
+ srcSet: srcSet,
40
+ sizes: srcSet ? sizes : void 0,
41
+ alt: resolvedAlt,
42
+ "aria-hidden": "" === resolvedAlt ? true : void 0,
43
+ loading: loading,
44
+ style: {
45
+ position: "absolute",
46
+ inset: 0,
47
+ width: "100%",
48
+ height: "100%",
49
+ objectFit: "cover",
50
+ objectPosition: `${100 * focalPoint.x}% ${100 * focalPoint.y}%`
51
+ }
52
+ }), null != children ? /*#__PURE__*/ react.createElement("div", {
53
+ style: {
54
+ position: "relative",
55
+ zIndex: 1
56
+ }
57
+ }, children) : null);
58
+ }
59
+ export { BackgroundImage };
60
+
61
+ //# sourceMappingURL=BackgroundImage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image/BackgroundImage.js","sources":["../../src/image/BackgroundImage.tsx"],"sourcesContent":["import React from \"react\";\nimport { normalizeToAsset, type Asset } from \"@webiny/website-builder-sdk\";\n\nexport interface BackgroundImageProps extends Omit<React.HTMLAttributes<HTMLDivElement>, \"style\"> {\n /** The image value (unified `Asset` or a legacy value — both accepted). */\n image: Asset;\n /** Content rendered on top of the background (auto-stacked above the image). */\n children?: React.ReactNode;\n /** Class applied to the wrapper element. */\n className?: string;\n /** Styles merged into the wrapper. Give it a height (e.g. `minHeight`). */\n style?: React.CSSProperties;\n /** Class applied to the background `<img>`. */\n imgClassName?: string;\n /** Explicit alt text; falls back to the image's stored alt. Empty = decorative. */\n alt?: string;\n /** Delivery width requested for the background image. Defaults to 1920. */\n width?: number;\n /**\n * Responsive URL builder — e.g. `({ src, width }) => \\`${src}?width=${width}&format=auto\\``.\n * When provided, a `srcSet` is generated from `widths`.\n */\n loader?: (params: { src: string; width: number }) => string;\n /** Candidate widths for the generated `srcSet`. */\n widths?: number[];\n /** The `sizes` attribute (defaults to `100vw`, since backgrounds are usually full-bleed). */\n sizes?: string;\n /** Native loading strategy for the background image. */\n loading?: \"eager\" | \"lazy\";\n}\n\nconst DEFAULT_WIDTHS = [640, 750, 828, 1080, 1200, 1920, 2048];\n\nexport function BackgroundImage({\n image,\n children,\n className,\n style,\n imgClassName,\n alt,\n width = 1920,\n loader,\n widths = DEFAULT_WIDTHS,\n sizes = \"100vw\",\n loading,\n ...rest\n}: BackgroundImageProps) {\n const asset = normalizeToAsset(image);\n const src = asset?.src ?? \"\";\n const focalPoint = asset?.image?.focalPoint ?? { x: 0.5, y: 0.5 };\n const resolvedAlt = alt ?? asset?.image?.alt ?? \"\";\n\n const resolvedSrc = loader ? loader({ src, width }) : src;\n const srcSet = loader\n ? widths.map(w => `${loader({ src, width: w })} ${w}w`).join(\", \") || undefined\n : undefined;\n\n return (\n <div\n {...rest}\n className={className}\n style={{ position: \"relative\", overflow: \"hidden\", ...style }}\n >\n <img\n className={imgClassName}\n src={resolvedSrc}\n srcSet={srcSet}\n sizes={srcSet ? sizes : undefined}\n alt={resolvedAlt}\n aria-hidden={resolvedAlt === \"\" ? true : undefined}\n loading={loading}\n style={{\n position: \"absolute\",\n inset: 0,\n width: \"100%\",\n height: \"100%\",\n objectFit: \"cover\",\n objectPosition: `${focalPoint.x * 100}% ${focalPoint.y * 100}%`\n }}\n />\n {children != null ? (\n <div style={{ position: \"relative\", zIndex: 1 }}>{children}</div>\n ) : null}\n </div>\n );\n}\n"],"names":["DEFAULT_WIDTHS","BackgroundImage","image","children","className","style","imgClassName","alt","width","loader","widths","sizes","loading","rest","asset","normalizeToAsset","src","focalPoint","resolvedAlt","resolvedSrc","srcSet","w","undefined"],"mappings":";;AA+BA,MAAMA,iBAAiB;IAAC;IAAK;IAAK;IAAK;IAAM;IAAM;IAAM;CAAK;AAEvD,SAASC,gBAAgB,EAC5BC,KAAK,EACLC,QAAQ,EACRC,SAAS,EACTC,KAAK,EACLC,YAAY,EACZC,GAAG,EACHC,QAAQ,IAAI,EACZC,MAAM,EACNC,SAASV,cAAc,EACvBW,QAAQ,OAAO,EACfC,OAAO,EACP,GAAGC,MACgB;IACnB,MAAMC,QAAQC,iBAAiBb;IAC/B,MAAMc,MAAMF,OAAO,OAAO;IAC1B,MAAMG,aAAaH,OAAO,OAAO,cAAc;QAAE,GAAG;QAAK,GAAG;IAAI;IAChE,MAAMI,cAAcX,OAAOO,OAAO,OAAO,OAAO;IAEhD,MAAMK,cAAcV,SAASA,OAAO;QAAEO;QAAKR;IAAM,KAAKQ;IACtD,MAAMI,SAASX,SACTC,OAAO,GAAG,CAACW,CAAAA,IAAK,GAAGZ,OAAO;YAAEO;YAAK,OAAOK;QAAE,GAAG,CAAC,EAAEA,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,SAASC,SACpEA;IAEN,OAAO,WAAP,GACI,oBAAC;QACI,GAAGT,IAAI;QACR,WAAWT;QACX,OAAO;YAAE,UAAU;YAAY,UAAU;YAAU,GAAGC,KAAK;QAAC;qBAE5D,oBAAC;QACG,WAAWC;QACX,KAAKa;QACL,QAAQC;QACR,OAAOA,SAAST,QAAQW;QACxB,KAAKJ;QACL,eAAaA,AAAgB,OAAhBA,cAAqB,OAAOI;QACzC,SAASV;QACT,OAAO;YACH,UAAU;YACV,OAAO;YACP,OAAO;YACP,QAAQ;YACR,WAAW;YACX,gBAAgB,GAAGK,AAAe,MAAfA,WAAW,CAAC,CAAO,EAAE,EAAEA,AAAe,MAAfA,WAAW,CAAC,CAAO,CAAC,CAAC;QACnE;QAEHd,AAAY,QAAZA,WAAmB,WAAP,GACT,oBAAC;QAAI,OAAO;YAAE,UAAU;YAAY,QAAQ;QAAE;OAAIA,YAClD;AAGhB"}
@@ -0,0 +1,29 @@
1
+ import React from "react";
2
+ import type { AspectRatioInput, Asset } from "@webiny/website-builder-sdk";
3
+ export interface ImageComponentProps extends Omit<React.ImgHTMLAttributes<HTMLImageElement>, "src" | "width" | "height" | "style" | "alt"> {
4
+ image: Asset;
5
+ /** Target aspect ratio (e.g. `16 / 9` or `{ width, height }`). Omit for the crop's own ratio. */
6
+ aspectRatio?: AspectRatioInput;
7
+ /** Explicit alt text; falls back to the image's stored alt. */
8
+ alt?: string;
9
+ /** Class applied to the wrapper element. */
10
+ className?: string;
11
+ /** Class applied to the `<img>` element. */
12
+ imgClassName?: string;
13
+ /** Extra styles merged into the wrapper (e.g. `maxWidth`). */
14
+ style?: React.CSSProperties;
15
+ /**
16
+ * Optional responsive URL builder — e.g. `({ src, width }) => \`${src}?width=${width}\``.
17
+ * When provided, a `srcSet` is generated from `widths`. This is also the seam for a
18
+ * future server/CDN transform (crop params can be appended here).
19
+ */
20
+ loader?: (params: {
21
+ src: string;
22
+ width: number;
23
+ }) => string;
24
+ /** Candidate widths for the generated `srcSet` (defaults to a common set). */
25
+ widths?: number[];
26
+ /** The `sizes` attribute for responsive selection. */
27
+ sizes?: string;
28
+ }
29
+ export declare function Image({ image, aspectRatio, alt, className, imgClassName, style, loader, widths, sizes, ...imgProps }: ImageComponentProps): React.JSX.Element;
package/image/Image.js ADDED
@@ -0,0 +1,43 @@
1
+ import react from "react";
2
+ import { getImageProps } from "./getImageProps.js";
3
+ const DEFAULT_WIDTHS = [
4
+ 640,
5
+ 750,
6
+ 828,
7
+ 1080,
8
+ 1200,
9
+ 1920,
10
+ 2048
11
+ ];
12
+ function Image({ image, aspectRatio, alt, className, imgClassName, style, loader, widths = DEFAULT_WIDTHS, sizes, ...imgProps }) {
13
+ const { style: containerStyle, imgStyle, src, alt: resolvedAlt, width } = getImageProps(image, {
14
+ aspectRatio,
15
+ alt
16
+ });
17
+ const srcSet = loader ? widths.filter((w)=>!width || w <= width).map((w)=>`${loader({
18
+ src,
19
+ width: w
20
+ })} ${w}w`).join(", ") || void 0 : void 0;
21
+ const resolvedSrc = loader ? loader({
22
+ src,
23
+ width: width || widths[widths.length - 1]
24
+ }) : src;
25
+ return /*#__PURE__*/ react.createElement("div", {
26
+ className: className,
27
+ style: {
28
+ ...containerStyle,
29
+ ...style
30
+ }
31
+ }, /*#__PURE__*/ react.createElement("img", {
32
+ ...imgProps,
33
+ className: imgClassName,
34
+ src: resolvedSrc,
35
+ srcSet: srcSet,
36
+ sizes: sizes,
37
+ alt: resolvedAlt,
38
+ style: imgStyle
39
+ }));
40
+ }
41
+ export { Image };
42
+
43
+ //# sourceMappingURL=Image.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image/Image.js","sources":["../../src/image/Image.tsx"],"sourcesContent":["import React from \"react\";\nimport type { AspectRatioInput, Asset } from \"@webiny/website-builder-sdk\";\nimport { getImageProps } from \"./getImageProps.js\";\n\nexport interface ImageComponentProps extends Omit<\n React.ImgHTMLAttributes<HTMLImageElement>,\n \"src\" | \"width\" | \"height\" | \"style\" | \"alt\"\n> {\n image: Asset;\n /** Target aspect ratio (e.g. `16 / 9` or `{ width, height }`). Omit for the crop's own ratio. */\n aspectRatio?: AspectRatioInput;\n /** Explicit alt text; falls back to the image's stored alt. */\n alt?: string;\n /** Class applied to the wrapper element. */\n className?: string;\n /** Class applied to the `<img>` element. */\n imgClassName?: string;\n /** Extra styles merged into the wrapper (e.g. `maxWidth`). */\n style?: React.CSSProperties;\n /**\n * Optional responsive URL builder — e.g. `({ src, width }) => \\`${src}?width=${width}\\``.\n * When provided, a `srcSet` is generated from `widths`. This is also the seam for a\n * future server/CDN transform (crop params can be appended here).\n */\n loader?: (params: { src: string; width: number }) => string;\n /** Candidate widths for the generated `srcSet` (defaults to a common set). */\n widths?: number[];\n /** The `sizes` attribute for responsive selection. */\n sizes?: string;\n}\n\nconst DEFAULT_WIDTHS = [640, 750, 828, 1080, 1200, 1920, 2048];\n\nexport function Image({\n image,\n aspectRatio,\n alt,\n className,\n imgClassName,\n style,\n loader,\n widths = DEFAULT_WIDTHS,\n sizes,\n ...imgProps\n}: ImageComponentProps) {\n const {\n style: containerStyle,\n imgStyle,\n src,\n alt: resolvedAlt,\n width\n } = getImageProps(image, { aspectRatio, alt });\n\n const srcSet = loader\n ? widths\n .filter(w => !width || w <= width)\n .map(w => `${loader({ src, width: w })} ${w}w`)\n .join(\", \") || undefined\n : undefined;\n\n const resolvedSrc = loader ? loader({ src, width: width || widths[widths.length - 1] }) : src;\n\n return (\n <div className={className} style={{ ...containerStyle, ...style }}>\n <img\n {...imgProps}\n className={imgClassName}\n src={resolvedSrc}\n srcSet={srcSet}\n sizes={sizes}\n alt={resolvedAlt}\n style={imgStyle}\n />\n </div>\n );\n}\n"],"names":["DEFAULT_WIDTHS","Image","image","aspectRatio","alt","className","imgClassName","style","loader","widths","sizes","imgProps","containerStyle","imgStyle","src","resolvedAlt","width","getImageProps","srcSet","w","undefined","resolvedSrc"],"mappings":";;AA+BA,MAAMA,iBAAiB;IAAC;IAAK;IAAK;IAAK;IAAM;IAAM;IAAM;CAAK;AAEvD,SAASC,MAAM,EAClBC,KAAK,EACLC,WAAW,EACXC,GAAG,EACHC,SAAS,EACTC,YAAY,EACZC,KAAK,EACLC,MAAM,EACNC,SAAST,cAAc,EACvBU,KAAK,EACL,GAAGC,UACe;IAClB,MAAM,EACF,OAAOC,cAAc,EACrBC,QAAQ,EACRC,GAAG,EACH,KAAKC,WAAW,EAChBC,KAAK,EACR,GAAGC,cAAcf,OAAO;QAAEC;QAAaC;IAAI;IAE5C,MAAMc,SAASV,SACTC,OACK,MAAM,CAACU,CAAAA,IAAK,CAACH,SAASG,KAAKH,OAC3B,GAAG,CAACG,CAAAA,IAAK,GAAGX,OAAO;YAAEM;YAAK,OAAOK;QAAE,GAAG,CAAC,EAAEA,EAAE,CAAC,CAAC,EAC7C,IAAI,CAAC,SAASC,SACnBA;IAEN,MAAMC,cAAcb,SAASA,OAAO;QAAEM;QAAK,OAAOE,SAASP,MAAM,CAACA,OAAO,MAAM,GAAG,EAAE;IAAC,KAAKK;IAE1F,OAAO,WAAP,GACI,oBAAC;QAAI,WAAWT;QAAW,OAAO;YAAE,GAAGO,cAAc;YAAE,GAAGL,KAAK;QAAC;qBAC5D,oBAAC;QACI,GAAGI,QAAQ;QACZ,WAAWL;QACX,KAAKe;QACL,QAAQH;QACR,OAAOR;QACP,KAAKK;QACL,OAAOF;;AAIvB"}
@@ -0,0 +1,42 @@
1
+ import type { CSSProperties } from "react";
2
+ import { type AspectRatioInput, type Asset } from "@webiny/website-builder-sdk";
3
+ export interface ImageProps {
4
+ /** Wrapper style: an aspect-ratio box that clips overflow. Spread onto a container. */
5
+ style: CSSProperties;
6
+ /** Image style: absolutely positioned to reveal exactly the cropped/focused region. */
7
+ imgStyle: CSSProperties;
8
+ /** The image URL. */
9
+ src: string;
10
+ /** Resolved alt text (explicit override, else the image's stored alt, else ""). */
11
+ alt: string;
12
+ /** Intrinsic (original) pixel dimensions of the asset. */
13
+ width: number;
14
+ height: number;
15
+ }
16
+ export interface ImageValue {
17
+ id: string;
18
+ name: string;
19
+ size: number;
20
+ mimeType: string;
21
+ src: string;
22
+ width: number;
23
+ height: number;
24
+ }
25
+ export interface GetImagePropsOptions {
26
+ /** Target aspect ratio. Omit to render at the crop's own aspect ratio. */
27
+ aspectRatio?: AspectRatioInput;
28
+ /** Explicit alt text; falls back to the image's stored `image.alt`. */
29
+ alt?: string;
30
+ }
31
+ /**
32
+ * Compute the props needed to render a Webiny image honoring its crop + focal point,
33
+ * using pure CSS (no image backend). Works with a plain `<img>`, SSR, and static
34
+ * export. Spread `style` onto a wrapper element and `imgStyle` onto the `<img>`.
35
+ *
36
+ * Accepts either the unified {@link Asset} shape or a legacy
37
+ * `ImageValue` (existing page snapshots) — both are normalized transparently.
38
+ *
39
+ * This is the escape hatch for custom rendering; most consumers can use the
40
+ * `<Image>` component instead.
41
+ */
42
+ export declare function getImageProps(input: Asset | ImageValue, options?: GetImagePropsOptions): ImageProps;
@@ -0,0 +1,18 @@
1
+ import { getAssetImageRenderData, normalizeToAsset } from "@webiny/website-builder-sdk";
2
+ function getImageProps(input, options = {}) {
3
+ const asset = normalizeToAsset(input);
4
+ const data = getAssetImageRenderData({
5
+ image: asset?.image
6
+ }, options.aspectRatio);
7
+ return {
8
+ style: data.container,
9
+ imgStyle: data.image,
10
+ src: asset?.src ?? "",
11
+ alt: options.alt ?? asset?.image?.alt ?? "",
12
+ width: data.intrinsicWidth,
13
+ height: data.intrinsicHeight
14
+ };
15
+ }
16
+ export { getImageProps };
17
+
18
+ //# sourceMappingURL=getImageProps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image/getImageProps.js","sources":["../../src/image/getImageProps.ts"],"sourcesContent":["import type { CSSProperties } from \"react\";\nimport {\n getAssetImageRenderData,\n normalizeToAsset,\n type AspectRatioInput,\n type Asset\n} from \"@webiny/website-builder-sdk\";\n\nexport interface ImageProps {\n /** Wrapper style: an aspect-ratio box that clips overflow. Spread onto a container. */\n style: CSSProperties;\n /** Image style: absolutely positioned to reveal exactly the cropped/focused region. */\n imgStyle: CSSProperties;\n /** The image URL. */\n src: string;\n /** Resolved alt text (explicit override, else the image's stored alt, else \"\"). */\n alt: string;\n /** Intrinsic (original) pixel dimensions of the asset. */\n width: number;\n height: number;\n}\n\nexport interface ImageValue {\n id: string;\n name: string;\n size: number;\n mimeType: string; // not \"type\"\n src: string;\n width: number; // top-level, not nested in image\n height: number; // top-level\n}\n\nexport interface GetImagePropsOptions {\n /** Target aspect ratio. Omit to render at the crop's own aspect ratio. */\n aspectRatio?: AspectRatioInput;\n /** Explicit alt text; falls back to the image's stored `image.alt`. */\n alt?: string;\n}\n\n/**\n * Compute the props needed to render a Webiny image honoring its crop + focal point,\n * using pure CSS (no image backend). Works with a plain `<img>`, SSR, and static\n * export. Spread `style` onto a wrapper element and `imgStyle` onto the `<img>`.\n *\n * Accepts either the unified {@link Asset} shape or a legacy\n * `ImageValue` (existing page snapshots) — both are normalized transparently.\n *\n * This is the escape hatch for custom rendering; most consumers can use the\n * `<Image>` component instead.\n */\nexport function getImageProps(\n input: Asset | ImageValue,\n options: GetImagePropsOptions = {}\n): ImageProps {\n const asset = normalizeToAsset(input);\n const data = getAssetImageRenderData({ image: asset?.image }, options.aspectRatio);\n\n return {\n style: data.container,\n imgStyle: data.image,\n src: asset?.src ?? \"\",\n alt: options.alt ?? asset?.image?.alt ?? \"\",\n width: data.intrinsicWidth,\n height: data.intrinsicHeight\n };\n}\n"],"names":["getImageProps","input","options","asset","normalizeToAsset","data","getAssetImageRenderData"],"mappings":";AAkDO,SAASA,cACZC,KAAyB,EACzBC,UAAgC,CAAC,CAAC;IAElC,MAAMC,QAAQC,iBAAiBH;IAC/B,MAAMI,OAAOC,wBAAwB;QAAE,OAAOH,OAAO;IAAM,GAAGD,QAAQ,WAAW;IAEjF,OAAO;QACH,OAAOG,KAAK,SAAS;QACrB,UAAUA,KAAK,KAAK;QACpB,KAAKF,OAAO,OAAO;QACnB,KAAKD,QAAQ,GAAG,IAAIC,OAAO,OAAO,OAAO;QACzC,OAAOE,KAAK,cAAc;QAC1B,QAAQA,KAAK,eAAe;IAChC;AACJ"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,70 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { getImageProps } from "./getImageProps.js";
3
+ const asset = (overrides = {})=>({
4
+ id: "1",
5
+ name: "photo.jpg",
6
+ size: 1234,
7
+ type: "image/jpeg",
8
+ src: "https://cdn.test/photo.jpg",
9
+ url: "https://cdn.test/photo.jpg",
10
+ image: {
11
+ width: 1600,
12
+ height: 900
13
+ },
14
+ ...overrides
15
+ });
16
+ describe("getImageProps", ()=>{
17
+ it("returns wrapper + image styles and passes through src and dimensions", ()=>{
18
+ const props = getImageProps(asset());
19
+ expect(props.src).toBe("https://cdn.test/photo.jpg");
20
+ expect(props.width).toBe(1600);
21
+ expect(props.height).toBe(900);
22
+ expect(props.style.overflow).toBe("hidden");
23
+ expect(props.style.position).toBe("relative");
24
+ expect(props.imgStyle.position).toBe("absolute");
25
+ });
26
+ it("resolves alt from the explicit option first", ()=>{
27
+ const props = getImageProps(asset({
28
+ image: {
29
+ alt: "stored alt"
30
+ }
31
+ }), {
32
+ alt: "explicit alt"
33
+ });
34
+ expect(props.alt).toBe("explicit alt");
35
+ });
36
+ it("falls back to the image's stored alt", ()=>{
37
+ const props = getImageProps(asset({
38
+ image: {
39
+ alt: "stored alt"
40
+ }
41
+ }));
42
+ expect(props.alt).toBe("stored alt");
43
+ });
44
+ it("defaults alt to an empty string", ()=>{
45
+ expect(getImageProps(asset()).alt).toBe("");
46
+ });
47
+ it("produces a wrapper with the requested aspect ratio", ()=>{
48
+ const props = getImageProps(asset(), {
49
+ aspectRatio: 1
50
+ });
51
+ expect(props.style.aspectRatio).toBe("1");
52
+ });
53
+ it("offsets the image to reveal a focal-point-shifted crop region", ()=>{
54
+ const props = getImageProps(asset({
55
+ image: {
56
+ width: 1600,
57
+ height: 900,
58
+ focalPoint: {
59
+ x: 0.9,
60
+ y: 0.5
61
+ }
62
+ }
63
+ }), {
64
+ aspectRatio: 1
65
+ });
66
+ expect(parseFloat(props.imgStyle.left)).toBeLessThan(0);
67
+ });
68
+ });
69
+
70
+ //# sourceMappingURL=getImageProps.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image/getImageProps.test.js","sources":["../../src/image/getImageProps.test.ts"],"sourcesContent":["import { describe, expect, it } from \"vitest\";\nimport { getImageProps } from \"./getImageProps.js\";\nimport type { Asset } from \"@webiny/website-builder-sdk\";\n\nconst asset = (overrides: Partial<Asset> = {}): Asset => ({\n id: \"1\",\n name: \"photo.jpg\",\n size: 1234,\n type: \"image/jpeg\",\n src: \"https://cdn.test/photo.jpg\",\n url: \"https://cdn.test/photo.jpg\",\n image: { width: 1600, height: 900 },\n ...overrides\n});\n\ndescribe(\"getImageProps\", () => {\n it(\"returns wrapper + image styles and passes through src and dimensions\", () => {\n const props = getImageProps(asset());\n expect(props.src).toBe(\"https://cdn.test/photo.jpg\");\n expect(props.width).toBe(1600);\n expect(props.height).toBe(900);\n expect(props.style.overflow).toBe(\"hidden\");\n expect(props.style.position).toBe(\"relative\");\n expect(props.imgStyle.position).toBe(\"absolute\");\n });\n\n it(\"resolves alt from the explicit option first\", () => {\n const props = getImageProps(asset({ image: { alt: \"stored alt\" } }), {\n alt: \"explicit alt\"\n });\n expect(props.alt).toBe(\"explicit alt\");\n });\n\n it(\"falls back to the image's stored alt\", () => {\n const props = getImageProps(asset({ image: { alt: \"stored alt\" } }));\n expect(props.alt).toBe(\"stored alt\");\n });\n\n it(\"defaults alt to an empty string\", () => {\n expect(getImageProps(asset()).alt).toBe(\"\");\n });\n\n it(\"produces a wrapper with the requested aspect ratio\", () => {\n const props = getImageProps(asset(), { aspectRatio: 1 });\n expect(props.style.aspectRatio).toBe(\"1\");\n });\n\n it(\"offsets the image to reveal a focal-point-shifted crop region\", () => {\n const props = getImageProps(\n asset({\n image: {\n width: 1600,\n height: 900,\n focalPoint: { x: 0.9, y: 0.5 }\n }\n }),\n { aspectRatio: 1 }\n );\n expect(parseFloat(props.imgStyle.left as string)).toBeLessThan(0);\n });\n});\n"],"names":["asset","overrides","describe","it","props","getImageProps","expect","parseFloat"],"mappings":";;AAIA,MAAMA,QAAQ,CAACC,YAA4B,CAAC,CAAC,GAAa;QACtD,IAAI;QACJ,MAAM;QACN,MAAM;QACN,MAAM;QACN,KAAK;QACL,KAAK;QACL,OAAO;YAAE,OAAO;YAAM,QAAQ;QAAI;QAClC,GAAGA,SAAS;IAChB;AAEAC,SAAS,iBAAiB;IACtBC,GAAG,wEAAwE;QACvE,MAAMC,QAAQC,cAAcL;QAC5BM,OAAOF,MAAM,GAAG,EAAE,IAAI,CAAC;QACvBE,OAAOF,MAAM,KAAK,EAAE,IAAI,CAAC;QACzBE,OAAOF,MAAM,MAAM,EAAE,IAAI,CAAC;QAC1BE,OAAOF,MAAM,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC;QAClCE,OAAOF,MAAM,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC;QAClCE,OAAOF,MAAM,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC;IACzC;IAEAD,GAAG,+CAA+C;QAC9C,MAAMC,QAAQC,cAAcL,MAAM;YAAE,OAAO;gBAAE,KAAK;YAAa;QAAE,IAAI;YACjE,KAAK;QACT;QACAM,OAAOF,MAAM,GAAG,EAAE,IAAI,CAAC;IAC3B;IAEAD,GAAG,wCAAwC;QACvC,MAAMC,QAAQC,cAAcL,MAAM;YAAE,OAAO;gBAAE,KAAK;YAAa;QAAE;QACjEM,OAAOF,MAAM,GAAG,EAAE,IAAI,CAAC;IAC3B;IAEAD,GAAG,mCAAmC;QAClCG,OAAOD,cAAcL,SAAS,GAAG,EAAE,IAAI,CAAC;IAC5C;IAEAG,GAAG,sDAAsD;QACrD,MAAMC,QAAQC,cAAcL,SAAS;YAAE,aAAa;QAAE;QACtDM,OAAOF,MAAM,KAAK,CAAC,WAAW,EAAE,IAAI,CAAC;IACzC;IAEAD,GAAG,iEAAiE;QAChE,MAAMC,QAAQC,cACVL,MAAM;YACF,OAAO;gBACH,OAAO;gBACP,QAAQ;gBACR,YAAY;oBAAE,GAAG;oBAAK,GAAG;gBAAI;YACjC;QACJ,IACA;YAAE,aAAa;QAAE;QAErBM,OAAOC,WAAWH,MAAM,QAAQ,CAAC,IAAI,GAAa,YAAY,CAAC;IACnE;AACJ"}
@@ -0,0 +1,3 @@
1
+ export * from "./getImageProps.js";
2
+ export * from "./Image.js";
3
+ export * from "./BackgroundImage.js";
package/image/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export * from "./getImageProps.js";
2
+ export * from "./Image.js";
3
+ export * from "./BackgroundImage.js";
package/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export * from "./components/index.js";
2
- export * from "./createComponent.js";
3
- export { createTextInput, createLongTextInput, createNumberInput, createBooleanInput, createColorInput, createFileInput, createDateInput, createLexicalInput, createSelectInput, createRadioInput, createObjectInput, createTagsInput, createSlotInput, createInput, createElement, createTheme, contentSdk, environment, setHeadersProvider, getHeadersProvider, registerComponentGroup, type CssProperties, type Document, type DocumentElement, type Breakpoint, type CreateElementParams, type ContentSDKConfig, type ComponentManifest, type ComponentInput, type ComponentConstraint, type WebsiteBuilderThemeInput, StyleSettings } from "@webiny/website-builder-sdk";
2
+ export { createComponent } from "@webiny/website-builder-sdk";
3
+ export { createTextInput, createLongTextInput, createNumberInput, createBooleanInput, createColorInput, createFileInput, createDateInput, createLexicalInput, createSelectInput, createRadioInput, createObjectInput, createTagsInput, createSlotInput, createInput, createElement, createTheme, contentSdk, environment, setHeadersProvider, getHeadersProvider, registerComponentGroup, getPageWithExperiment, resolveVisitorContext, assignVariant, forcedAssignment, registerAnalyticsProvider, getAnalyticsProvider, ASPECT_RATIO_PRESETS, FORCED_VARIANT_PARAM, DEFAULT_VISITOR_COOKIE, CONTROL_VARIANT_ID, type ActiveExperiment, type ActiveExperimentVariant, type VariantContent, type VariantAssignment, type VisitorContext, type DeviceType, type ExperimentTrafficSplit, type ExperimentTargeting, type ExperimentAnalyticsConfig, type ExperimentSdk, type ExperimentRenderResult, type GetPageWithExperimentOptions, type ExperimentCookie, type CssProperties, type Document, type DocumentElement, type Breakpoint, type CreateElementParams, type ContentSDKConfig, type ComponentManifest, type ComponentInput, type ComponentConstraint, type WebsiteBuilderThemeInput, type AssetCrop, type AssetFocalPoint, type Asset, type AssetImage, type AssetDocument, type AssetVideo, type AssetCategory, normalizeToAsset, getAssetCategory, getAssetUrl, getAssetCropParam, type AssetUrlOptions, IMAGE_RESIZE_WIDTHS, getImageSrcSet, getImageDimensions, type ImageSrcSet, type ImageSrcSetOptions, type ImageDimensions, type AspectRatioInput, type AspectRatioPreset, StyleSettings } from "@webiny/website-builder-sdk";
4
4
  export type { ComponentProps, ComponentPropsWithChildren, InferManifest, InferComponentChange, InferDescendantChange } from "./types.js";
package/index.js CHANGED
@@ -1,3 +1,2 @@
1
1
  export * from "./components/index.js";
2
- export * from "./createComponent.js";
3
- export { StyleSettings, contentSdk, createBooleanInput, createColorInput, createDateInput, createElement, createFileInput, createInput, createLexicalInput, createLongTextInput, createNumberInput, createObjectInput, createRadioInput, createSelectInput, createSlotInput, createTagsInput, createTextInput, createTheme, environment, getHeadersProvider, registerComponentGroup, setHeadersProvider } from "@webiny/website-builder-sdk";
2
+ export { ASPECT_RATIO_PRESETS, CONTROL_VARIANT_ID, DEFAULT_VISITOR_COOKIE, FORCED_VARIANT_PARAM, IMAGE_RESIZE_WIDTHS, StyleSettings, assignVariant, contentSdk, createBooleanInput, createColorInput, createComponent, createDateInput, createElement, createFileInput, createInput, createLexicalInput, createLongTextInput, createNumberInput, createObjectInput, createRadioInput, createSelectInput, createSlotInput, createTagsInput, createTextInput, createTheme, environment, forcedAssignment, getAnalyticsProvider, getAssetCategory, getAssetCropParam, getAssetUrl, getHeadersProvider, getImageDimensions, getImageSrcSet, getPageWithExperiment, normalizeToAsset, registerAnalyticsProvider, registerComponentGroup, resolveVisitorContext, setHeadersProvider } from "@webiny/website-builder-sdk";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webiny/website-builder-react",
3
- "version": "6.6.0-alpha.0",
3
+ "version": "6.6.0-alpha.2",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -17,18 +17,18 @@
17
17
  ],
18
18
  "license": "MIT",
19
19
  "dependencies": {
20
- "@webiny/website-builder-sdk": "6.6.0-alpha.0",
20
+ "@webiny/website-builder-sdk": "6.6.0-alpha.2",
21
21
  "deep-equal": "2.2.3",
22
- "mobx": "6.16.1",
23
- "mobx-react-lite": "4.1.1",
22
+ "mobx": "7.0.3",
23
+ "mobx-react-lite": "5.0.3",
24
24
  "react": "18.3.1",
25
25
  "react-dom": "18.3.1"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@types/react": "18.3.31",
29
- "@webiny/build-tools": "6.6.0-alpha.0",
29
+ "@webiny/build-tools": "6.6.0-alpha.2",
30
30
  "typescript": "7.0.2",
31
- "vitest": "4.1.10"
31
+ "vitest": "4.1.11"
32
32
  },
33
33
  "publishConfig": {
34
34
  "access": "public"
package/types.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- import type { CssProperties, DocumentElement, ComponentManifestInput, ComponentChangeHandler, DescendantChangeHandler } from "@webiny/website-builder-sdk";
1
+ import type { CssProperties, DocumentElement, ComponentManifestInput, ComponentChangeHandler, DescendantChangeHandler, ExtractInputs } from "@webiny/website-builder-sdk";
2
+ export type { ExtractInputs } from "@webiny/website-builder-sdk";
2
3
  export type ComponentProps<TInputs = unknown> = {
3
4
  inputs: TInputs;
4
5
  styles: CssProperties;
@@ -8,9 +9,6 @@ export type ComponentProps<TInputs = unknown> = {
8
9
  export type ComponentPropsWithChildren<TInputs = unknown> = ComponentProps<TInputs & {
9
10
  children: React.ReactNode;
10
11
  }>;
11
- export type ExtractInputs<T> = T extends {
12
- inputs: infer I;
13
- } ? I : never;
14
12
  export type ExtractInputNames<T extends (props: any) => any> = keyof ExtractInputs<Parameters<T>[0]>;
15
13
  /**
16
14
  * Infer the full typed ComponentManifestInput from a React component.
@@ -1 +0,0 @@
1
- {"version":3,"file":"createComponent.js","sources":["../src/createComponent.ts"],"sourcesContent":["import type {\n Component,\n ComponentInput,\n ComponentManifest,\n ComponentManifestInput,\n InputFactory\n} from \"@webiny/website-builder-sdk\";\nimport { createSlotInput } from \"@webiny/website-builder-sdk\";\nimport type { ExtractInputs } from \"~/types.js\";\n\nexport function createComponent<\n TComponent extends (props: any) => any,\n TInputs extends ExtractInputs<Parameters<TComponent>[0]>\n>(component: TComponent, manifest: ComponentManifestInput<TInputs>): Component {\n const inputs: ComponentInput[] = [];\n\n // Normalize inputs to always be an array of objects.\n\n if (Array.isArray(manifest.inputs)) {\n inputs.push(...manifest.inputs);\n } else {\n const inputsObject: Record<string, InputFactory<any>> = manifest.inputs ?? {};\n Object.keys(inputsObject).forEach((name: string) => {\n inputs.push({ ...inputsObject[name], name });\n });\n }\n\n const acceptsChildren = manifest.acceptsChildren;\n\n if (acceptsChildren) {\n const hasChildren = inputs.some(input => input.name === \"children\");\n if (!hasChildren) {\n inputs.push(createSlotInput({ name: \"children\" }));\n }\n }\n\n return {\n component,\n manifest: { ...manifest, tags: manifest.tags ?? [], inputs } as ComponentManifest\n };\n}\n"],"names":["createComponent","component","manifest","inputs","Array","inputsObject","Object","name","acceptsChildren","hasChildren","input","createSlotInput"],"mappings":";AAUO,SAASA,gBAGdC,SAAqB,EAAEC,QAAyC;IAC9D,MAAMC,SAA2B,EAAE;IAInC,IAAIC,MAAM,OAAO,CAACF,SAAS,MAAM,GAC7BC,OAAO,IAAI,IAAID,SAAS,MAAM;SAC3B;QACH,MAAMG,eAAkDH,SAAS,MAAM,IAAI,CAAC;QAC5EI,OAAO,IAAI,CAACD,cAAc,OAAO,CAAC,CAACE;YAC/BJ,OAAO,IAAI,CAAC;gBAAE,GAAGE,YAAY,CAACE,KAAK;gBAAEA;YAAK;QAC9C;IACJ;IAEA,MAAMC,kBAAkBN,SAAS,eAAe;IAEhD,IAAIM,iBAAiB;QACjB,MAAMC,cAAcN,OAAO,IAAI,CAACO,CAAAA,QAASA,AAAe,eAAfA,MAAM,IAAI;QACnD,IAAI,CAACD,aACDN,OAAO,IAAI,CAACQ,gBAAgB;YAAE,MAAM;QAAW;IAEvD;IAEA,OAAO;QACHV;QACA,UAAU;YAAE,GAAGC,QAAQ;YAAE,MAAMA,SAAS,IAAI,IAAI,EAAE;YAAEC;QAAO;IAC/D;AACJ"}