diff --git a/package-lock.json b/package-lock.json index 4dafa96fb2..dc7f3d37a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,14 +5,12 @@ "requires": true, "packages": { "": { - "name": "manager-ui", "version": "1.0.1", "license": "Commons Clause License Condition v1.0", "dependencies": { "@aeaton/react-prosemirror": "^0.21.1", "@aeaton/react-prosemirror-config-default": "^0.11.0", "@babel/runtime": "^7.10.4", - "@bynder/compact-view": "^4.2.0", "@fortawesome/fontawesome-svg-core": "^1.2.35", "@fortawesome/free-brands-svg-icons": "^5.15.3", "@fortawesome/free-solid-svg-icons": "^5.14.0", @@ -43,13 +41,13 @@ "moment-timezone": "^0.5.33", "monaco-editor": "^0.25.2", "notistack": "^3.0.1", - "react": "^17.0.2", + "react": "^18.0.0", "react-chartjs-2": "^4.3.1", - "react-codemirror2": "^7.2.1", + "react-codemirror2": "^8.0.1", "react-cool-onclickoutside": "^1.5.6", "react-dnd": "^14.0.2", "react-dnd-html5-backend": "^14.0.0", - "react-dom": "^17.0.2", + "react-dom": "^18.0.0", "react-dropzone": "^14.2.2", "react-flatpickr": "^3.10.7", "react-measure": "^2.5.2", @@ -89,7 +87,7 @@ "@types/history": "^4.7.11", "@types/lodash": "^4.14.182", "@types/react": "^17.0.85", - "@types/react-dom": "^17.0.11", + "@types/react-dom": "^18.0.0", "@types/react-is": "^19.0.0", "@types/react-router-dom": "^5.3.3", "@types/react-virtualized-auto-sizer": "^1.0.1", @@ -1785,15 +1783,6 @@ "node": ">=6.9.0" } }, - "node_modules/@bynder/compact-view": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@bynder/compact-view/-/compact-view-4.3.3.tgz", - "integrity": "sha512-1Kw8/8mcVrrQOK95Jb5nmWKQmCqxf9bL3USXD0bimKkm4dg+MyNuOlboza23wDK23512wtWKSeqGCf5fKrLWOw==", - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, "node_modules/@colors/colors": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", @@ -3429,12 +3418,12 @@ } }, "node_modules/@types/react-dom": { - "version": "17.0.26", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.26.tgz", - "integrity": "sha512-Z+2VcYXJwOqQ79HreLU/1fyQ88eXSSFh6I3JdrEHQIfYSI0kCQpTGvOrbE6jFGGYXKsHuwY9tBa/w5Uo6KzrEg==", + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", "dev": true, "peerDependencies": { - "@types/react": "^17.0.0" + "@types/react": "^18.0.0" } }, "node_modules/@types/react-is": { @@ -12165,12 +12154,11 @@ "dev": true }, "node_modules/react": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", - "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" + "loose-envify": "^1.1.0" }, "engines": { "node": ">=0.10.0" @@ -12198,12 +12186,12 @@ } }, "node_modules/react-codemirror2": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/react-codemirror2/-/react-codemirror2-7.3.0.tgz", - "integrity": "sha512-gCgJPXDX+5iaPolkHAu1YbJ92a2yL7Je4TuyO3QEqOtI/d6mbEk08l0oIm18R4ctuT/Sl87X63xIMBnRQBXYXA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/react-codemirror2/-/react-codemirror2-8.0.1.tgz", + "integrity": "sha512-ZALowE5sGK1t66i0Fm1hoJLWT/iZHNjaAmcjwgYl9gyl2v1sqWwxzWHLmgq6K9KCk7p5+I+U3jMF1vsLaIkrmA==", "peerDependencies": { "codemirror": "5.x", - "react": ">=15.5 <=17.x" + "react": ">=15.5 <=18.x" } }, "node_modules/react-cool-onclickoutside": { @@ -12252,16 +12240,15 @@ } }, "node_modules/react-dom": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", - "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "dependencies": { "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "scheduler": "^0.20.2" + "scheduler": "^0.23.2" }, "peerDependencies": { - "react": "17.0.2" + "react": "^18.3.1" } }, "node_modules/react-dropzone": { @@ -13060,12 +13047,11 @@ "optional": true }, "node_modules/scheduler": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", - "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" + "loose-envify": "^1.1.0" } }, "node_modules/schema-utils": { @@ -17703,11 +17689,6 @@ "@babel/helper-validator-identifier": "^7.27.1" } }, - "@bynder/compact-view": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@bynder/compact-view/-/compact-view-4.3.3.tgz", - "integrity": "sha512-1Kw8/8mcVrrQOK95Jb5nmWKQmCqxf9bL3USXD0bimKkm4dg+MyNuOlboza23wDK23512wtWKSeqGCf5fKrLWOw==" - }, "@colors/colors": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", @@ -18744,9 +18725,9 @@ } }, "@types/react-dom": { - "version": "17.0.26", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.26.tgz", - "integrity": "sha512-Z+2VcYXJwOqQ79HreLU/1fyQ88eXSSFh6I3JdrEHQIfYSI0kCQpTGvOrbE6jFGGYXKsHuwY9tBa/w5Uo6KzrEg==", + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", "dev": true }, "@types/react-is": { @@ -25499,12 +25480,11 @@ } }, "react": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", - "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" + "loose-envify": "^1.1.0" } }, "react-base16-styling": { @@ -25525,9 +25505,9 @@ "integrity": "sha512-5i3mjP6tU7QSn0jvb8I4hudTzHJqS8l00ORJnVwI2sYu0ihpj83Lv2YzfxunfxTZkscKvZu2F2w9LkwNBhj6xA==" }, "react-codemirror2": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/react-codemirror2/-/react-codemirror2-7.3.0.tgz", - "integrity": "sha512-gCgJPXDX+5iaPolkHAu1YbJ92a2yL7Je4TuyO3QEqOtI/d6mbEk08l0oIm18R4ctuT/Sl87X63xIMBnRQBXYXA==" + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/react-codemirror2/-/react-codemirror2-8.0.1.tgz", + "integrity": "sha512-ZALowE5sGK1t66i0Fm1hoJLWT/iZHNjaAmcjwgYl9gyl2v1sqWwxzWHLmgq6K9KCk7p5+I+U3jMF1vsLaIkrmA==" }, "react-cool-onclickoutside": { "version": "1.7.0", @@ -25555,13 +25535,12 @@ } }, "react-dom": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", - "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "requires": { "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "scheduler": "^0.20.2" + "scheduler": "^0.23.2" } }, "react-dropzone": { @@ -26167,12 +26146,11 @@ "optional": true }, "scheduler": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", - "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" + "loose-envify": "^1.1.0" } }, "schema-utils": { diff --git a/package.json b/package.json index ea7e43a76e..ca1599b26f 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,6 @@ "@aeaton/react-prosemirror": "^0.21.1", "@aeaton/react-prosemirror-config-default": "^0.11.0", "@babel/runtime": "^7.10.4", - "@bynder/compact-view": "^4.2.0", "@fortawesome/fontawesome-svg-core": "^1.2.35", "@fortawesome/free-brands-svg-icons": "^5.15.3", "@fortawesome/free-solid-svg-icons": "^5.14.0", @@ -71,13 +70,13 @@ "moment-timezone": "^0.5.33", "monaco-editor": "^0.25.2", "notistack": "^3.0.1", - "react": "^17.0.2", + "react": "^18.0.0", "react-chartjs-2": "^4.3.1", - "react-codemirror2": "^7.2.1", + "react-codemirror2": "^8.0.1", "react-cool-onclickoutside": "^1.5.6", "react-dnd": "^14.0.2", "react-dnd-html5-backend": "^14.0.0", - "react-dom": "^17.0.2", + "react-dom": "^18.0.0", "react-dropzone": "^14.2.2", "react-flatpickr": "^3.10.7", "react-measure": "^2.5.2", @@ -116,8 +115,8 @@ "@types/cli-progress": "^3.11.6", "@types/history": "^4.7.11", "@types/lodash": "^4.14.182", + "@types/react-dom": "^18.0.0", "@types/react": "^17.0.85", - "@types/react-dom": "^17.0.11", "@types/react-is": "^19.0.0", "@types/react-router-dom": "^5.3.3", "@types/react-virtualized-auto-sizer": "^1.0.1", diff --git a/src/apps/active-preview/index.js b/src/apps/active-preview/index.js index 17041e0142..a7b292d618 100644 --- a/src/apps/active-preview/index.js +++ b/src/apps/active-preview/index.js @@ -1,4 +1,4 @@ -import ReactDOM from "react-dom"; +import { createRoot } from "react-dom/client"; import { Preview } from "./Preview"; import { ThemeProvider } from "@mui/material/styles"; import { theme } from "@zesty-io/material"; @@ -6,9 +6,11 @@ import { theme } from "@zesty-io/material"; // interploated by webpack at build time window.CONFIG = __CONFIG__; -ReactDOM.render( +const container = document.getElementById("root"); +const root = createRoot(container); + +root.render( - , - document.getElementById("root") + ); diff --git a/src/apps/content-editor/src/app/components/FieldTypeMedia.tsx b/src/apps/content-editor/src/app/components/FieldTypeMedia.tsx index aebd0237fa..3939b5fda5 100644 --- a/src/apps/content-editor/src/app/components/FieldTypeMedia.tsx +++ b/src/apps/content-editor/src/app/components/FieldTypeMedia.tsx @@ -32,7 +32,6 @@ import { CloseRounded, } from "@mui/icons-material"; import { alpha } from "@mui/material/styles"; -import { CompactView, Modal, Login } from "@bynder/compact-view"; import { Bynder, FileReplace } from "@zesty-io/material"; import { @@ -51,7 +50,7 @@ import cx from "classnames"; import { FileTypePreview } from "../../../../media/src/app/components/FileModal/FileTypePreview"; import { useGetInstanceSettingsQuery } from "../../../../../shell/services/instance"; import { ReplaceFileModal } from "../../../../media/src/app/components/FileModal/ReplaceFileModal"; -import { showReportDialog } from "@sentry/react"; +import openBynder from "../../../../../utility/openBynder"; type FieldTypeMediaProps = { images: string[]; @@ -90,7 +89,6 @@ export const FieldTypeMedia = forwardRef( const dispatch = useDispatch(); const [showFileModal, setShowFileModal] = useState(""); const [imageToReplace, setImageToReplace] = useState(""); - const [isBynderOpen, setIsBynderOpen] = useState(false); const { data: rawInstanceSettings } = useGetInstanceSettingsQuery(); const [selectionError, setSelectionError] = useState(""); @@ -180,8 +178,8 @@ export const FieldTypeMedia = forwardRef( onChange([...images, ...filteredImageZUIDs].join(","), name); }; - const addBynderAsset = (selectedAsset: any[]) => { - if (images.length > limit) return; + const addBynderAsset = (selectedAsset: ReadonlyArray) => { + if (images.length > limit || !selectedAsset?.length) return; const removedAssets: any[] = []; const filteredBynderAssets = selectedAsset?.filter((asset) => { @@ -263,7 +261,7 @@ export const FieldTypeMedia = forwardRef( onChange(newImageZUIDs.join(","), name); }; - const replaceBynderAsset = (selectedAsset: any) => { + const replaceBynderAsset = (selectedAsset: BynderImage) => { // Prevent adding bynder asset that has already been added if (localImageZUIDs.includes(selectedAsset.originalUrl)) return; @@ -328,6 +326,33 @@ export const FieldTypeMedia = forwardRef( onChange(newLocalImages.join(","), name); }; + const handleOpenBynder = () => { + openBynder({ + url: bynderPortalUrlSetting?.value, + onSuccess: (assets) => { + if (imageToReplace) { + replaceBynderAsset(assets[0]); + } else { + addBynderAsset(assets); + } + }, + mode: limit > 1 && !imageToReplace ? "MultiSelect" : "SingleSelect", + }); + }; + + useEffect(() => { + if (!!imageToReplace) { + if (imageToReplace.includes("bynder.com")) { + handleOpenBynder(); + } else { + openMediaBrowser({ + callback: replaceImage, + isReplace: true, + }); + } + } + }, [imageToReplace]); + const sortedImages = useMemo(() => { if (draggedIndex === null || hoveredIndex === null) { return localImageZUIDs; @@ -346,128 +371,114 @@ export const FieldTypeMedia = forwardRef( if (!images?.length) return ( - <> + evt.stopPropagation(), + onKeyDown: (evt) => evt.stopPropagation(), + })} + sx={{ + "&:focus-visible": { + outlineColor: (theme) => theme.palette.primary.main, + borderRadius: 2, + }, + }} + > + evt.stopPropagation(), - onKeyDown: (evt) => evt.stopPropagation(), - })} sx={{ - "&:focus-visible": { - outlineColor: (theme) => theme.palette.primary.main, - borderRadius: 2, - }, + border: (theme) => `1px dashed ${theme.palette.primary.main}`, + borderRadius: "8px", + backgroundColor: (theme) => + alpha(theme.palette.primary.main, 0.04), + borderColor: hasError ? "error.main" : "primary.main", }} > - - `1px dashed ${theme.palette.primary.main}`, - borderRadius: "8px", - backgroundColor: (theme) => - alpha(theme.palette.primary.main, 0.04), - borderColor: hasError ? "error.main" : "primary.main", - }} - > - + + {isDragActive ? ( + + ) : ( + + )} + {isDragActive ? ( - + "Drop your files here to Upload" ) : ( - + <> + Drag and drop your files here
or + )} - + {!isDragActive && ( + - {isDragActive ? ( - "Drop your files here to Upload" - ) : ( - <> - Drag and drop your files here
or - - )} -
- {!isDragActive && ( - } + fullWidth + sx={{ + maxWidth: "196px", + flexShrink: 0, + }} + > + Upload + + + {isBynderSessionValid && ( - - {isBynderSessionValid && ( - - )} - - )} -
-
- {selectionError && ( - - {selectionError} - - )} + )} +
+ )} +
- setIsBynderOpen(false)}> - - { - if (assets?.length) { - addBynderAsset(assets); - setIsBynderOpen(false); - } - }} - /> - - - + {selectionError && ( + + {selectionError} + + )} + ); return ( @@ -494,15 +505,6 @@ export const FieldTypeMedia = forwardRef( onRemove={removeImage} onReplace={(imageZUID) => { setImageToReplace(imageZUID); - - if (isBynderAsset) { - setIsBynderOpen(true); - } else { - openMediaBrowser({ - callback: replaceImage, - isReplace: true, - }); - } }} hideDrag={hideDrag || limit === 1} isBynderAsset={isBynderAsset} @@ -542,7 +544,7 @@ export const FieldTypeMedia = forwardRef( data-cy="addFromBynderBtn" size="large" variant="outlined" - onClick={() => setIsBynderOpen(true)} + onClick={handleOpenBynder} startIcon={} fullWidth > @@ -571,23 +573,6 @@ export const FieldTypeMedia = forwardRef( }} /> )} - setIsBynderOpen(false)}> - - { - if (assets?.length) { - if (imageToReplace) { - replaceBynderAsset(assets[0]); - } else { - addBynderAsset(assets); - } - - setIsBynderOpen(false); - } - }} - /> - - ); } diff --git a/src/apps/settings/src/app/views/Bynder.tsx b/src/apps/settings/src/app/views/Bynder.tsx index ea0da7a3e3..e8192ca39f 100644 --- a/src/apps/settings/src/app/views/Bynder.tsx +++ b/src/apps/settings/src/app/views/Bynder.tsx @@ -9,7 +9,6 @@ import { } from "@mui/material"; import PersonRemoveRoundedIcon from "@mui/icons-material/PersonRemoveRounded"; import { theme } from "@zesty-io/material"; -import { Modal, Login } from "@bynder/compact-view"; import bynderPreview from "../../../../../../public/images/bynder-preview.png"; import bynderLogo from "../../../../../../public/images/bynder-logo.svg"; @@ -18,10 +17,10 @@ import { useGetInstanceSettingsQuery, useUpdateInstanceSettingMutation, } from "../../../../../shell/services/instance"; +import openBynder from "../../../../../utility/openBynder"; // NOTE: cvrt is the bynder refresh token, determines if user is logged in or not export const Bynder = () => { - const [isLoginOpen, setIsLoginOpen] = useState(false); const [isBynderSessionValid, setIsBynderSessionValid] = useState(false); const [bynderSessionUrl, setBynderSessionUrl] = useState(""); const [createInstanceSetting] = useCreateInstanceSettingsMutation(); @@ -118,7 +117,13 @@ export const Bynder = () => { bynderToken = localStorage.getItem("cvrt"); if (!!bynderToken) { - setIsLoginOpen(false); + // This makes sure the bynder modal is closed after the user logs in + const bynderCloseButton = document + ?.querySelector("[data-test-id='CompactViewContainer'] div") + ?.shadowRoot.querySelector( + "button[title='Close']" + ) as HTMLButtonElement; + bynderCloseButton?.click(); } setIsBynderSessionValid(!!bynderToken); @@ -137,6 +142,12 @@ export const Bynder = () => { return () => clearInterval(bynderSessionInterval); }, [bynderTokenSetting]); + const handleOpenBynder = () => { + openBynder({ + url: bynderPortalUrlSetting?.value, + }); + }; + return ( { clearInterval(tokenInterval); updateBynderPortalUrl(""); updateBynderToken(""); - setIsLoginOpen(true); + handleOpenBynder(); }} > Change Bynder Portal @@ -211,11 +222,7 @@ export const Bynder = () => { Streamline your workflow by giving your team easy access to your Bynder assets within Zesty - @@ -231,12 +238,6 @@ export const Bynder = () => { /> )} - setIsLoginOpen(false)}> - - {/** HACK: Bynder's Login component requires a child*/} - <> - - ); }; diff --git a/src/index.html b/src/index.html index 1d750156ce..5e91aff912 100644 --- a/src/index.html +++ b/src/index.html @@ -114,6 +114,7 @@ }); } + <%= htmlWebpackPlugin.tags.headTags %> diff --git a/src/shell/byder.d.ts b/src/shell/byder.d.ts new file mode 100644 index 0000000000..9304f5ed92 --- /dev/null +++ b/src/shell/byder.d.ts @@ -0,0 +1,36 @@ +type BynderFile = Readonly<{ + fileSize: null | number; + height: null | number; + width: null | number; + url: string; +}>; + +type BynderImage = Readonly<{ + createdAt: string; + databaseId: string; + derivatives: Record; + description: string; + extensions: string[]; + files: Record; + id: string; + name: string; + originalUrl: string; + publishedAt: string; + tags: string[]; + type: string; + updatedAt: string; + url: string; +}>; + +type BynderMode = "MultiSelect" | "SingleSelect" | "SingleSelectFile"; + +declare const BynderCompactView: Readonly<{ + open: ( + options: Readonly<{ + onSuccess?: (assets: ReadonlyArray) => void; + portal?: Readonly<{ url?: string; editable?: boolean }>; + mode?: BynderMode; + assetTypes?: ReadonlyArray<"image" | "video" | "document" | "audio">; + }> + ) => void; +}>; diff --git a/src/shell/components/FieldTypeEditor/Editors/Html.js b/src/shell/components/FieldTypeEditor/Editors/Html.js index d31fe5c53c..cf0dda657c 100644 --- a/src/shell/components/FieldTypeEditor/Editors/Html.js +++ b/src/shell/components/FieldTypeEditor/Editors/Html.js @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from "react"; +import React, { useEffect, useState, useRef } from "react"; import cx from "classnames"; import styles from "./Html.less"; @@ -15,8 +15,19 @@ function parse(str = "") { } export function HtmlEditor(props) { + const editor = useRef(); + const wrapper = useRef(); + const mounted = useRef(false); + const [parsed, setParsed] = useState(parse(props.value)); + useEffect(() => { + mounted.current = true; + return () => { + mounted.current = false; + }; + }, []); + // NOTE: Update parsed value when version changes useEffect(() => { setParsed(parse(props.value)); @@ -24,6 +35,7 @@ export function HtmlEditor(props) { return ( { setParsed(value.trim()); }} onChange={(editor, data, value) => { + // Prevent firing onChange on first mount + if (!mounted.current) return; + + console.log("onChange", value.trim()); if (props.onChange) { props.onChange(value.trim()); } }} + // Fixes issue with React 18 where 2 editors are rendered + editorDidMount={(_editor) => (editor.current = _editor)} + editorWillUnmount={() => { + if (editor.current) { + editor.current.display.wrapper.remove(); + } + + if (wrapper.current) { + wrapper.current.hydrated = false; + } + }} /> ); } diff --git a/src/shell/components/FieldTypeEditor/Editors/Markdown.js b/src/shell/components/FieldTypeEditor/Editors/Markdown.js index d57fb607bf..2054c31c04 100644 --- a/src/shell/components/FieldTypeEditor/Editors/Markdown.js +++ b/src/shell/components/FieldTypeEditor/Editors/Markdown.js @@ -13,7 +13,7 @@ export function MarkdownEditor(props) { }); // update value if the version changes - useEffect(() => setValue(props.value), [props.version]); + useEffect(() => setValue(props.value), [props.version, props.value]); return (