@webiny/app-website-builder 6.6.0-alpha.8 → 6.6.0-alpha.9

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.
@@ -80,8 +80,7 @@ const BackgroundImage = observer(({ elementId })=>{
80
80
  type: "compact",
81
81
  value: url ? fileInfo : void 0,
82
82
  onSelectItem: ()=>showFileManager(),
83
- onRemoveItem: onRemove,
84
- onEditItem: ()=>showFileManager()
83
+ onRemoveItem: onRemove
85
84
  })
86
85
  }));
87
86
  });
@@ -1 +1 @@
1
- {"version":3,"file":"BaseEditor/defaultConfig/Sidebar/StyleSettings/Groups/Background/BackgroundImage.js","sources":["../../../../../../../src/BaseEditor/defaultConfig/Sidebar/StyleSettings/Groups/Background/BackgroundImage.tsx"],"sourcesContent":["import React, { useEffect, useState, useMemo } from \"react\";\nimport { observer } from \"mobx-react-lite\";\nimport { FileManager, type FileManagerFileItem } from \"@webiny/app-admin\";\nimport { FilePicker } from \"@webiny/admin-ui\";\nimport { useStyles } from \"~/BaseEditor/defaultConfig/Sidebar/StyleSettings/useStyles.js\";\nimport { BackgroundImageParser } from \"./BackgroundImageParser.js\";\nimport { useBreakpoint } from \"~/BaseEditor/hooks/useBreakpoint.js\";\nimport { InheritanceLabel } from \"../../../InheritanceLabel.js\";\nimport { SidebarRow } from \"~/BaseEditor/defaultConfig/Sidebar/StyleSettings/SidebarRow.js\";\n\ntype FileInfo = {\n id: string;\n name: string;\n size: number;\n type: string;\n url: string;\n};\n\nconst DEFAULT_POSITION = \"center\";\nconst DEFAULT_SCALING = {\n backgroundSize: \"cover\",\n backgroundRepeat: \"no-repeat\"\n};\n\nexport const parseValue = (value: string) => {\n if (!value) {\n return undefined;\n }\n\n return;\n};\n\nexport const BackgroundImage = observer(({ elementId }: { elementId: string }) => {\n const { isBaseBreakpoint } = useBreakpoint();\n const { styles, metadata, onChange, inheritanceMap } = useStyles(elementId);\n const [localValue, setLocalValue] = useState<string | null>(styles.backgroundImage);\n const url = useMemo(() => {\n const parser = new BackgroundImageParser(styles.backgroundImage);\n const rules = parser.getRules();\n const urlRule = rules.find(r => r.type === \"url\");\n if (urlRule && urlRule.type === \"url\") {\n return urlRule.parsed.url;\n }\n return null;\n }, [styles.backgroundImage]);\n\n useEffect(() => {\n if (styles.backgroundImage !== localValue) {\n setLocalValue(styles.backgroundImage);\n }\n }, [styles.backgroundImage]);\n\n const onFileChange = (file: FileManagerFileItem) => {\n onChange(({ styles, metadata }) => {\n styles.set(\"backgroundPosition\", DEFAULT_POSITION);\n styles.set(\"backgroundSize\", DEFAULT_SCALING.backgroundSize);\n styles.set(\"backgroundRepeat\", DEFAULT_SCALING.backgroundRepeat);\n styles.set(\"backgroundImage\", `url(\"${file.src}\")`);\n\n metadata.set(\"backgroundImage\", {\n id: file.id,\n name: file.name,\n size: file.size,\n type: file.type,\n url: file.src || \"\"\n });\n });\n };\n\n const onRemove = () => {\n onChange(({ styles, metadata }) => {\n // On base breakpoint, we unset the image and all styles related to it.\n if (isBaseBreakpoint) {\n styles.unset(\"backgroundImage\");\n styles.unset(\"backgroundPosition\");\n styles.unset(\"backgroundSize\");\n styles.unset(\"backgroundRepeat\");\n } else {\n styles.set(\"backgroundImage\", \"none\");\n }\n\n metadata.unset(\"backgroundImage\");\n });\n };\n\n const onReset = () => {\n onChange(({ styles }) => {\n styles.unset(\"backgroundImage\");\n\n metadata.unset(\"backgroundImage\");\n });\n };\n\n const inheritance = inheritanceMap?.backgroundImage ?? {};\n\n const fileInfo = metadata.get<FileInfo>(\"backgroundImage\");\n\n return (\n <SidebarRow\n label={\n <InheritanceLabel\n onReset={onReset}\n isOverridden={inheritance?.overridden ?? false}\n inheritedFrom={inheritance?.inheritedFrom}\n text={\"Image\"}\n />\n }\n >\n <FileManager\n images={true}\n onChange={onFileChange}\n render={({ showFileManager }) => (\n <FilePicker\n variant={\"secondary\"}\n type=\"compact\"\n value={url ? fileInfo : undefined}\n onSelectItem={() => showFileManager()}\n onRemoveItem={onRemove}\n onEditItem={() => showFileManager()}\n />\n )}\n />\n </SidebarRow>\n );\n});\n"],"names":["DEFAULT_POSITION","DEFAULT_SCALING","parseValue","value","BackgroundImage","observer","elementId","isBaseBreakpoint","useBreakpoint","styles","metadata","onChange","inheritanceMap","useStyles","localValue","setLocalValue","useState","url","useMemo","parser","BackgroundImageParser","rules","urlRule","r","useEffect","onFileChange","file","onRemove","onReset","inheritance","fileInfo","SidebarRow","InheritanceLabel","FileManager","showFileManager","FilePicker","undefined"],"mappings":";;;;;;;;;AAkBA,MAAMA,mBAAmB;AACzB,MAAMC,kBAAkB;IACpB,gBAAgB;IAChB,kBAAkB;AACtB;AAEO,MAAMC,aAAa,CAACC,SAM3B;AAEO,MAAMC,kBAAkBC,SAAS,CAAC,EAAEC,SAAS,EAAyB;IACzE,MAAM,EAAEC,gBAAgB,EAAE,GAAGC;IAC7B,MAAM,EAAEC,MAAM,EAAEC,QAAQ,EAAEC,QAAQ,EAAEC,cAAc,EAAE,GAAGC,UAAUP;IACjE,MAAM,CAACQ,YAAYC,cAAc,GAAGC,SAAwBP,OAAO,eAAe;IAClF,MAAMQ,MAAMC,QAAQ;QAChB,MAAMC,SAAS,IAAIC,sBAAsBX,OAAO,eAAe;QAC/D,MAAMY,QAAQF,OAAO,QAAQ;QAC7B,MAAMG,UAAUD,MAAM,IAAI,CAACE,CAAAA,IAAKA,AAAW,UAAXA,EAAE,IAAI;QACtC,IAAID,WAAWA,AAAiB,UAAjBA,QAAQ,IAAI,EACvB,OAAOA,QAAQ,MAAM,CAAC,GAAG;QAE7B,OAAO;IACX,GAAG;QAACb,OAAO,eAAe;KAAC;IAE3Be,UAAU;QACN,IAAIf,OAAO,eAAe,KAAKK,YAC3BC,cAAcN,OAAO,eAAe;IAE5C,GAAG;QAACA,OAAO,eAAe;KAAC;IAE3B,MAAMgB,eAAe,CAACC;QAClBf,SAAS,CAAC,EAAEF,MAAM,EAAEC,QAAQ,EAAE;YAC1BD,OAAO,GAAG,CAAC,sBAAsBT;YACjCS,OAAO,GAAG,CAAC,kBAAkBR,gBAAgB,cAAc;YAC3DQ,OAAO,GAAG,CAAC,oBAAoBR,gBAAgB,gBAAgB;YAC/DQ,OAAO,GAAG,CAAC,mBAAmB,CAAC,KAAK,EAAEiB,KAAK,GAAG,CAAC,EAAE,CAAC;YAElDhB,SAAS,GAAG,CAAC,mBAAmB;gBAC5B,IAAIgB,KAAK,EAAE;gBACX,MAAMA,KAAK,IAAI;gBACf,MAAMA,KAAK,IAAI;gBACf,MAAMA,KAAK,IAAI;gBACf,KAAKA,KAAK,GAAG,IAAI;YACrB;QACJ;IACJ;IAEA,MAAMC,WAAW;QACbhB,SAAS,CAAC,EAAEF,MAAM,EAAEC,QAAQ,EAAE;YAE1B,IAAIH,kBAAkB;gBAClBE,OAAO,KAAK,CAAC;gBACbA,OAAO,KAAK,CAAC;gBACbA,OAAO,KAAK,CAAC;gBACbA,OAAO,KAAK,CAAC;YACjB,OACIA,OAAO,GAAG,CAAC,mBAAmB;YAGlCC,SAAS,KAAK,CAAC;QACnB;IACJ;IAEA,MAAMkB,UAAU;QACZjB,SAAS,CAAC,EAAEF,MAAM,EAAE;YAChBA,OAAO,KAAK,CAAC;YAEbC,SAAS,KAAK,CAAC;QACnB;IACJ;IAEA,MAAMmB,cAAcjB,gBAAgB,mBAAmB,CAAC;IAExD,MAAMkB,WAAWpB,SAAS,GAAG,CAAW;IAExC,OAAO,WAAP,GACI,oBAACqB,YAAUA;QACP,qBACI,oBAACC,kBAAgBA;YACb,SAASJ;YACT,cAAcC,aAAa,cAAc;YACzC,eAAeA,aAAa;YAC5B,MAAM;;qBAId,oBAACI,aAAWA;QACR,QAAQ;QACR,UAAUR;QACV,QAAQ,CAAC,EAAES,eAAe,EAAE,iBACxB,oBAACC,YAAUA;gBACP,SAAS;gBACT,MAAK;gBACL,OAAOlB,MAAMa,WAAWM;gBACxB,cAAc,IAAMF;gBACpB,cAAcP;gBACd,YAAY,IAAMO;;;AAM1C"}
1
+ {"version":3,"file":"BaseEditor/defaultConfig/Sidebar/StyleSettings/Groups/Background/BackgroundImage.js","sources":["../../../../../../../src/BaseEditor/defaultConfig/Sidebar/StyleSettings/Groups/Background/BackgroundImage.tsx"],"sourcesContent":["import React, { useEffect, useState, useMemo } from \"react\";\nimport { observer } from \"mobx-react-lite\";\nimport { FileManager, type FileManagerFileItem } from \"@webiny/app-admin\";\nimport { FilePicker } from \"@webiny/admin-ui\";\nimport { useStyles } from \"~/BaseEditor/defaultConfig/Sidebar/StyleSettings/useStyles.js\";\nimport { BackgroundImageParser } from \"./BackgroundImageParser.js\";\nimport { useBreakpoint } from \"~/BaseEditor/hooks/useBreakpoint.js\";\nimport { InheritanceLabel } from \"../../../InheritanceLabel.js\";\nimport { SidebarRow } from \"~/BaseEditor/defaultConfig/Sidebar/StyleSettings/SidebarRow.js\";\n\ntype FileInfo = {\n id: string;\n name: string;\n size: number;\n type: string;\n url: string;\n};\n\nconst DEFAULT_POSITION = \"center\";\nconst DEFAULT_SCALING = {\n backgroundSize: \"cover\",\n backgroundRepeat: \"no-repeat\"\n};\n\nexport const parseValue = (value: string) => {\n if (!value) {\n return undefined;\n }\n\n return;\n};\n\nexport const BackgroundImage = observer(({ elementId }: { elementId: string }) => {\n const { isBaseBreakpoint } = useBreakpoint();\n const { styles, metadata, onChange, inheritanceMap } = useStyles(elementId);\n const [localValue, setLocalValue] = useState<string | null>(styles.backgroundImage);\n const url = useMemo(() => {\n const parser = new BackgroundImageParser(styles.backgroundImage);\n const rules = parser.getRules();\n const urlRule = rules.find(r => r.type === \"url\");\n if (urlRule && urlRule.type === \"url\") {\n return urlRule.parsed.url;\n }\n return null;\n }, [styles.backgroundImage]);\n\n useEffect(() => {\n if (styles.backgroundImage !== localValue) {\n setLocalValue(styles.backgroundImage);\n }\n }, [styles.backgroundImage]);\n\n const onFileChange = (file: FileManagerFileItem) => {\n onChange(({ styles, metadata }) => {\n styles.set(\"backgroundPosition\", DEFAULT_POSITION);\n styles.set(\"backgroundSize\", DEFAULT_SCALING.backgroundSize);\n styles.set(\"backgroundRepeat\", DEFAULT_SCALING.backgroundRepeat);\n styles.set(\"backgroundImage\", `url(\"${file.src}\")`);\n\n metadata.set(\"backgroundImage\", {\n id: file.id,\n name: file.name,\n size: file.size,\n type: file.type,\n url: file.src || \"\"\n });\n });\n };\n\n const onRemove = () => {\n onChange(({ styles, metadata }) => {\n // On base breakpoint, we unset the image and all styles related to it.\n if (isBaseBreakpoint) {\n styles.unset(\"backgroundImage\");\n styles.unset(\"backgroundPosition\");\n styles.unset(\"backgroundSize\");\n styles.unset(\"backgroundRepeat\");\n } else {\n styles.set(\"backgroundImage\", \"none\");\n }\n\n metadata.unset(\"backgroundImage\");\n });\n };\n\n const onReset = () => {\n onChange(({ styles }) => {\n styles.unset(\"backgroundImage\");\n\n metadata.unset(\"backgroundImage\");\n });\n };\n\n const inheritance = inheritanceMap?.backgroundImage ?? {};\n\n const fileInfo = metadata.get<FileInfo>(\"backgroundImage\");\n\n return (\n <SidebarRow\n label={\n <InheritanceLabel\n onReset={onReset}\n isOverridden={inheritance?.overridden ?? false}\n inheritedFrom={inheritance?.inheritedFrom}\n text={\"Image\"}\n />\n }\n >\n <FileManager\n images={true}\n onChange={onFileChange}\n render={({ showFileManager }) => (\n <FilePicker\n variant={\"secondary\"}\n type=\"compact\"\n value={url ? fileInfo : undefined}\n onSelectItem={() => showFileManager()}\n onRemoveItem={onRemove}\n />\n )}\n />\n </SidebarRow>\n );\n});\n"],"names":["DEFAULT_POSITION","DEFAULT_SCALING","parseValue","value","BackgroundImage","observer","elementId","isBaseBreakpoint","useBreakpoint","styles","metadata","onChange","inheritanceMap","useStyles","localValue","setLocalValue","useState","url","useMemo","parser","BackgroundImageParser","rules","urlRule","r","useEffect","onFileChange","file","onRemove","onReset","inheritance","fileInfo","SidebarRow","InheritanceLabel","FileManager","showFileManager","FilePicker","undefined"],"mappings":";;;;;;;;;AAkBA,MAAMA,mBAAmB;AACzB,MAAMC,kBAAkB;IACpB,gBAAgB;IAChB,kBAAkB;AACtB;AAEO,MAAMC,aAAa,CAACC,SAM3B;AAEO,MAAMC,kBAAkBC,SAAS,CAAC,EAAEC,SAAS,EAAyB;IACzE,MAAM,EAAEC,gBAAgB,EAAE,GAAGC;IAC7B,MAAM,EAAEC,MAAM,EAAEC,QAAQ,EAAEC,QAAQ,EAAEC,cAAc,EAAE,GAAGC,UAAUP;IACjE,MAAM,CAACQ,YAAYC,cAAc,GAAGC,SAAwBP,OAAO,eAAe;IAClF,MAAMQ,MAAMC,QAAQ;QAChB,MAAMC,SAAS,IAAIC,sBAAsBX,OAAO,eAAe;QAC/D,MAAMY,QAAQF,OAAO,QAAQ;QAC7B,MAAMG,UAAUD,MAAM,IAAI,CAACE,CAAAA,IAAKA,AAAW,UAAXA,EAAE,IAAI;QACtC,IAAID,WAAWA,AAAiB,UAAjBA,QAAQ,IAAI,EACvB,OAAOA,QAAQ,MAAM,CAAC,GAAG;QAE7B,OAAO;IACX,GAAG;QAACb,OAAO,eAAe;KAAC;IAE3Be,UAAU;QACN,IAAIf,OAAO,eAAe,KAAKK,YAC3BC,cAAcN,OAAO,eAAe;IAE5C,GAAG;QAACA,OAAO,eAAe;KAAC;IAE3B,MAAMgB,eAAe,CAACC;QAClBf,SAAS,CAAC,EAAEF,MAAM,EAAEC,QAAQ,EAAE;YAC1BD,OAAO,GAAG,CAAC,sBAAsBT;YACjCS,OAAO,GAAG,CAAC,kBAAkBR,gBAAgB,cAAc;YAC3DQ,OAAO,GAAG,CAAC,oBAAoBR,gBAAgB,gBAAgB;YAC/DQ,OAAO,GAAG,CAAC,mBAAmB,CAAC,KAAK,EAAEiB,KAAK,GAAG,CAAC,EAAE,CAAC;YAElDhB,SAAS,GAAG,CAAC,mBAAmB;gBAC5B,IAAIgB,KAAK,EAAE;gBACX,MAAMA,KAAK,IAAI;gBACf,MAAMA,KAAK,IAAI;gBACf,MAAMA,KAAK,IAAI;gBACf,KAAKA,KAAK,GAAG,IAAI;YACrB;QACJ;IACJ;IAEA,MAAMC,WAAW;QACbhB,SAAS,CAAC,EAAEF,MAAM,EAAEC,QAAQ,EAAE;YAE1B,IAAIH,kBAAkB;gBAClBE,OAAO,KAAK,CAAC;gBACbA,OAAO,KAAK,CAAC;gBACbA,OAAO,KAAK,CAAC;gBACbA,OAAO,KAAK,CAAC;YACjB,OACIA,OAAO,GAAG,CAAC,mBAAmB;YAGlCC,SAAS,KAAK,CAAC;QACnB;IACJ;IAEA,MAAMkB,UAAU;QACZjB,SAAS,CAAC,EAAEF,MAAM,EAAE;YAChBA,OAAO,KAAK,CAAC;YAEbC,SAAS,KAAK,CAAC;QACnB;IACJ;IAEA,MAAMmB,cAAcjB,gBAAgB,mBAAmB,CAAC;IAExD,MAAMkB,WAAWpB,SAAS,GAAG,CAAW;IAExC,OAAO,WAAP,GACI,oBAACqB,YAAUA;QACP,qBACI,oBAACC,kBAAgBA;YACb,SAASJ;YACT,cAAcC,aAAa,cAAc;YACzC,eAAeA,aAAa;YAC5B,MAAM;;qBAId,oBAACI,aAAWA;QACR,QAAQ;QACR,UAAUR;QACV,QAAQ,CAAC,EAAES,eAAe,EAAE,iBACxB,oBAACC,YAAUA;gBACP,SAAS;gBACT,MAAK;gBACL,OAAOlB,MAAMa,WAAWM;gBACxB,cAAc,IAAMF;gBACpB,cAAcP;;;AAMtC"}
@@ -2,9 +2,9 @@ import react from "react";
2
2
  import { Icon, Tooltip } from "@webiny/admin-ui";
3
3
  import { ReactComponent } from "@webiny/icons/info.svg";
4
4
  const SidebarRow = ({ label, tooltip, children })=>/*#__PURE__*/ react.createElement("div", {
5
- className: "flex items-center gap-xxs"
5
+ className: "flex items-start gap-xxs"
6
6
  }, /*#__PURE__*/ react.createElement("div", {
7
- className: "w-[80px] flex flex-row items-center gap-xxs shrink-0 text-sm text-neutral-strong"
7
+ className: "w-[80px] pt-sm flex flex-row items-center gap-xxs shrink-0 text-sm text-neutral-strong"
8
8
  }, label, tooltip ? /*#__PURE__*/ react.createElement(Tooltip, {
9
9
  trigger: /*#__PURE__*/ react.createElement(Icon, {
10
10
  icon: /*#__PURE__*/ react.createElement(ReactComponent, null),
@@ -1 +1 @@
1
- {"version":3,"file":"BaseEditor/defaultConfig/Sidebar/StyleSettings/SidebarRow.js","sources":["../../../../../src/BaseEditor/defaultConfig/Sidebar/StyleSettings/SidebarRow.tsx"],"sourcesContent":["import React from \"react\";\nimport { Icon, Tooltip } from \"@webiny/admin-ui\";\nimport { ReactComponent as InfoIcon } from \"@webiny/icons/info.svg\";\n\ninterface SidebarRowProps {\n label: React.ReactNode;\n tooltip?: React.ReactNode;\n children: React.ReactNode;\n}\n\nexport const SidebarRow = ({ label, tooltip, children }: SidebarRowProps) => {\n return (\n <div className={\"flex items-center gap-xxs\"}>\n <div\n className={\n \"w-[80px] flex flex-row items-center gap-xxs shrink-0 text-sm text-neutral-strong\"\n }\n >\n {label}\n\n {tooltip ? (\n <Tooltip\n trigger={\n <Icon\n icon={<InfoIcon />}\n size={\"xs\"}\n label={\"More information\"}\n color={\"neutral-light\"}\n />\n }\n content={tooltip}\n side={\"left\"}\n />\n ) : (\n <div className={\"w-xs shrink-0\"} />\n )}\n </div>\n <div className={\"flex-1\"}>{children}</div>\n </div>\n );\n};\n"],"names":["SidebarRow","label","tooltip","children","Tooltip","Icon","InfoIcon"],"mappings":";;;AAUO,MAAMA,aAAa,CAAC,EAAEC,KAAK,EAAEC,OAAO,EAAEC,QAAQ,EAAmB,GAC7D,WAAP,GACI,oBAAC;QAAI,WAAW;qBACZ,oBAAC;QACG,WACI;OAGHF,OAEAC,UAAU,WAAVA,GACG,oBAACE,SAAOA;QACJ,uBACI,oBAACC,MAAIA;YACD,oBAAM,oBAACC,gBAAQA;YACf,MAAM;YACN,OAAO;YACP,OAAO;;QAGf,SAASJ;QACT,MAAM;uBAGV,oBAAC;QAAI,WAAW;uBAGxB,oBAAC;QAAI,WAAW;OAAWC"}
1
+ {"version":3,"file":"BaseEditor/defaultConfig/Sidebar/StyleSettings/SidebarRow.js","sources":["../../../../../src/BaseEditor/defaultConfig/Sidebar/StyleSettings/SidebarRow.tsx"],"sourcesContent":["import React from \"react\";\nimport { Icon, Tooltip } from \"@webiny/admin-ui\";\nimport { ReactComponent as InfoIcon } from \"@webiny/icons/info.svg\";\n\ninterface SidebarRowProps {\n label: React.ReactNode;\n tooltip?: React.ReactNode;\n children: React.ReactNode;\n}\n\nexport const SidebarRow = ({ label, tooltip, children }: SidebarRowProps) => {\n return (\n <div className={\"flex items-start gap-xxs\"}>\n <div\n className={\n \"w-[80px] pt-sm flex flex-row items-center gap-xxs shrink-0 text-sm text-neutral-strong\"\n }\n >\n {label}\n\n {tooltip ? (\n <Tooltip\n trigger={\n <Icon\n icon={<InfoIcon />}\n size={\"xs\"}\n label={\"More information\"}\n color={\"neutral-light\"}\n />\n }\n content={tooltip}\n side={\"left\"}\n />\n ) : (\n <div className={\"w-xs shrink-0\"} />\n )}\n </div>\n <div className={\"flex-1\"}>{children}</div>\n </div>\n );\n};\n"],"names":["SidebarRow","label","tooltip","children","Tooltip","Icon","InfoIcon"],"mappings":";;;AAUO,MAAMA,aAAa,CAAC,EAAEC,KAAK,EAAEC,OAAO,EAAEC,QAAQ,EAAmB,GAC7D,WAAP,GACI,oBAAC;QAAI,WAAW;qBACZ,oBAAC;QACG,WACI;OAGHF,OAEAC,UAAU,WAAVA,GACG,oBAACE,SAAOA;QACJ,uBACI,oBAACC,MAAIA;YACD,oBAAM,oBAACC,gBAAQA;YACf,MAAM;YACN,OAAO;YACP,OAAO;;QAGf,SAASJ;QACT,MAAM;uBAGV,oBAAC;QAAI,WAAW;uBAGxB,oBAAC;QAAI,WAAW;OAAWC"}
@@ -4,7 +4,7 @@ import { FileManager } from "@webiny/app-admin";
4
4
  import { useBreakpoint } from "../BaseEditor/hooks/useBreakpoint.js";
5
5
  import { getAssetCropParam, normalizeToAsset } from "@webiny/website-builder-sdk";
6
6
  import { fileManagerItemToValue } from "../shared/fileManagerItemToValue.js";
7
- const isEditableImage = (asset)=>!!asset?.src && "string" == typeof asset.type && asset.type.startsWith("image/") && "image/svg+xml" !== asset.type;
7
+ const isEditableImage = (asset)=>!!asset?.src && "string" == typeof asset.mimeType && asset.mimeType.startsWith("image/") && "image/svg+xml" !== asset.mimeType;
8
8
  const hasImageEdit = (image)=>{
9
9
  if (!image?.width || !image?.height) return false;
10
10
  const c = image.crop;
@@ -1 +1 @@
1
- {"version":3,"file":"inputRenderers/FileInput.js","sources":["../../src/inputRenderers/FileInput.tsx"],"sourcesContent":["import React, { useState } from \"react\";\nimport {\n FilePicker,\n ImageEditor,\n RichItemPreview,\n getCroppedImageRenderStyles,\n type ImageEditorValue\n} from \"@webiny/admin-ui\";\nimport type { ElementInputRendererProps } from \"~/BaseEditor/index.js\";\nimport { FileManager, type FileManagerFileItem } from \"@webiny/app-admin\";\nimport { useBreakpoint } from \"~/BaseEditor/hooks/useBreakpoint.js\";\nimport {\n normalizeToAsset,\n getAssetCropParam,\n type Asset,\n type AssetImage\n} from \"@webiny/website-builder-sdk\";\nimport type { FileInput } from \"@webiny/website-builder-sdk\";\nimport { fileManagerItemToValue } from \"~/shared/fileManagerItemToValue.js\";\n\nconst isEditableImage = (asset: Asset | undefined): asset is Asset => {\n return (\n !!asset?.src &&\n typeof asset.type === \"string\" &&\n asset.type.startsWith(\"image/\") &&\n asset.type !== \"image/svg+xml\"\n );\n};\n\n/** True when the image carries a non-trivial crop or focal point worth previewing. */\nconst hasImageEdit = (image: AssetImage | undefined): boolean => {\n if (!image?.width || !image?.height) {\n return false;\n }\n const c = image.crop;\n const fullCrop = !c || (c.top === 0 && c.left === 0 && c.bottom === 0 && c.right === 0);\n const fp = image.focalPoint;\n const centeredFocal = !fp || (fp.x === 0.5 && fp.y === 0.5);\n return !fullCrop || !centeredFocal;\n};\n\n/** Map the stored asset image into the shared `ImageEditor` value (focalPoint → hotspot). */\nconst toEditorValue = (image: AssetImage | undefined): ImageEditorValue | undefined => {\n if (!image) {\n return undefined;\n }\n return {\n crop: image.crop,\n hotspot: image.focalPoint\n ? { x: image.focalPoint.x, y: image.focalPoint.y, width: 1, height: 1 }\n : undefined,\n alt: image.alt,\n caption: image.caption\n };\n};\n\nexport const FileInputRenderer = ({\n value,\n onChange,\n label,\n ...props\n}: ElementInputRendererProps) => {\n const input = props.input as FileInput;\n const { isBaseBreakpoint } = useBreakpoint();\n const [editorOpen, setEditorOpen] = useState(false);\n\n const asset = normalizeToAsset(value) ?? undefined;\n const editable = isEditableImage(asset);\n\n const onFileChange = (file: FileManagerFileItem) => {\n onChange(({ value }) => {\n value.set(fileManagerItemToValue(file));\n });\n };\n\n const onRemove = () => {\n onChange(({ value }) => {\n if (isBaseBreakpoint) {\n value.set(undefined);\n } else {\n value.set(null);\n }\n });\n };\n\n // Save the per-usage crop / focal point / alt override onto the element value,\n // writing the unified asset shape (hotspot → focalPoint).\n const onSaveEdit = (edit: ImageEditorValue) => {\n onChange(({ value }) => {\n if (!asset) {\n return;\n }\n const image: AssetImage = {\n width: asset.image?.width,\n height: asset.image?.height,\n crop: edit.crop,\n focalPoint: edit.hotspot ? { x: edit.hotspot.x, y: edit.hotspot.y } : undefined,\n alt: edit.alt,\n caption: edit.caption\n };\n const updated = { ...asset, image };\n const cropParam = getAssetCropParam(updated);\n if (cropParam) {\n const sep = asset.src.includes(\"?\") ? \"&\" : \"?\";\n updated.url = `${asset.src}${sep}crop=${cropParam}`;\n } else {\n updated.url = asset.src;\n }\n value.set(updated);\n });\n };\n\n return (\n <FileManager\n accept={input.allowedFileTypes}\n onChange={onFileChange}\n render={({ showFileManager }) => (\n <>\n <FilePicker\n variant={\"secondary\"}\n label={label}\n description={input.description}\n type=\"compact\"\n value={asset?.src}\n // Reflect the per-usage crop + focal point in the thumbnail.\n renderFilePreview={\n editable && asset?.src && hasImageEdit(asset.image)\n ? previewProps => (\n <RichItemPreview\n {...previewProps}\n renderImage={({ name }) => {\n const { wrapper, image } =\n getCroppedImageRenderStyles(\n asset.image?.width ?? 0,\n asset.image?.height ?? 0,\n asset.image?.crop,\n asset.image?.focalPoint\n ? {\n x: asset.image.focalPoint.x,\n y: asset.image.focalPoint.y,\n width: 1,\n height: 1\n }\n : undefined,\n { boxWidth: 1, boxHeight: 1, fit: \"cover\" }\n );\n return (\n <div style={wrapper}>\n <img\n src={asset.src as string}\n alt={name}\n draggable={false}\n style={image}\n />\n </div>\n );\n }}\n />\n )\n : undefined\n }\n onSelectItem={() => showFileManager()}\n onRemoveItem={onRemove}\n // The \"Edit\" (pencil) action edits the image (crop / focal\n // point / alt). Replacing the file is done by clicking the\n // preview. For non-images there is nothing to edit, so the\n // pencil is hidden.\n onEditItem={editable ? () => setEditorOpen(true) : undefined}\n />\n {editable ? (\n <ImageEditor\n open={editorOpen}\n onClose={() => setEditorOpen(false)}\n image={{\n src: asset.src,\n width: asset.image?.width ?? 0,\n height: asset.image?.height ?? 0\n }}\n value={toEditorValue(asset.image)}\n onSave={onSaveEdit}\n />\n ) : null}\n </>\n )}\n />\n );\n};\n"],"names":["isEditableImage","asset","hasImageEdit","image","c","fullCrop","fp","centeredFocal","toEditorValue","undefined","FileInputRenderer","value","onChange","label","props","input","isBaseBreakpoint","useBreakpoint","editorOpen","setEditorOpen","useState","normalizeToAsset","editable","onFileChange","file","fileManagerItemToValue","onRemove","onSaveEdit","edit","updated","cropParam","getAssetCropParam","sep","FileManager","showFileManager","FilePicker","previewProps","RichItemPreview","name","wrapper","getCroppedImageRenderStyles","ImageEditor"],"mappings":"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"}
1
+ {"version":3,"file":"inputRenderers/FileInput.js","sources":["../../src/inputRenderers/FileInput.tsx"],"sourcesContent":["import React, { useState } from \"react\";\nimport {\n FilePicker,\n ImageEditor,\n RichItemPreview,\n getCroppedImageRenderStyles,\n type ImageEditorValue\n} from \"@webiny/admin-ui\";\nimport type { ElementInputRendererProps } from \"~/BaseEditor/index.js\";\nimport { FileManager, type FileManagerFileItem } from \"@webiny/app-admin\";\nimport { useBreakpoint } from \"~/BaseEditor/hooks/useBreakpoint.js\";\nimport {\n normalizeToAsset,\n getAssetCropParam,\n type Asset,\n type AssetImage\n} from \"@webiny/website-builder-sdk\";\nimport type { FileInput } from \"@webiny/website-builder-sdk\";\nimport { fileManagerItemToValue } from \"~/shared/fileManagerItemToValue.js\";\n\nconst isEditableImage = (asset: Asset | undefined): asset is Asset => {\n return (\n !!asset?.src &&\n typeof asset.mimeType === \"string\" &&\n asset.mimeType.startsWith(\"image/\") &&\n asset.mimeType !== \"image/svg+xml\"\n );\n};\n\n/** True when the image carries a non-trivial crop or focal point worth previewing. */\nconst hasImageEdit = (image: AssetImage | undefined): boolean => {\n if (!image?.width || !image?.height) {\n return false;\n }\n const c = image.crop;\n const fullCrop = !c || (c.top === 0 && c.left === 0 && c.bottom === 0 && c.right === 0);\n const fp = image.focalPoint;\n const centeredFocal = !fp || (fp.x === 0.5 && fp.y === 0.5);\n return !fullCrop || !centeredFocal;\n};\n\n/** Map the stored asset image into the shared `ImageEditor` value (focalPoint → hotspot). */\nconst toEditorValue = (image: AssetImage | undefined): ImageEditorValue | undefined => {\n if (!image) {\n return undefined;\n }\n return {\n crop: image.crop,\n hotspot: image.focalPoint\n ? { x: image.focalPoint.x, y: image.focalPoint.y, width: 1, height: 1 }\n : undefined,\n alt: image.alt,\n caption: image.caption\n };\n};\n\nexport const FileInputRenderer = ({\n value,\n onChange,\n label,\n ...props\n}: ElementInputRendererProps) => {\n const input = props.input as FileInput;\n const { isBaseBreakpoint } = useBreakpoint();\n const [editorOpen, setEditorOpen] = useState(false);\n\n const asset = normalizeToAsset(value) ?? undefined;\n const editable = isEditableImage(asset);\n\n const onFileChange = (file: FileManagerFileItem) => {\n onChange(({ value }) => {\n value.set(fileManagerItemToValue(file));\n });\n };\n\n const onRemove = () => {\n onChange(({ value }) => {\n if (isBaseBreakpoint) {\n value.set(undefined);\n } else {\n value.set(null);\n }\n });\n };\n\n // Save the per-usage crop / focal point / alt override onto the element value,\n // writing the unified asset shape (hotspot → focalPoint).\n const onSaveEdit = (edit: ImageEditorValue) => {\n onChange(({ value }) => {\n if (!asset) {\n return;\n }\n const image: AssetImage = {\n width: asset.image?.width,\n height: asset.image?.height,\n crop: edit.crop,\n focalPoint: edit.hotspot ? { x: edit.hotspot.x, y: edit.hotspot.y } : undefined,\n alt: edit.alt,\n caption: edit.caption\n };\n const updated = { ...asset, image };\n const cropParam = getAssetCropParam(updated);\n if (cropParam) {\n const sep = asset.src.includes(\"?\") ? \"&\" : \"?\";\n updated.url = `${asset.src}${sep}crop=${cropParam}`;\n } else {\n updated.url = asset.src;\n }\n value.set(updated);\n });\n };\n\n return (\n <FileManager\n accept={input.allowedFileTypes}\n onChange={onFileChange}\n render={({ showFileManager }) => (\n <>\n <FilePicker\n variant={\"secondary\"}\n label={label}\n description={input.description}\n type=\"compact\"\n value={asset?.src}\n // Reflect the per-usage crop + focal point in the thumbnail.\n renderFilePreview={\n editable && asset?.src && hasImageEdit(asset.image)\n ? previewProps => (\n <RichItemPreview\n {...previewProps}\n renderImage={({ name }) => {\n const { wrapper, image } =\n getCroppedImageRenderStyles(\n asset.image?.width ?? 0,\n asset.image?.height ?? 0,\n asset.image?.crop,\n asset.image?.focalPoint\n ? {\n x: asset.image.focalPoint.x,\n y: asset.image.focalPoint.y,\n width: 1,\n height: 1\n }\n : undefined,\n { boxWidth: 1, boxHeight: 1, fit: \"cover\" }\n );\n return (\n <div style={wrapper}>\n <img\n src={asset.src as string}\n alt={name}\n draggable={false}\n style={image}\n />\n </div>\n );\n }}\n />\n )\n : undefined\n }\n onSelectItem={() => showFileManager()}\n onRemoveItem={onRemove}\n // The \"Edit\" (pencil) action edits the image (crop / focal\n // point / alt). Replacing the file is done by clicking the\n // preview. For non-images there is nothing to edit, so the\n // pencil is hidden.\n onEditItem={editable ? () => setEditorOpen(true) : undefined}\n />\n {editable ? (\n <ImageEditor\n open={editorOpen}\n onClose={() => setEditorOpen(false)}\n image={{\n src: asset.src,\n width: asset.image?.width ?? 0,\n height: asset.image?.height ?? 0\n }}\n value={toEditorValue(asset.image)}\n onSave={onSaveEdit}\n />\n ) : null}\n </>\n )}\n />\n );\n};\n"],"names":["isEditableImage","asset","hasImageEdit","image","c","fullCrop","fp","centeredFocal","toEditorValue","undefined","FileInputRenderer","value","onChange","label","props","input","isBaseBreakpoint","useBreakpoint","editorOpen","setEditorOpen","useState","normalizeToAsset","editable","onFileChange","file","fileManagerItemToValue","onRemove","onSaveEdit","edit","updated","cropParam","getAssetCropParam","sep","FileManager","showFileManager","FilePicker","previewProps","RichItemPreview","name","wrapper","getCroppedImageRenderStyles","ImageEditor"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webiny/app-website-builder",
3
- "version": "6.6.0-alpha.8",
3
+ "version": "6.6.0-alpha.9",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./index.js",
@@ -19,26 +19,26 @@
19
19
  "@lexical/utils": "0.49.0",
20
20
  "@monaco-editor/react": "4.7.0",
21
21
  "@types/react": "18.3.31",
22
- "@webiny/admin-ui": "6.6.0-alpha.8",
23
- "@webiny/app": "6.6.0-alpha.8",
24
- "@webiny/app-aco": "6.6.0-alpha.8",
25
- "@webiny/app-admin": "6.6.0-alpha.8",
26
- "@webiny/app-headless-cms-common": "6.6.0-alpha.8",
27
- "@webiny/app-utils": "6.6.0-alpha.8",
22
+ "@webiny/admin-ui": "6.6.0-alpha.9",
23
+ "@webiny/app": "6.6.0-alpha.9",
24
+ "@webiny/app-aco": "6.6.0-alpha.9",
25
+ "@webiny/app-admin": "6.6.0-alpha.9",
26
+ "@webiny/app-headless-cms-common": "6.6.0-alpha.9",
27
+ "@webiny/app-utils": "6.6.0-alpha.9",
28
28
  "@webiny/di": "1.1.0",
29
- "@webiny/feature": "6.6.0-alpha.8",
30
- "@webiny/form": "6.6.0-alpha.8",
31
- "@webiny/icons": "6.6.0-alpha.8",
32
- "@webiny/languages": "6.6.0-alpha.8",
33
- "@webiny/lexical-converter": "6.6.0-alpha.8",
34
- "@webiny/lexical-editor": "6.6.0-alpha.8",
35
- "@webiny/lexical-nodes": "6.6.0-alpha.8",
36
- "@webiny/lexical-theme": "6.6.0-alpha.8",
37
- "@webiny/react-composition": "6.6.0-alpha.8",
38
- "@webiny/react-properties": "6.6.0-alpha.8",
39
- "@webiny/utils": "6.6.0-alpha.8",
40
- "@webiny/validation": "6.6.0-alpha.8",
41
- "@webiny/website-builder-sdk": "6.6.0-alpha.8",
29
+ "@webiny/feature": "6.6.0-alpha.9",
30
+ "@webiny/form": "6.6.0-alpha.9",
31
+ "@webiny/icons": "6.6.0-alpha.9",
32
+ "@webiny/languages": "6.6.0-alpha.9",
33
+ "@webiny/lexical-converter": "6.6.0-alpha.9",
34
+ "@webiny/lexical-editor": "6.6.0-alpha.9",
35
+ "@webiny/lexical-nodes": "6.6.0-alpha.9",
36
+ "@webiny/lexical-theme": "6.6.0-alpha.9",
37
+ "@webiny/react-composition": "6.6.0-alpha.9",
38
+ "@webiny/react-properties": "6.6.0-alpha.9",
39
+ "@webiny/utils": "6.6.0-alpha.9",
40
+ "@webiny/validation": "6.6.0-alpha.9",
41
+ "@webiny/website-builder-sdk": "6.6.0-alpha.9",
42
42
  "classnames": "2.5.1",
43
43
  "deep-equal": "2.2.3",
44
44
  "graphql": "16.14.2",
@@ -60,7 +60,7 @@
60
60
  "devDependencies": {
61
61
  "@types/deep-equal": "1.0.4",
62
62
  "@types/is-hotkey": "0.1.10",
63
- "@webiny/build-tools": "6.6.0-alpha.8",
63
+ "@webiny/build-tools": "6.6.0-alpha.9",
64
64
  "execa": "10.0.1",
65
65
  "rimraf": "6.1.3",
66
66
  "typescript": "7.0.2",
@@ -1,6 +1,7 @@
1
1
  import { describe, expect, it } from "vitest";
2
2
  import { Container } from "@webiny/di";
3
3
  import { FormModelFeature } from "@webiny/app-admin/features/formModel/feature.js";
4
+ import { IdentityContextFeature } from "@webiny/app-admin/features/security/IdentityContext/feature.js";
4
5
  import { FormModelFactory } from "@webiny/app-admin/features/formModel/abstractions.js";
5
6
  import { AddLanguageModifier } from "./AddLanguageModifier.js";
6
7
  import { PagePath } from "../../../shared/PagePath.js";
@@ -19,6 +20,7 @@ function createLanguageMocks(languages) {
19
20
  }
20
21
  function createBaseForm(config) {
21
22
  const container = new Container();
23
+ IdentityContextFeature.register(container);
22
24
  FormModelFeature.register(container);
23
25
  const factory = container.resolve(FormModelFactory);
24
26
  return factory.create({
@@ -1 +1 @@
1
- {"version":3,"file":"presentation/pages/CreatePage/CreatePage.test.js","sources":["../../../../src/presentation/pages/CreatePage/CreatePage.test.ts"],"sourcesContent":["import { describe, it, expect } from \"vitest\";\nimport { Container } from \"@webiny/di\";\nimport { FormModelFeature } from \"@webiny/app-admin/features/formModel/feature.js\";\nimport { FormModelFactory } from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport type { IFormModel, IFormModelConfig, IRowNodeVM } from \"@webiny/app-admin\";\nimport type { LanguageDto } from \"@webiny/languages/admin/features/listLanguages/abstractions.js\";\nimport { AddLanguageModifier } from \"./AddLanguageModifier.js\";\nimport { PagePath } from \"~/shared/PagePath.js\";\nimport type { IPageType, ICreatePageFormModifier } from \"./abstractions.js\";\n\nfunction createLanguageMocks(languages: LanguageDto[]) {\n const repository = {\n execute: async () => languages,\n getLanguages: () => languages\n };\n const useCase = {\n execute: async () => languages\n };\n return { useCase, repository };\n}\n\nfunction createBaseForm(config?: Partial<IFormModelConfig>) {\n const container = new Container();\n FormModelFeature.register(container);\n const factory = container.resolve(FormModelFactory);\n\n return factory.create({\n fields: fields => ({\n title: fields\n .text()\n .label(\"Title\")\n .required(\"Title is required\")\n .onBlur((value, { form }) => {\n const currentPath = form.field(\"path\").getValue();\n if (currentPath) {\n return;\n }\n form.field(\"path\").setValue(PagePath.fromTitle(String(value)).toString());\n }),\n path: fields\n .text()\n .label(\"Path\")\n .required(\"Path is required\")\n .beforeChange(value => {\n return PagePath.create(String(value)).slugify().toString();\n }),\n pageType: fields.text().hidden().defaultValue(\"staticPage\")\n }),\n layout: layout => [layout.row(\"title\"), layout.row(\"path\")],\n ...config\n });\n}\n\n/**\n * Helper: set title and blur to trigger path generation.\n */\nfunction setTitleAndBlur(form: IFormModel, value: string) {\n form.field(\"title\").setValue(value);\n form.field(\"title\").blur();\n}\n\ndescribe(\"CreatePage base form\", () => {\n it(\"should create a form with title, path, and hidden pageType\", () => {\n const form = createBaseForm();\n expect(form.field(\"title\")).toBeDefined();\n expect(form.field(\"path\")).toBeDefined();\n expect(form.field(\"pageType\")).toBeDefined();\n });\n\n it(\"should include pageType in getData but not in layout\", () => {\n const form = createBaseForm();\n const data = form.getData();\n expect(data.pageType).toBe(\"staticPage\");\n\n const fieldNames = form.vm.layout\n .filter((n): n is IRowNodeVM => n.type === \"row\")\n .flatMap(row => row.fields.map(f => f.name));\n expect(fieldNames).not.toContain(\"pageType\");\n });\n\n it(\"should auto-generate path from title on blur\", () => {\n const form = createBaseForm();\n setTitleAndBlur(form, \"Hello World\");\n expect(form.field(\"path\").getValue()).toBe(\"/hello-world\");\n });\n\n it(\"should not auto-generate path on setValue alone (before blur)\", () => {\n const form = createBaseForm();\n form.field(\"title\").setValue(\"Hello World\");\n expect(form.field(\"path\").getValue()).toBeNull();\n });\n\n it(\"should not overwrite path when manually edited\", () => {\n const form = createBaseForm();\n setTitleAndBlur(form, \"Hello World\");\n form.field(\"path\").setValue(\"/custom-path\");\n setTitleAndBlur(form, \"New Title\");\n expect(form.field(\"path\").getValue()).toBe(\"/custom-path\");\n });\n\n it(\"should return data on valid submit\", async () => {\n const form = createBaseForm();\n form.field(\"title\").setValue(\"My Page\");\n form.field(\"path\").setValue(\"/my-page\");\n\n const result = await form.submit();\n expect(result).toEqual({\n title: \"My Page\",\n path: \"/my-page\",\n pageType: \"staticPage\"\n });\n });\n\n it(\"should return false on invalid submit\", async () => {\n const form = createBaseForm();\n const result = await form.submit();\n expect(result).toBe(false);\n expect(form.errors.length).toBeGreaterThan(0);\n });\n});\n\ndescribe(\"PageType + Modifier 3-layer architecture\", () => {\n /**\n * Simulates the 3-layer build order used by CreatePagePresenter:\n * 1. Base form (title, path, pageType)\n * 2. Page type modify\n * 3. Cross-cutting modifiers\n */\n function buildForm(pageType: IPageType, modifiers: ICreatePageFormModifier[] = []): IFormModel {\n const form = createBaseForm();\n pageType.modifyForm?.(form);\n for (const modifier of modifiers) {\n modifier.modifyForm(form);\n }\n return form;\n }\n\n const staticPageType: IPageType = {\n name: \"static\",\n label: \"Static Page\",\n modifyForm() {\n // no-op\n }\n };\n\n const productPageType: IPageType = {\n name: \"product\",\n label: \"Product Page\",\n modifyForm(form) {\n form.fields(fields => ({\n product: fields\n .text()\n .label(\"Product\")\n .required(\"Product is required\")\n .options([\n { label: \"Shoes\", value: \"shoes\" },\n { label: \"Hats\", value: \"hats\" }\n ])\n }));\n form.field(\"title\").setDisabled(true);\n form.field(\"path\").setDisabled(true);\n form.layout(layout => [layout.row(\"product\").before(\"title\")]);\n }\n };\n\n it(\"should leave base form unchanged for static page type\", () => {\n const form = buildForm(staticPageType);\n const fieldNames = form.vm.layout\n .filter((n): n is IRowNodeVM => n.type === \"row\")\n .flatMap(row => row.fields.map(f => f.name));\n expect(fieldNames).toEqual([\"title\", \"path\"]);\n });\n\n it(\"should add product field and disable title/path for product page type\", () => {\n const form = buildForm(productPageType);\n const fieldNames = form.vm.layout\n .filter((n): n is IRowNodeVM => n.type === \"row\")\n .flatMap(row => row.fields.map(f => f.name));\n expect(fieldNames).toEqual([\"product\", \"title\", \"path\"]);\n\n expect(form.field(\"title\").vm.disabled).toBe(true);\n expect(form.field(\"path\").vm.disabled).toBe(true);\n });\n\n it(\"should include product in getData\", () => {\n const form = buildForm(productPageType);\n form.field(\"product\").setValue(\"shoes\");\n const data = form.getData();\n expect(data.product).toBe(\"shoes\");\n });\n\n it(\"should apply cross-cutting modifier after page type\", () => {\n const langs: LanguageDto[] = [\n { id: \"en\", code: \"en\", name: \"English\", isDefault: true },\n { id: \"de\", code: \"de\", name: \"German\" }\n ];\n const { useCase, repository } = createLanguageMocks(langs);\n const languageModifier = new AddLanguageModifier(useCase, repository);\n\n const form = buildForm(productPageType, [languageModifier]);\n const fieldNames = form.vm.layout\n .filter((n): n is IRowNodeVM => n.type === \"row\")\n .flatMap(row => row.fields.map(f => f.name));\n\n // language before title (from modifier), product before title (from page type)\n expect(fieldNames).toEqual([\"product\", \"language\", \"title\", \"path\"]);\n });\n\n it(\"should apply cross-cutting modifier to static page type too\", () => {\n const langs: LanguageDto[] = [\n { id: \"en\", code: \"en\", name: \"English\", isDefault: true },\n { id: \"de\", code: \"de\", name: \"German\" }\n ];\n const { useCase, repository } = createLanguageMocks(langs);\n const languageModifier = new AddLanguageModifier(useCase, repository);\n\n const form = buildForm(staticPageType, [languageModifier]);\n const fieldNames = form.vm.layout\n .filter((n): n is IRowNodeVM => n.type === \"row\")\n .flatMap(row => row.fields.map(f => f.name));\n\n expect(fieldNames).toEqual([\"language\", \"title\", \"path\"]);\n });\n});\n\ndescribe(\"Form rebuild on page type switch\", () => {\n const staticPageType: IPageType = {\n name: \"static\",\n label: \"Static Page\",\n modifyForm() {\n // no-op\n }\n };\n\n const productPageType: IPageType = {\n name: \"product\",\n label: \"Product Page\",\n modifyForm(form) {\n form.fields(fields => ({\n product: fields\n .text()\n .label(\"Product\")\n .required(\"Product is required\")\n .options([\n { label: \"Shoes\", value: \"shoes\" },\n { label: \"Hats\", value: \"hats\" }\n ])\n }));\n form.field(\"title\").setDisabled(true);\n form.field(\"path\").setDisabled(true);\n form.layout(layout => [layout.row(\"product\").before(\"title\")]);\n }\n };\n\n const pageTypes: Record<string, IPageType> = {\n static: staticPageType,\n product: productPageType\n };\n\n /**\n * Simulates the presenter's changePageType: getData → rebuild → setData.\n * The real presenter sets `this.selectedPageType` before `buildForm()`,\n * which sets the hidden field's defaultValue. Here we just rebuild and restore.\n */\n function changePageType(\n currentForm: IFormModel,\n newType: string,\n modifiers: ICreatePageFormModifier[] = []\n ): IFormModel {\n const previousData = currentForm.getData();\n const form = createBaseForm();\n pageTypes[newType].modifyForm?.(form);\n for (const modifier of modifiers) {\n modifier.modifyForm(form);\n }\n form.setData(previousData);\n return form;\n }\n\n it(\"should preserve common field values when switching page types\", () => {\n // Start with static page, fill in title and path.\n const staticForm = createBaseForm();\n staticPageType.modifyForm?.(staticForm);\n staticForm.field(\"title\").setValue(\"My Page\");\n staticForm.field(\"path\").setValue(\"/my-page\");\n\n // Switch to product page.\n const productForm = changePageType(staticForm, \"product\");\n\n expect(productForm.field(\"title\").getValue()).toBe(\"My Page\");\n expect(productForm.field(\"path\").getValue()).toBe(\"/my-page\");\n });\n\n it(\"should drop page-type-specific fields on switch\", () => {\n // Start with product page, select a product.\n const productForm = createBaseForm();\n productPageType.modifyForm?.(productForm);\n productForm.field(\"product\").setValue(\"shoes\");\n\n // Switch to static page — product field should not exist.\n const staticForm = changePageType(productForm, \"static\");\n\n const fieldNames = staticForm.vm.layout\n .filter((n): n is IRowNodeVM => n.type === \"row\")\n .flatMap(row => row.fields.map(f => f.name));\n expect(fieldNames).toEqual([\"title\", \"path\"]);\n expect(staticForm.getData()).not.toHaveProperty(\"product\");\n });\n\n it(\"should preserve cross-cutting modifier values across page type switch\", () => {\n const langs: LanguageDto[] = [\n { id: \"en\", code: \"en\", name: \"English\", isDefault: true },\n { id: \"de\", code: \"de\", name: \"German\" }\n ];\n const { useCase, repository } = createLanguageMocks(langs);\n const languageModifier = new AddLanguageModifier(useCase, repository);\n\n // Start with static page + language modifier.\n const staticForm = createBaseForm();\n staticPageType.modifyForm?.(staticForm);\n languageModifier.modifyForm(staticForm);\n staticForm.field(\"title\").setValue(\"Demo\");\n // Language is auto-assigned \"en\" by the modifier reaction.\n\n const langValue = staticForm.field(\"language\").getValue();\n expect(langValue).toBe(\"en\");\n\n // Switch to product page with same modifier.\n const productForm = changePageType(staticForm, \"product\", [languageModifier]);\n\n expect(productForm.field(\"language\").getValue()).toBe(\"en\");\n expect(productForm.field(\"title\").getValue()).toBe(\"Demo\");\n });\n\n it(\"should preserve hidden field values across rebuild\", () => {\n const staticForm = createBaseForm();\n staticPageType.modifyForm?.(staticForm);\n expect(staticForm.getData().pageType).toBe(\"staticPage\");\n\n // Switch to product — setData restores pageType from previous form.\n const productForm = changePageType(staticForm, \"product\");\n\n // The hidden pageType field is preserved via setData.\n // In the real presenter, buildForm() sets defaultValue to the new type,\n // so the hidden field gets the correct value regardless.\n expect(productForm.field(\"pageType\").getValue()).toBe(\"staticPage\");\n });\n});\n"],"names":["createLanguageMocks","languages","repository","useCase","createBaseForm","config","container","Container","FormModelFeature","factory","FormModelFactory","fields","value","form","currentPath","PagePath","String","layout","setTitleAndBlur","describe","it","expect","data","fieldNames","n","row","f","result","buildForm","pageType","modifiers","modifier","staticPageType","productPageType","langs","languageModifier","AddLanguageModifier","pageTypes","changePageType","currentForm","newType","previousData","staticForm","productForm","langValue"],"mappings":";;;;;;AAUA,SAASA,oBAAoBC,SAAwB;IACjD,MAAMC,aAAa;QACf,SAAS,UAAYD;QACrB,cAAc,IAAMA;IACxB;IACA,MAAME,UAAU;QACZ,SAAS,UAAYF;IACzB;IACA,OAAO;QAAEE;QAASD;IAAW;AACjC;AAEA,SAASE,eAAeC,MAAkC;IACtD,MAAMC,YAAY,IAAIC;IACtBC,iBAAiB,QAAQ,CAACF;IAC1B,MAAMG,UAAUH,UAAU,OAAO,CAACI;IAElC,OAAOD,QAAQ,MAAM,CAAC;QAClB,QAAQE,CAAAA,SAAW;gBACf,OAAOA,OACF,IAAI,GACJ,KAAK,CAAC,SACN,QAAQ,CAAC,qBACT,MAAM,CAAC,CAACC,OAAO,EAAEC,IAAI,EAAE;oBACpB,MAAMC,cAAcD,KAAK,KAAK,CAAC,QAAQ,QAAQ;oBAC/C,IAAIC,aACA;oBAEJD,KAAK,KAAK,CAAC,QAAQ,QAAQ,CAACE,SAAS,SAAS,CAACC,OAAOJ,QAAQ,QAAQ;gBAC1E;gBACJ,MAAMD,OACD,IAAI,GACJ,KAAK,CAAC,QACN,QAAQ,CAAC,oBACT,YAAY,CAACC,CAAAA,QACHG,SAAS,MAAM,CAACC,OAAOJ,QAAQ,OAAO,GAAG,QAAQ;gBAEhE,UAAUD,OAAO,IAAI,GAAG,MAAM,GAAG,YAAY,CAAC;YAClD;QACA,QAAQM,CAAAA,SAAU;gBAACA,OAAO,GAAG,CAAC;gBAAUA,OAAO,GAAG,CAAC;aAAQ;QAC3D,GAAGZ,MAAM;IACb;AACJ;AAKA,SAASa,gBAAgBL,IAAgB,EAAED,KAAa;IACpDC,KAAK,KAAK,CAAC,SAAS,QAAQ,CAACD;IAC7BC,KAAK,KAAK,CAAC,SAAS,IAAI;AAC5B;AAEAM,SAAS,wBAAwB;IAC7BC,GAAG,8DAA8D;QAC7D,MAAMP,OAAOT;QACbiB,OAAOR,KAAK,KAAK,CAAC,UAAU,WAAW;QACvCQ,OAAOR,KAAK,KAAK,CAAC,SAAS,WAAW;QACtCQ,OAAOR,KAAK,KAAK,CAAC,aAAa,WAAW;IAC9C;IAEAO,GAAG,wDAAwD;QACvD,MAAMP,OAAOT;QACb,MAAMkB,OAAOT,KAAK,OAAO;QACzBQ,OAAOC,KAAK,QAAQ,EAAE,IAAI,CAAC;QAE3B,MAAMC,aAAaV,KAAK,EAAE,CAAC,MAAM,CAC5B,MAAM,CAAC,CAACW,IAAuBA,AAAW,UAAXA,EAAE,IAAI,EACrC,OAAO,CAACC,CAAAA,MAAOA,IAAI,MAAM,CAAC,GAAG,CAACC,CAAAA,IAAKA,EAAE,IAAI;QAC9CL,OAAOE,YAAY,GAAG,CAAC,SAAS,CAAC;IACrC;IAEAH,GAAG,gDAAgD;QAC/C,MAAMP,OAAOT;QACbc,gBAAgBL,MAAM;QACtBQ,OAAOR,KAAK,KAAK,CAAC,QAAQ,QAAQ,IAAI,IAAI,CAAC;IAC/C;IAEAO,GAAG,iEAAiE;QAChE,MAAMP,OAAOT;QACbS,KAAK,KAAK,CAAC,SAAS,QAAQ,CAAC;QAC7BQ,OAAOR,KAAK,KAAK,CAAC,QAAQ,QAAQ,IAAI,QAAQ;IAClD;IAEAO,GAAG,kDAAkD;QACjD,MAAMP,OAAOT;QACbc,gBAAgBL,MAAM;QACtBA,KAAK,KAAK,CAAC,QAAQ,QAAQ,CAAC;QAC5BK,gBAAgBL,MAAM;QACtBQ,OAAOR,KAAK,KAAK,CAAC,QAAQ,QAAQ,IAAI,IAAI,CAAC;IAC/C;IAEAO,GAAG,sCAAsC;QACrC,MAAMP,OAAOT;QACbS,KAAK,KAAK,CAAC,SAAS,QAAQ,CAAC;QAC7BA,KAAK,KAAK,CAAC,QAAQ,QAAQ,CAAC;QAE5B,MAAMc,SAAS,MAAMd,KAAK,MAAM;QAChCQ,OAAOM,QAAQ,OAAO,CAAC;YACnB,OAAO;YACP,MAAM;YACN,UAAU;QACd;IACJ;IAEAP,GAAG,yCAAyC;QACxC,MAAMP,OAAOT;QACb,MAAMuB,SAAS,MAAMd,KAAK,MAAM;QAChCQ,OAAOM,QAAQ,IAAI,CAAC;QACpBN,OAAOR,KAAK,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC;IAC/C;AACJ;AAEAM,SAAS,4CAA4C;IAOjD,SAASS,UAAUC,QAAmB,EAAEC,YAAuC,EAAE;QAC7E,MAAMjB,OAAOT;QACbyB,SAAS,UAAU,GAAGhB;QACtB,KAAK,MAAMkB,YAAYD,UACnBC,SAAS,UAAU,CAAClB;QAExB,OAAOA;IACX;IAEA,MAAMmB,iBAA4B;QAC9B,MAAM;QACN,OAAO;QACP,eAEA;IACJ;IAEA,MAAMC,kBAA6B;QAC/B,MAAM;QACN,OAAO;QACP,YAAWpB,IAAI;YACXA,KAAK,MAAM,CAACF,CAAAA,SAAW;oBACnB,SAASA,OACJ,IAAI,GACJ,KAAK,CAAC,WACN,QAAQ,CAAC,uBACT,OAAO,CAAC;wBACL;4BAAE,OAAO;4BAAS,OAAO;wBAAQ;wBACjC;4BAAE,OAAO;4BAAQ,OAAO;wBAAO;qBAClC;gBACT;YACAE,KAAK,KAAK,CAAC,SAAS,WAAW,CAAC;YAChCA,KAAK,KAAK,CAAC,QAAQ,WAAW,CAAC;YAC/BA,KAAK,MAAM,CAACI,CAAAA,SAAU;oBAACA,OAAO,GAAG,CAAC,WAAW,MAAM,CAAC;iBAAS;QACjE;IACJ;IAEAG,GAAG,yDAAyD;QACxD,MAAMP,OAAOe,UAAUI;QACvB,MAAMT,aAAaV,KAAK,EAAE,CAAC,MAAM,CAC5B,MAAM,CAAC,CAACW,IAAuBA,AAAW,UAAXA,EAAE,IAAI,EACrC,OAAO,CAACC,CAAAA,MAAOA,IAAI,MAAM,CAAC,GAAG,CAACC,CAAAA,IAAKA,EAAE,IAAI;QAC9CL,OAAOE,YAAY,OAAO,CAAC;YAAC;YAAS;SAAO;IAChD;IAEAH,GAAG,yEAAyE;QACxE,MAAMP,OAAOe,UAAUK;QACvB,MAAMV,aAAaV,KAAK,EAAE,CAAC,MAAM,CAC5B,MAAM,CAAC,CAACW,IAAuBA,AAAW,UAAXA,EAAE,IAAI,EACrC,OAAO,CAACC,CAAAA,MAAOA,IAAI,MAAM,CAAC,GAAG,CAACC,CAAAA,IAAKA,EAAE,IAAI;QAC9CL,OAAOE,YAAY,OAAO,CAAC;YAAC;YAAW;YAAS;SAAO;QAEvDF,OAAOR,KAAK,KAAK,CAAC,SAAS,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC;QAC7CQ,OAAOR,KAAK,KAAK,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC;IAChD;IAEAO,GAAG,qCAAqC;QACpC,MAAMP,OAAOe,UAAUK;QACvBpB,KAAK,KAAK,CAAC,WAAW,QAAQ,CAAC;QAC/B,MAAMS,OAAOT,KAAK,OAAO;QACzBQ,OAAOC,KAAK,OAAO,EAAE,IAAI,CAAC;IAC9B;IAEAF,GAAG,uDAAuD;QACtD,MAAMc,QAAuB;YACzB;gBAAE,IAAI;gBAAM,MAAM;gBAAM,MAAM;gBAAW,WAAW;YAAK;YACzD;gBAAE,IAAI;gBAAM,MAAM;gBAAM,MAAM;YAAS;SAC1C;QACD,MAAM,EAAE/B,OAAO,EAAED,UAAU,EAAE,GAAGF,oBAAoBkC;QACpD,MAAMC,mBAAmB,IAAIC,oBAAoBjC,SAASD;QAE1D,MAAMW,OAAOe,UAAUK,iBAAiB;YAACE;SAAiB;QAC1D,MAAMZ,aAAaV,KAAK,EAAE,CAAC,MAAM,CAC5B,MAAM,CAAC,CAACW,IAAuBA,AAAW,UAAXA,EAAE,IAAI,EACrC,OAAO,CAACC,CAAAA,MAAOA,IAAI,MAAM,CAAC,GAAG,CAACC,CAAAA,IAAKA,EAAE,IAAI;QAG9CL,OAAOE,YAAY,OAAO,CAAC;YAAC;YAAW;YAAY;YAAS;SAAO;IACvE;IAEAH,GAAG,+DAA+D;QAC9D,MAAMc,QAAuB;YACzB;gBAAE,IAAI;gBAAM,MAAM;gBAAM,MAAM;gBAAW,WAAW;YAAK;YACzD;gBAAE,IAAI;gBAAM,MAAM;gBAAM,MAAM;YAAS;SAC1C;QACD,MAAM,EAAE/B,OAAO,EAAED,UAAU,EAAE,GAAGF,oBAAoBkC;QACpD,MAAMC,mBAAmB,IAAIC,oBAAoBjC,SAASD;QAE1D,MAAMW,OAAOe,UAAUI,gBAAgB;YAACG;SAAiB;QACzD,MAAMZ,aAAaV,KAAK,EAAE,CAAC,MAAM,CAC5B,MAAM,CAAC,CAACW,IAAuBA,AAAW,UAAXA,EAAE,IAAI,EACrC,OAAO,CAACC,CAAAA,MAAOA,IAAI,MAAM,CAAC,GAAG,CAACC,CAAAA,IAAKA,EAAE,IAAI;QAE9CL,OAAOE,YAAY,OAAO,CAAC;YAAC;YAAY;YAAS;SAAO;IAC5D;AACJ;AAEAJ,SAAS,oCAAoC;IACzC,MAAMa,iBAA4B;QAC9B,MAAM;QACN,OAAO;QACP,eAEA;IACJ;IAEA,MAAMC,kBAA6B;QAC/B,MAAM;QACN,OAAO;QACP,YAAWpB,IAAI;YACXA,KAAK,MAAM,CAACF,CAAAA,SAAW;oBACnB,SAASA,OACJ,IAAI,GACJ,KAAK,CAAC,WACN,QAAQ,CAAC,uBACT,OAAO,CAAC;wBACL;4BAAE,OAAO;4BAAS,OAAO;wBAAQ;wBACjC;4BAAE,OAAO;4BAAQ,OAAO;wBAAO;qBAClC;gBACT;YACAE,KAAK,KAAK,CAAC,SAAS,WAAW,CAAC;YAChCA,KAAK,KAAK,CAAC,QAAQ,WAAW,CAAC;YAC/BA,KAAK,MAAM,CAACI,CAAAA,SAAU;oBAACA,OAAO,GAAG,CAAC,WAAW,MAAM,CAAC;iBAAS;QACjE;IACJ;IAEA,MAAMoB,YAAuC;QACzC,QAAQL;QACR,SAASC;IACb;IAOA,SAASK,eACLC,WAAuB,EACvBC,OAAe,EACfV,YAAuC,EAAE;QAEzC,MAAMW,eAAeF,YAAY,OAAO;QACxC,MAAM1B,OAAOT;QACbiC,SAAS,CAACG,QAAQ,CAAC,UAAU,GAAG3B;QAChC,KAAK,MAAMkB,YAAYD,UACnBC,SAAS,UAAU,CAAClB;QAExBA,KAAK,OAAO,CAAC4B;QACb,OAAO5B;IACX;IAEAO,GAAG,iEAAiE;QAEhE,MAAMsB,aAAatC;QACnB4B,eAAe,UAAU,GAAGU;QAC5BA,WAAW,KAAK,CAAC,SAAS,QAAQ,CAAC;QACnCA,WAAW,KAAK,CAAC,QAAQ,QAAQ,CAAC;QAGlC,MAAMC,cAAcL,eAAeI,YAAY;QAE/CrB,OAAOsB,YAAY,KAAK,CAAC,SAAS,QAAQ,IAAI,IAAI,CAAC;QACnDtB,OAAOsB,YAAY,KAAK,CAAC,QAAQ,QAAQ,IAAI,IAAI,CAAC;IACtD;IAEAvB,GAAG,mDAAmD;QAElD,MAAMuB,cAAcvC;QACpB6B,gBAAgB,UAAU,GAAGU;QAC7BA,YAAY,KAAK,CAAC,WAAW,QAAQ,CAAC;QAGtC,MAAMD,aAAaJ,eAAeK,aAAa;QAE/C,MAAMpB,aAAamB,WAAW,EAAE,CAAC,MAAM,CAClC,MAAM,CAAC,CAAClB,IAAuBA,AAAW,UAAXA,EAAE,IAAI,EACrC,OAAO,CAACC,CAAAA,MAAOA,IAAI,MAAM,CAAC,GAAG,CAACC,CAAAA,IAAKA,EAAE,IAAI;QAC9CL,OAAOE,YAAY,OAAO,CAAC;YAAC;YAAS;SAAO;QAC5CF,OAAOqB,WAAW,OAAO,IAAI,GAAG,CAAC,cAAc,CAAC;IACpD;IAEAtB,GAAG,yEAAyE;QACxE,MAAMc,QAAuB;YACzB;gBAAE,IAAI;gBAAM,MAAM;gBAAM,MAAM;gBAAW,WAAW;YAAK;YACzD;gBAAE,IAAI;gBAAM,MAAM;gBAAM,MAAM;YAAS;SAC1C;QACD,MAAM,EAAE/B,OAAO,EAAED,UAAU,EAAE,GAAGF,oBAAoBkC;QACpD,MAAMC,mBAAmB,IAAIC,oBAAoBjC,SAASD;QAG1D,MAAMwC,aAAatC;QACnB4B,eAAe,UAAU,GAAGU;QAC5BP,iBAAiB,UAAU,CAACO;QAC5BA,WAAW,KAAK,CAAC,SAAS,QAAQ,CAAC;QAGnC,MAAME,YAAYF,WAAW,KAAK,CAAC,YAAY,QAAQ;QACvDrB,OAAOuB,WAAW,IAAI,CAAC;QAGvB,MAAMD,cAAcL,eAAeI,YAAY,WAAW;YAACP;SAAiB;QAE5Ed,OAAOsB,YAAY,KAAK,CAAC,YAAY,QAAQ,IAAI,IAAI,CAAC;QACtDtB,OAAOsB,YAAY,KAAK,CAAC,SAAS,QAAQ,IAAI,IAAI,CAAC;IACvD;IAEAvB,GAAG,sDAAsD;QACrD,MAAMsB,aAAatC;QACnB4B,eAAe,UAAU,GAAGU;QAC5BrB,OAAOqB,WAAW,OAAO,GAAG,QAAQ,EAAE,IAAI,CAAC;QAG3C,MAAMC,cAAcL,eAAeI,YAAY;QAK/CrB,OAAOsB,YAAY,KAAK,CAAC,YAAY,QAAQ,IAAI,IAAI,CAAC;IAC1D;AACJ"}
1
+ {"version":3,"file":"presentation/pages/CreatePage/CreatePage.test.js","sources":["../../../../src/presentation/pages/CreatePage/CreatePage.test.ts"],"sourcesContent":["import { describe, it, expect } from \"vitest\";\nimport { Container } from \"@webiny/di\";\nimport { FormModelFeature } from \"@webiny/app-admin/features/formModel/feature.js\";\nimport { IdentityContextFeature } from \"@webiny/app-admin/features/security/IdentityContext/feature.js\";\nimport { FormModelFactory } from \"@webiny/app-admin/features/formModel/abstractions.js\";\nimport type { IFormModel, IFormModelConfig, IRowNodeVM } from \"@webiny/app-admin\";\nimport type { LanguageDto } from \"@webiny/languages/admin/features/listLanguages/abstractions.js\";\nimport { AddLanguageModifier } from \"./AddLanguageModifier.js\";\nimport { PagePath } from \"~/shared/PagePath.js\";\nimport type { IPageType, ICreatePageFormModifier } from \"./abstractions.js\";\n\nfunction createLanguageMocks(languages: LanguageDto[]) {\n const repository = {\n execute: async () => languages,\n getLanguages: () => languages\n };\n const useCase = {\n execute: async () => languages\n };\n return { useCase, repository };\n}\n\nfunction createBaseForm(config?: Partial<IFormModelConfig>) {\n const container = new Container();\n IdentityContextFeature.register(container);\n FormModelFeature.register(container);\n const factory = container.resolve(FormModelFactory);\n\n return factory.create({\n fields: fields => ({\n title: fields\n .text()\n .label(\"Title\")\n .required(\"Title is required\")\n .onBlur((value, { form }) => {\n const currentPath = form.field(\"path\").getValue();\n if (currentPath) {\n return;\n }\n form.field(\"path\").setValue(PagePath.fromTitle(String(value)).toString());\n }),\n path: fields\n .text()\n .label(\"Path\")\n .required(\"Path is required\")\n .beforeChange(value => {\n return PagePath.create(String(value)).slugify().toString();\n }),\n pageType: fields.text().hidden().defaultValue(\"staticPage\")\n }),\n layout: layout => [layout.row(\"title\"), layout.row(\"path\")],\n ...config\n });\n}\n\n/**\n * Helper: set title and blur to trigger path generation.\n */\nfunction setTitleAndBlur(form: IFormModel, value: string) {\n form.field(\"title\").setValue(value);\n form.field(\"title\").blur();\n}\n\ndescribe(\"CreatePage base form\", () => {\n it(\"should create a form with title, path, and hidden pageType\", () => {\n const form = createBaseForm();\n expect(form.field(\"title\")).toBeDefined();\n expect(form.field(\"path\")).toBeDefined();\n expect(form.field(\"pageType\")).toBeDefined();\n });\n\n it(\"should include pageType in getData but not in layout\", () => {\n const form = createBaseForm();\n const data = form.getData();\n expect(data.pageType).toBe(\"staticPage\");\n\n const fieldNames = form.vm.layout\n .filter((n): n is IRowNodeVM => n.type === \"row\")\n .flatMap(row => row.fields.map(f => f.name));\n expect(fieldNames).not.toContain(\"pageType\");\n });\n\n it(\"should auto-generate path from title on blur\", () => {\n const form = createBaseForm();\n setTitleAndBlur(form, \"Hello World\");\n expect(form.field(\"path\").getValue()).toBe(\"/hello-world\");\n });\n\n it(\"should not auto-generate path on setValue alone (before blur)\", () => {\n const form = createBaseForm();\n form.field(\"title\").setValue(\"Hello World\");\n expect(form.field(\"path\").getValue()).toBeNull();\n });\n\n it(\"should not overwrite path when manually edited\", () => {\n const form = createBaseForm();\n setTitleAndBlur(form, \"Hello World\");\n form.field(\"path\").setValue(\"/custom-path\");\n setTitleAndBlur(form, \"New Title\");\n expect(form.field(\"path\").getValue()).toBe(\"/custom-path\");\n });\n\n it(\"should return data on valid submit\", async () => {\n const form = createBaseForm();\n form.field(\"title\").setValue(\"My Page\");\n form.field(\"path\").setValue(\"/my-page\");\n\n const result = await form.submit();\n expect(result).toEqual({\n title: \"My Page\",\n path: \"/my-page\",\n pageType: \"staticPage\"\n });\n });\n\n it(\"should return false on invalid submit\", async () => {\n const form = createBaseForm();\n const result = await form.submit();\n expect(result).toBe(false);\n expect(form.errors.length).toBeGreaterThan(0);\n });\n});\n\ndescribe(\"PageType + Modifier 3-layer architecture\", () => {\n /**\n * Simulates the 3-layer build order used by CreatePagePresenter:\n * 1. Base form (title, path, pageType)\n * 2. Page type modify\n * 3. Cross-cutting modifiers\n */\n function buildForm(pageType: IPageType, modifiers: ICreatePageFormModifier[] = []): IFormModel {\n const form = createBaseForm();\n pageType.modifyForm?.(form);\n for (const modifier of modifiers) {\n modifier.modifyForm(form);\n }\n return form;\n }\n\n const staticPageType: IPageType = {\n name: \"static\",\n label: \"Static Page\",\n modifyForm() {\n // no-op\n }\n };\n\n const productPageType: IPageType = {\n name: \"product\",\n label: \"Product Page\",\n modifyForm(form) {\n form.fields(fields => ({\n product: fields\n .text()\n .label(\"Product\")\n .required(\"Product is required\")\n .options([\n { label: \"Shoes\", value: \"shoes\" },\n { label: \"Hats\", value: \"hats\" }\n ])\n }));\n form.field(\"title\").setDisabled(true);\n form.field(\"path\").setDisabled(true);\n form.layout(layout => [layout.row(\"product\").before(\"title\")]);\n }\n };\n\n it(\"should leave base form unchanged for static page type\", () => {\n const form = buildForm(staticPageType);\n const fieldNames = form.vm.layout\n .filter((n): n is IRowNodeVM => n.type === \"row\")\n .flatMap(row => row.fields.map(f => f.name));\n expect(fieldNames).toEqual([\"title\", \"path\"]);\n });\n\n it(\"should add product field and disable title/path for product page type\", () => {\n const form = buildForm(productPageType);\n const fieldNames = form.vm.layout\n .filter((n): n is IRowNodeVM => n.type === \"row\")\n .flatMap(row => row.fields.map(f => f.name));\n expect(fieldNames).toEqual([\"product\", \"title\", \"path\"]);\n\n expect(form.field(\"title\").vm.disabled).toBe(true);\n expect(form.field(\"path\").vm.disabled).toBe(true);\n });\n\n it(\"should include product in getData\", () => {\n const form = buildForm(productPageType);\n form.field(\"product\").setValue(\"shoes\");\n const data = form.getData();\n expect(data.product).toBe(\"shoes\");\n });\n\n it(\"should apply cross-cutting modifier after page type\", () => {\n const langs: LanguageDto[] = [\n { id: \"en\", code: \"en\", name: \"English\", isDefault: true },\n { id: \"de\", code: \"de\", name: \"German\" }\n ];\n const { useCase, repository } = createLanguageMocks(langs);\n const languageModifier = new AddLanguageModifier(useCase, repository);\n\n const form = buildForm(productPageType, [languageModifier]);\n const fieldNames = form.vm.layout\n .filter((n): n is IRowNodeVM => n.type === \"row\")\n .flatMap(row => row.fields.map(f => f.name));\n\n // language before title (from modifier), product before title (from page type)\n expect(fieldNames).toEqual([\"product\", \"language\", \"title\", \"path\"]);\n });\n\n it(\"should apply cross-cutting modifier to static page type too\", () => {\n const langs: LanguageDto[] = [\n { id: \"en\", code: \"en\", name: \"English\", isDefault: true },\n { id: \"de\", code: \"de\", name: \"German\" }\n ];\n const { useCase, repository } = createLanguageMocks(langs);\n const languageModifier = new AddLanguageModifier(useCase, repository);\n\n const form = buildForm(staticPageType, [languageModifier]);\n const fieldNames = form.vm.layout\n .filter((n): n is IRowNodeVM => n.type === \"row\")\n .flatMap(row => row.fields.map(f => f.name));\n\n expect(fieldNames).toEqual([\"language\", \"title\", \"path\"]);\n });\n});\n\ndescribe(\"Form rebuild on page type switch\", () => {\n const staticPageType: IPageType = {\n name: \"static\",\n label: \"Static Page\",\n modifyForm() {\n // no-op\n }\n };\n\n const productPageType: IPageType = {\n name: \"product\",\n label: \"Product Page\",\n modifyForm(form) {\n form.fields(fields => ({\n product: fields\n .text()\n .label(\"Product\")\n .required(\"Product is required\")\n .options([\n { label: \"Shoes\", value: \"shoes\" },\n { label: \"Hats\", value: \"hats\" }\n ])\n }));\n form.field(\"title\").setDisabled(true);\n form.field(\"path\").setDisabled(true);\n form.layout(layout => [layout.row(\"product\").before(\"title\")]);\n }\n };\n\n const pageTypes: Record<string, IPageType> = {\n static: staticPageType,\n product: productPageType\n };\n\n /**\n * Simulates the presenter's changePageType: getData → rebuild → setData.\n * The real presenter sets `this.selectedPageType` before `buildForm()`,\n * which sets the hidden field's defaultValue. Here we just rebuild and restore.\n */\n function changePageType(\n currentForm: IFormModel,\n newType: string,\n modifiers: ICreatePageFormModifier[] = []\n ): IFormModel {\n const previousData = currentForm.getData();\n const form = createBaseForm();\n pageTypes[newType].modifyForm?.(form);\n for (const modifier of modifiers) {\n modifier.modifyForm(form);\n }\n form.setData(previousData);\n return form;\n }\n\n it(\"should preserve common field values when switching page types\", () => {\n // Start with static page, fill in title and path.\n const staticForm = createBaseForm();\n staticPageType.modifyForm?.(staticForm);\n staticForm.field(\"title\").setValue(\"My Page\");\n staticForm.field(\"path\").setValue(\"/my-page\");\n\n // Switch to product page.\n const productForm = changePageType(staticForm, \"product\");\n\n expect(productForm.field(\"title\").getValue()).toBe(\"My Page\");\n expect(productForm.field(\"path\").getValue()).toBe(\"/my-page\");\n });\n\n it(\"should drop page-type-specific fields on switch\", () => {\n // Start with product page, select a product.\n const productForm = createBaseForm();\n productPageType.modifyForm?.(productForm);\n productForm.field(\"product\").setValue(\"shoes\");\n\n // Switch to static page — product field should not exist.\n const staticForm = changePageType(productForm, \"static\");\n\n const fieldNames = staticForm.vm.layout\n .filter((n): n is IRowNodeVM => n.type === \"row\")\n .flatMap(row => row.fields.map(f => f.name));\n expect(fieldNames).toEqual([\"title\", \"path\"]);\n expect(staticForm.getData()).not.toHaveProperty(\"product\");\n });\n\n it(\"should preserve cross-cutting modifier values across page type switch\", () => {\n const langs: LanguageDto[] = [\n { id: \"en\", code: \"en\", name: \"English\", isDefault: true },\n { id: \"de\", code: \"de\", name: \"German\" }\n ];\n const { useCase, repository } = createLanguageMocks(langs);\n const languageModifier = new AddLanguageModifier(useCase, repository);\n\n // Start with static page + language modifier.\n const staticForm = createBaseForm();\n staticPageType.modifyForm?.(staticForm);\n languageModifier.modifyForm(staticForm);\n staticForm.field(\"title\").setValue(\"Demo\");\n // Language is auto-assigned \"en\" by the modifier reaction.\n\n const langValue = staticForm.field(\"language\").getValue();\n expect(langValue).toBe(\"en\");\n\n // Switch to product page with same modifier.\n const productForm = changePageType(staticForm, \"product\", [languageModifier]);\n\n expect(productForm.field(\"language\").getValue()).toBe(\"en\");\n expect(productForm.field(\"title\").getValue()).toBe(\"Demo\");\n });\n\n it(\"should preserve hidden field values across rebuild\", () => {\n const staticForm = createBaseForm();\n staticPageType.modifyForm?.(staticForm);\n expect(staticForm.getData().pageType).toBe(\"staticPage\");\n\n // Switch to product — setData restores pageType from previous form.\n const productForm = changePageType(staticForm, \"product\");\n\n // The hidden pageType field is preserved via setData.\n // In the real presenter, buildForm() sets defaultValue to the new type,\n // so the hidden field gets the correct value regardless.\n expect(productForm.field(\"pageType\").getValue()).toBe(\"staticPage\");\n });\n});\n"],"names":["createLanguageMocks","languages","repository","useCase","createBaseForm","config","container","Container","IdentityContextFeature","FormModelFeature","factory","FormModelFactory","fields","value","form","currentPath","PagePath","String","layout","setTitleAndBlur","describe","it","expect","data","fieldNames","n","row","f","result","buildForm","pageType","modifiers","modifier","staticPageType","productPageType","langs","languageModifier","AddLanguageModifier","pageTypes","changePageType","currentForm","newType","previousData","staticForm","productForm","langValue"],"mappings":"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"}
@@ -6,7 +6,7 @@ const fileManagerItemToValue = (file)=>{
6
6
  src,
7
7
  url: src,
8
8
  name: file.name,
9
- type: file.type,
9
+ mimeType: file.type,
10
10
  size: file.size
11
11
  };
12
12
  if ("image" === getAssetCategory(file.type)) {
@@ -19,6 +19,8 @@ const fileManagerItemToValue = (file)=>{
19
19
  alt: meta?.alt ?? void 0,
20
20
  caption: meta?.caption ?? void 0
21
21
  };
22
+ asset.width = asset.image.width;
23
+ asset.height = asset.image.height;
22
24
  }
23
25
  return asset;
24
26
  };
@@ -1 +1 @@
1
- {"version":3,"file":"shared/fileManagerItemToValue.js","sources":["../../src/shared/fileManagerItemToValue.ts"],"sourcesContent":["import type { FileManagerFileItem } from \"@webiny/app-admin\";\nimport { getAssetCategory, type Asset } from \"@webiny/website-builder-sdk\";\n\n/**\n * Build the unified {@link Asset} value from a picked File Manager item.\n * For images, the per-usage `image` edit is seeded from the asset-level default\n * (set in File Manager); from here it lives on the element value and is editable\n * per placement.\n */\nexport const fileManagerItemToValue = (file: FileManagerFileItem): Asset => {\n const src = file.src || \"\";\n const asset: Asset = {\n id: file.id,\n src,\n url: src,\n name: file.name,\n type: file.type,\n size: file.size\n };\n\n if (getAssetCategory(file.type) === \"image\") {\n const meta = file.metadata?.image;\n asset.image = {\n width: meta?.width ?? file.width,\n height: meta?.height ?? file.height,\n crop: meta?.crop ?? undefined,\n focalPoint: meta?.focalPoint ?? undefined,\n alt: meta?.alt ?? undefined,\n caption: meta?.caption ?? undefined\n };\n }\n\n return asset;\n};\n"],"names":["fileManagerItemToValue","file","src","asset","getAssetCategory","meta","undefined"],"mappings":";AASO,MAAMA,yBAAyB,CAACC;IACnC,MAAMC,MAAMD,KAAK,GAAG,IAAI;IACxB,MAAME,QAAe;QACjB,IAAIF,KAAK,EAAE;QACXC;QACA,KAAKA;QACL,MAAMD,KAAK,IAAI;QACf,MAAMA,KAAK,IAAI;QACf,MAAMA,KAAK,IAAI;IACnB;IAEA,IAAIG,AAAgC,YAAhCA,iBAAiBH,KAAK,IAAI,GAAe;QACzC,MAAMI,OAAOJ,KAAK,QAAQ,EAAE;QAC5BE,MAAM,KAAK,GAAG;YACV,OAAOE,MAAM,SAASJ,KAAK,KAAK;YAChC,QAAQI,MAAM,UAAUJ,KAAK,MAAM;YACnC,MAAMI,MAAM,QAAQC;YACpB,YAAYD,MAAM,cAAcC;YAChC,KAAKD,MAAM,OAAOC;YAClB,SAASD,MAAM,WAAWC;QAC9B;IACJ;IAEA,OAAOH;AACX"}
1
+ {"version":3,"file":"shared/fileManagerItemToValue.js","sources":["../../src/shared/fileManagerItemToValue.ts"],"sourcesContent":["import type { FileManagerFileItem } from \"@webiny/app-admin\";\nimport { getAssetCategory, type Asset } from \"@webiny/website-builder-sdk\";\n\n/**\n * Build the unified {@link Asset} value from a picked File Manager item.\n * For images, the per-usage `image` edit is seeded from the asset-level default\n * (set in File Manager); from here it lives on the element value and is editable\n * per placement.\n */\nexport const fileManagerItemToValue = (file: FileManagerFileItem): Asset => {\n const src = file.src || \"\";\n const asset: Asset = {\n id: file.id,\n src,\n url: src,\n name: file.name,\n mimeType: file.type,\n size: file.size\n };\n\n if (getAssetCategory(file.type) === \"image\") {\n const meta = file.metadata?.image;\n asset.image = {\n width: meta?.width ?? file.width,\n height: meta?.height ?? file.height,\n crop: meta?.crop ?? undefined,\n focalPoint: meta?.focalPoint ?? undefined,\n alt: meta?.alt ?? undefined,\n caption: meta?.caption ?? undefined\n };\n // Root dimensions for 6.4 frontends, which read `width`/`height` there.\n asset.width = asset.image.width;\n asset.height = asset.image.height;\n }\n\n return asset;\n};\n"],"names":["fileManagerItemToValue","file","src","asset","getAssetCategory","meta","undefined"],"mappings":";AASO,MAAMA,yBAAyB,CAACC;IACnC,MAAMC,MAAMD,KAAK,GAAG,IAAI;IACxB,MAAME,QAAe;QACjB,IAAIF,KAAK,EAAE;QACXC;QACA,KAAKA;QACL,MAAMD,KAAK,IAAI;QACf,UAAUA,KAAK,IAAI;QACnB,MAAMA,KAAK,IAAI;IACnB;IAEA,IAAIG,AAAgC,YAAhCA,iBAAiBH,KAAK,IAAI,GAAe;QACzC,MAAMI,OAAOJ,KAAK,QAAQ,EAAE;QAC5BE,MAAM,KAAK,GAAG;YACV,OAAOE,MAAM,SAASJ,KAAK,KAAK;YAChC,QAAQI,MAAM,UAAUJ,KAAK,MAAM;YACnC,MAAMI,MAAM,QAAQC;YACpB,YAAYD,MAAM,cAAcC;YAChC,KAAKD,MAAM,OAAOC;YAClB,SAASD,MAAM,WAAWC;QAC9B;QAEAH,MAAM,KAAK,GAAGA,MAAM,KAAK,CAAC,KAAK;QAC/BA,MAAM,MAAM,GAAGA,MAAM,KAAK,CAAC,MAAM;IACrC;IAEA,OAAOA;AACX"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,73 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { fileManagerItemToValue } from "./fileManagerItemToValue.js";
3
+ describe("fileManagerItemToValue", ()=>{
4
+ it("writes mimeType and image dimensions at the root and in image", ()=>{
5
+ const value = fileManagerItemToValue({
6
+ id: "file-1",
7
+ src: "https://cdn.test/files/file-1/cat.jpg",
8
+ name: "cat.jpg",
9
+ type: "image/jpeg",
10
+ size: 1234,
11
+ width: 1200,
12
+ height: 800
13
+ });
14
+ expect(value).toEqual({
15
+ id: "file-1",
16
+ src: "https://cdn.test/files/file-1/cat.jpg",
17
+ url: "https://cdn.test/files/file-1/cat.jpg",
18
+ name: "cat.jpg",
19
+ mimeType: "image/jpeg",
20
+ size: 1234,
21
+ width: 1200,
22
+ height: 800,
23
+ image: {
24
+ width: 1200,
25
+ height: 800,
26
+ crop: void 0,
27
+ focalPoint: void 0,
28
+ alt: void 0,
29
+ caption: void 0
30
+ }
31
+ });
32
+ });
33
+ it("prefers the File Manager image metadata for dimensions", ()=>{
34
+ const value = fileManagerItemToValue({
35
+ id: "file-2",
36
+ src: "https://cdn.test/files/file-2/dog.png",
37
+ name: "dog.png",
38
+ type: "image/png",
39
+ size: 10,
40
+ width: 100,
41
+ height: 100,
42
+ metadata: {
43
+ image: {
44
+ width: 640,
45
+ height: 480,
46
+ alt: "A dog"
47
+ }
48
+ }
49
+ });
50
+ expect(value.width).toBe(640);
51
+ expect(value.height).toBe(480);
52
+ expect(value.image).toMatchObject({
53
+ width: 640,
54
+ height: 480,
55
+ alt: "A dog"
56
+ });
57
+ });
58
+ it("leaves dimensions out for non-image files", ()=>{
59
+ const value = fileManagerItemToValue({
60
+ id: "file-3",
61
+ src: "https://cdn.test/files/file-3/doc.pdf",
62
+ name: "doc.pdf",
63
+ type: "application/pdf",
64
+ size: 99
65
+ });
66
+ expect(value.mimeType).toBe("application/pdf");
67
+ expect(value.width).toBeUndefined();
68
+ expect(value.height).toBeUndefined();
69
+ expect(value.image).toBeUndefined();
70
+ });
71
+ });
72
+
73
+ //# sourceMappingURL=fileManagerItemToValue.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared/fileManagerItemToValue.test.js","sources":["../../src/shared/fileManagerItemToValue.test.ts"],"sourcesContent":["import { describe, it, expect } from \"vitest\";\nimport { fileManagerItemToValue } from \"./fileManagerItemToValue.js\";\n\ndescribe(\"fileManagerItemToValue\", () => {\n it(\"writes mimeType and image dimensions at the root and in image\", () => {\n const value = fileManagerItemToValue({\n id: \"file-1\",\n src: \"https://cdn.test/files/file-1/cat.jpg\",\n name: \"cat.jpg\",\n type: \"image/jpeg\",\n size: 1234,\n width: 1200,\n height: 800\n });\n\n expect(value).toEqual({\n id: \"file-1\",\n src: \"https://cdn.test/files/file-1/cat.jpg\",\n url: \"https://cdn.test/files/file-1/cat.jpg\",\n name: \"cat.jpg\",\n mimeType: \"image/jpeg\",\n size: 1234,\n width: 1200,\n height: 800,\n image: {\n width: 1200,\n height: 800,\n crop: undefined,\n focalPoint: undefined,\n alt: undefined,\n caption: undefined\n }\n });\n });\n\n it(\"prefers the File Manager image metadata for dimensions\", () => {\n const value = fileManagerItemToValue({\n id: \"file-2\",\n src: \"https://cdn.test/files/file-2/dog.png\",\n name: \"dog.png\",\n type: \"image/png\",\n size: 10,\n width: 100,\n height: 100,\n metadata: { image: { width: 640, height: 480, alt: \"A dog\" } }\n });\n\n expect(value.width).toBe(640);\n expect(value.height).toBe(480);\n expect(value.image).toMatchObject({ width: 640, height: 480, alt: \"A dog\" });\n });\n\n it(\"leaves dimensions out for non-image files\", () => {\n const value = fileManagerItemToValue({\n id: \"file-3\",\n src: \"https://cdn.test/files/file-3/doc.pdf\",\n name: \"doc.pdf\",\n type: \"application/pdf\",\n size: 99\n });\n\n expect(value.mimeType).toBe(\"application/pdf\");\n expect(value.width).toBeUndefined();\n expect(value.height).toBeUndefined();\n expect(value.image).toBeUndefined();\n });\n});\n"],"names":["describe","it","value","fileManagerItemToValue","expect","undefined"],"mappings":";;AAGAA,SAAS,0BAA0B;IAC/BC,GAAG,iEAAiE;QAChE,MAAMC,QAAQC,uBAAuB;YACjC,IAAI;YACJ,KAAK;YACL,MAAM;YACN,MAAM;YACN,MAAM;YACN,OAAO;YACP,QAAQ;QACZ;QAEAC,OAAOF,OAAO,OAAO,CAAC;YAClB,IAAI;YACJ,KAAK;YACL,KAAK;YACL,MAAM;YACN,UAAU;YACV,MAAM;YACN,OAAO;YACP,QAAQ;YACR,OAAO;gBACH,OAAO;gBACP,QAAQ;gBACR,MAAMG;gBACN,YAAYA;gBACZ,KAAKA;gBACL,SAASA;YACb;QACJ;IACJ;IAEAJ,GAAG,0DAA0D;QACzD,MAAMC,QAAQC,uBAAuB;YACjC,IAAI;YACJ,KAAK;YACL,MAAM;YACN,MAAM;YACN,MAAM;YACN,OAAO;YACP,QAAQ;YACR,UAAU;gBAAE,OAAO;oBAAE,OAAO;oBAAK,QAAQ;oBAAK,KAAK;gBAAQ;YAAE;QACjE;QAEAC,OAAOF,MAAM,KAAK,EAAE,IAAI,CAAC;QACzBE,OAAOF,MAAM,MAAM,EAAE,IAAI,CAAC;QAC1BE,OAAOF,MAAM,KAAK,EAAE,aAAa,CAAC;YAAE,OAAO;YAAK,QAAQ;YAAK,KAAK;QAAQ;IAC9E;IAEAD,GAAG,6CAA6C;QAC5C,MAAMC,QAAQC,uBAAuB;YACjC,IAAI;YACJ,KAAK;YACL,MAAM;YACN,MAAM;YACN,MAAM;QACV;QAEAC,OAAOF,MAAM,QAAQ,EAAE,IAAI,CAAC;QAC5BE,OAAOF,MAAM,KAAK,EAAE,aAAa;QACjCE,OAAOF,MAAM,MAAM,EAAE,aAAa;QAClCE,OAAOF,MAAM,KAAK,EAAE,aAAa;IACrC;AACJ"}