diff --git a/packages/editor/dist/components/popuppresenter/index.d.ts b/packages/editor/dist/components/popuppresenter/index.d.ts index 1d11d6603..56597fe8d 100644 --- a/packages/editor/dist/components/popuppresenter/index.d.ts +++ b/packages/editor/dist/components/popuppresenter/index.d.ts @@ -19,6 +19,7 @@ export declare type PopupWrapperProps = { isOpen: boolean; onClosed?: () => void; renderPopup: (closePopup: () => void) => React.ReactNode; + autoCloseOnUnmount?: boolean; } & Partial>; export declare function PopupWrapper(props: PopupWrapperProps): null; declare type ShowPopupOptions = { diff --git a/packages/editor/dist/components/popuppresenter/index.js b/packages/editor/dist/components/popuppresenter/index.js index e83005d72..06bcc3541 100644 --- a/packages/editor/dist/components/popuppresenter/index.js +++ b/packages/editor/dist/components/popuppresenter/index.js @@ -146,7 +146,7 @@ export function PopupPresenter(props) { return _jsx(_PopupPresenter, __assign({}, props)); } export function PopupWrapper(props) { - var id = props.id, group = props.group, position = props.position, renderPopup = props.renderPopup, isOpen = props.isOpen, onClosed = props.onClosed, presenterProps = __rest(props, ["id", "group", "position", "renderPopup", "isOpen", "onClosed"]); + var id = props.id, group = props.group, position = props.position, renderPopup = props.renderPopup, isOpen = props.isOpen, onClosed = props.onClosed, autoCloseOnUnmount = props.autoCloseOnUnmount, presenterProps = __rest(props, ["id", "group", "position", "renderPopup", "isOpen", "onClosed", "autoCloseOnUnmount"]); var closePopup = useToolbarStore(function (store) { return store.closePopup; }); var openPopup = useToolbarStore(function (store) { return store.openPopup; }); var closePopupGroup = useToolbarStore(function (store) { return store.closePopupGroup; }); @@ -165,17 +165,18 @@ export function PopupWrapper(props) { onClosed === null || onClosed === void 0 ? void 0 : onClosed(); }, [isPopupOpen]); useEffect(function () { - console.log("Opening popup", id, isOpen); if (isOpen) openPopup({ id: id, group: group }); else closePopup(id); }, [isOpen, id, group, openPopup]); useEffect(function () { + if (!autoCloseOnUnmount) + return; return function () { PopupRenderer === null || PopupRenderer === void 0 ? void 0 : PopupRenderer.closePopup(id); }; - }, [id]); + }, [autoCloseOnUnmount, id]); useEffect(function () { if (PopupRenderer && isPopupOpen) { PopupRenderer.openPopup(id, function () { return (_jsx(PopupPresenter, __assign({ isOpen: isPopupOpen, onClose: function () { return closePopup(id); }, position: position, blocking: true, focusOnRender: true }, presenterProps, { children: _jsx(Box, __assign({ sx: { diff --git a/packages/editor/dist/components/popuppresenter/popuprenderer.d.ts b/packages/editor/dist/components/popuppresenter/popuprenderer.d.ts index bafffe0dc..7202e07cf 100644 --- a/packages/editor/dist/components/popuppresenter/popuprenderer.d.ts +++ b/packages/editor/dist/components/popuppresenter/popuprenderer.d.ts @@ -6,13 +6,16 @@ export declare type PopupRendererProps = PropsWithChildren<{ editor: Editor; }>; declare type PopupRendererState = { - popups: Record; + popups: { + id: string; + popup: React.FunctionComponent; + }[]; }; -export declare class PopupRenderer extends React.Component { +export declare class PopupRenderer extends React.Component { popupContainer: HTMLDivElement | null; state: PopupRendererState; - openPopup(id: string, popup: React.FunctionComponent): void; - closePopup(id: string): void; + openPopup: (id: string, popup: React.FunctionComponent) => void; + closePopup: (id: string) => void; render(): React.ReactNode; } export declare function usePopupRenderer(): PopupRenderer | null; diff --git a/packages/editor/dist/components/popuppresenter/popuprenderer.js b/packages/editor/dist/components/popuppresenter/popuprenderer.js index 25cfb0db8..a4adb8b65 100644 --- a/packages/editor/dist/components/popuppresenter/popuprenderer.js +++ b/packages/editor/dist/components/popuppresenter/popuprenderer.js @@ -40,6 +40,15 @@ var __read = (this && this.__read) || function (o, n) { } return ar; }; +var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { + if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { + if (ar || !(i in from)) { + if (!ar) ar = Array.prototype.slice.call(from, 0, i); + ar[i] = from[i]; + } + } + return to.concat(ar || Array.prototype.slice.call(from)); +}; import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import React, { useContext } from "react"; export var PopupRendererContext = React.createContext(null); @@ -50,23 +59,36 @@ var PopupRenderer = /** @class */ (function (_super) { var _this = _super !== null && _super.apply(this, arguments) || this; _this.popupContainer = null; _this.state = { - popups: {}, + popups: [], + }; + _this.openPopup = function (id, popup) { + if (!popup) + return; + _this.setState(function (prev) { + return { + popups: __spreadArray(__spreadArray([], __read(prev.popups), false), [{ id: id, popup: popup }], false), + }; + }); + }; + _this.closePopup = function (id) { + _this.setState(function (prev) { + var index = prev.popups.findIndex(function (p) { return p.id === id; }); + if (index <= -1) + return prev; + console.log(index, id, prev.popups[index]); + var clone = prev.popups.slice(); + clone.splice(index, 1); + return { + popups: clone, + }; + }); }; return _this; } - PopupRenderer.prototype.openPopup = function (id, popup) { - var _a; - this.setState({ popups: __assign(__assign({}, this.state.popups), (_a = {}, _a[id] = popup, _a)) }); - }; - PopupRenderer.prototype.closePopup = function (id) { - var _a; - this.setState({ popups: __assign(__assign({}, this.state.popups), (_a = {}, _a[id] = null, _a)) }); - }; PopupRenderer.prototype.render = function () { - return (_jsxs(PopupRendererContext.Provider, __assign({ value: this }, { children: [this.props.children, _jsxs(EditorContext.Provider, __assign({ value: this.props.editor }, { children: [Object.entries(this.state.popups).map(function (_a) { - var _b = __read(_a, 2), id = _b[0], Popup = _b[1]; - if (!Popup) - return null; + return (_jsxs(PopupRendererContext.Provider, __assign({ value: this }, { children: [this.props.children, _jsxs(EditorContext.Provider, __assign({ value: this.props.editor }, { children: [this.state.popups.map(function (_a) { + var id = _a.id, Popup = _a.popup; + console.log(id, Popup); return _jsx(Popup, {}, id); }), _jsx("div", { id: "popup-container" })] }))] }))); }; diff --git a/packages/editor/dist/toolbar/components/moretools.d.ts b/packages/editor/dist/toolbar/components/moretools.d.ts index 76d87de17..f630e403e 100644 --- a/packages/editor/dist/toolbar/components/moretools.d.ts +++ b/packages/editor/dist/toolbar/components/moretools.d.ts @@ -4,6 +4,7 @@ import { ToolId } from "../tools"; declare type MoreToolsProps = ToolProps & { popupId: string; tools: ToolId[]; + autoCloseOnUnmount?: boolean; }; export declare function MoreTools(props: MoreToolsProps): JSX.Element; export {}; diff --git a/packages/editor/dist/toolbar/components/moretools.js b/packages/editor/dist/toolbar/components/moretools.js index e53313de4..82eadff96 100644 --- a/packages/editor/dist/toolbar/components/moretools.js +++ b/packages/editor/dist/toolbar/components/moretools.js @@ -33,7 +33,7 @@ import { useToolbarLocation } from "../stores/toolbar-store"; import { getToolbarElement } from "../utils/dom"; import { ToolbarGroup } from "./toolbar-group"; export function MoreTools(props) { - var popupId = props.popupId, editor = props.editor, tools = props.tools; + var popupId = props.popupId, editor = props.editor, tools = props.tools, autoCloseOnUnmount = props.autoCloseOnUnmount; var toolbarLocation = useToolbarLocation(); var isBottom = toolbarLocation === "bottom"; var buttonRef = useRef(); @@ -44,7 +44,7 @@ export function MoreTools(props) { align: "center", location: isBottom ? "top" : "below", yOffset: isBottom ? 10 : 5, - }, focusOnRender: false, blocking: false, renderPopup: function () { return (_jsx(ToolbarGroup, { tools: tools, editor: editor, sx: { + }, autoCloseOnUnmount: autoCloseOnUnmount, focusOnRender: false, blocking: false, renderPopup: function () { return (_jsx(ToolbarGroup, { tools: tools, editor: editor, sx: { flex: 1, p: 1, // TODO: we cannot put a fix height here diff --git a/packages/editor/dist/toolbar/tools/colors.js b/packages/editor/dist/toolbar/tools/colors.js index 4843499df..b212139ef 100644 --- a/packages/editor/dist/toolbar/tools/colors.js +++ b/packages/editor/dist/toolbar/tools/colors.js @@ -72,7 +72,7 @@ export function ColorTool(props) { }, }, onOpen: function () { setIsOpen(function (s) { return !s; }); - }, toggled: isOpen }, { children: _jsx(PopupWrapper, { isOpen: isOpen, id: title, group: "color", position: { + }, toggled: isOpen }, { children: _jsx(PopupWrapper, { isOpen: isOpen, id: props.icon, group: "color", position: { isTargetAbsolute: true, target: getToolbarElement(), align: isBottom ? "center" : "end", diff --git a/packages/editor/dist/toolbar/tools/image.js b/packages/editor/dist/toolbar/tools/image.js index b9e2e6b89..100437359 100644 --- a/packages/editor/dist/toolbar/tools/image.js +++ b/packages/editor/dist/toolbar/tools/image.js @@ -41,7 +41,7 @@ export function ImageSettings(props) { return null; var image = useMemo(function () { return findSelectedNode(editor, "image"); }, []); var float = ((image === null || image === void 0 ? void 0 : image.attrs) || {}).float; - return (_jsx(MoreTools, __assign({}, props, { popupId: "imageSettings", tools: float + return (_jsx(MoreTools, __assign({}, props, { autoCloseOnUnmount: true, popupId: "imageSettings", tools: float ? ["imageAlignLeft", "imageAlignRight", "imageProperties"] : [ "imageAlignLeft", diff --git a/packages/editor/dist/toolbar/tools/table.js b/packages/editor/dist/toolbar/tools/table.js index 6cd9c2693..5e0eed249 100644 --- a/packages/editor/dist/toolbar/tools/table.js +++ b/packages/editor/dist/toolbar/tools/table.js @@ -44,7 +44,7 @@ export function TableSettings(props) { var isBottom = useToolbarLocation() === "bottom"; if (!editor.isActive("table") || !isBottom) return null; - return (_jsx(MoreTools, __assign({}, props, { popupId: "tableSettings", tools: [ + return (_jsx(MoreTools, __assign({}, props, { autoCloseOnUnmount: true, popupId: "tableSettings", tools: [ "insertColumnLeft", "insertColumnRight", "insertRowAbove", diff --git a/packages/editor/src/components/popup-presenter/index.tsx b/packages/editor/src/components/popup-presenter/index.tsx index 70199eda9..254efe811 100644 --- a/packages/editor/src/components/popup-presenter/index.tsx +++ b/packages/editor/src/components/popup-presenter/index.tsx @@ -224,6 +224,7 @@ export type PopupWrapperProps = { isOpen: boolean; onClosed?: () => void; renderPopup: (closePopup: () => void) => React.ReactNode; + autoCloseOnUnmount?: boolean; } & Partial>; export function PopupWrapper(props: PopupWrapperProps) { let { @@ -233,6 +234,7 @@ export function PopupWrapper(props: PopupWrapperProps) { renderPopup, isOpen, onClosed, + autoCloseOnUnmount, ...presenterProps } = props; const closePopup = useToolbarStore((store) => store.closePopup); @@ -256,16 +258,16 @@ export function PopupWrapper(props: PopupWrapperProps) { }, [isPopupOpen]); useEffect(() => { - console.log("Opening popup", id, isOpen); if (isOpen) openPopup({ id, group }); else closePopup(id); }, [isOpen, id, group, openPopup]); useEffect(() => { + if (!autoCloseOnUnmount) return; return () => { PopupRenderer?.closePopup(id); }; - }, [id]); + }, [autoCloseOnUnmount, id]); useEffect(() => { if (PopupRenderer && isPopupOpen) { diff --git a/packages/editor/src/components/popup-presenter/popuprenderer.tsx b/packages/editor/src/components/popup-presenter/popuprenderer.tsx index 37da8868e..64f00d6a6 100644 --- a/packages/editor/src/components/popup-presenter/popuprenderer.tsx +++ b/packages/editor/src/components/popup-presenter/popuprenderer.tsx @@ -9,28 +9,48 @@ export const PopupRendererContext = React.createContext( export const EditorContext = React.createContext(null); export type PopupRendererProps = PropsWithChildren<{ editor: Editor }>; -type PopupRendererState = { popups: Record }; -export class PopupRenderer extends React.Component { +type PopupRendererState = { + popups: { id: string; popup: React.FunctionComponent }[]; +}; +export class PopupRenderer extends React.Component< + PopupRendererProps, + PopupRendererState, + PopupRendererState +> { popupContainer: HTMLDivElement | null = null; state: PopupRendererState = { - popups: {} as Record, + popups: [] as PopupRendererState["popups"], }; - openPopup(id: string, popup: React.FunctionComponent) { - this.setState({ popups: { ...this.state.popups, [id]: popup } }); - } + openPopup = (id: string, popup: React.FunctionComponent) => { + if (!popup) return; + this.setState((prev) => { + return { + popups: [...prev.popups, { id, popup }], + }; + }); + }; - closePopup(id: string) { - this.setState({ popups: { ...this.state.popups, [id]: null } }); - } + closePopup = (id: string) => { + this.setState((prev) => { + const index = prev.popups.findIndex((p) => p.id === id); + if (index <= -1) return prev; + console.log(index, id, prev.popups[index]); + const clone = prev.popups.slice(); + clone.splice(index, 1); + return { + popups: clone, + }; + }); + }; render(): React.ReactNode { return ( {this.props.children} - {Object.entries(this.state.popups).map(([id, Popup]) => { - if (!Popup) return null; + {this.state.popups.map(({ id, popup: Popup }) => { + console.log(id, Popup); return ; })}