mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-23 23:19:40 +01:00
fix: orphaned popup cannot be closed
This commit is contained in:
@@ -157,29 +157,20 @@ export function PopupPresenter(props) {
|
||||
}
|
||||
export function PopupWrapper(props) {
|
||||
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; });
|
||||
var isPopupOpen = useToolbarStore(function (store) { return !!store.openedPopups[id]; });
|
||||
var PopupRenderer = usePopupRenderer();
|
||||
var isPopupOpen = useToolbarStore(function (store) { return !!store.openedPopups[id]; });
|
||||
var openPopup = useToolbarStore(function (store) { return store.openPopup; });
|
||||
var closePopup = useToolbarStore(function (store) { return store.closePopup; });
|
||||
var closePopupGroup = useToolbarStore(function (store) { return store.closePopupGroup; });
|
||||
var isBottom = useToolbarStore(function (store) { return store.toolbarLocation === "bottom"; });
|
||||
if (isBottom)
|
||||
group = "popup";
|
||||
useEffect(function () {
|
||||
if (isPopupOpen) {
|
||||
closePopupGroup(group, [id]);
|
||||
}
|
||||
}, [onClosed, isPopupOpen, closePopupGroup, id, group]);
|
||||
useEffect(function () {
|
||||
if (!isPopupOpen)
|
||||
onClosed === null || onClosed === void 0 ? void 0 : onClosed();
|
||||
}, [isPopupOpen]);
|
||||
useEffect(function () {
|
||||
if (isOpen)
|
||||
openPopup({ id: id, group: group });
|
||||
else
|
||||
closePopup(id);
|
||||
}, [isOpen, id, group, openPopup]);
|
||||
}, [isOpen, id, group, openPopup, closePopup]);
|
||||
useEffect(function () {
|
||||
if (!autoCloseOnUnmount)
|
||||
return;
|
||||
@@ -188,18 +179,37 @@ export function PopupWrapper(props) {
|
||||
};
|
||||
}, [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: {
|
||||
boxShadow: "menu",
|
||||
borderRadius: "default",
|
||||
overflow: "hidden",
|
||||
// width,
|
||||
} }, { children: _jsx(EditorContext.Consumer, { children: function () {
|
||||
return renderPopup(function () { return PopupRenderer.closePopup(id); });
|
||||
} }) })) }), id)); });
|
||||
if (!isPopupOpen)
|
||||
onClosed === null || onClosed === void 0 ? void 0 : onClosed();
|
||||
}, [isPopupOpen]);
|
||||
useEffect(function () {
|
||||
if (isPopupOpen) {
|
||||
closePopupGroup(group, [id]);
|
||||
}
|
||||
else if (PopupRenderer && !isPopupOpen) {
|
||||
PopupRenderer.closePopup(id);
|
||||
}, [onClosed, isPopupOpen, closePopupGroup, id, group]);
|
||||
useEffect(function () {
|
||||
if (!isOpen)
|
||||
closePopup(id);
|
||||
}, [isOpen, id, group, closePopup]);
|
||||
useEffect(function () {
|
||||
if (PopupRenderer && isPopupOpen) {
|
||||
PopupRenderer.openPopup(id, function Popup(_a) {
|
||||
var id = _a.id;
|
||||
var isPopupOpen = useToolbarStore(function (store) { return !!store.openedPopups[id]; });
|
||||
useEffect(function () {
|
||||
if (!isPopupOpen) {
|
||||
PopupRenderer.closePopup(id);
|
||||
}
|
||||
}, [isPopupOpen]);
|
||||
return (_jsx(PopupPresenter, __assign({ isOpen: isPopupOpen, onClose: function () { return closePopup(id); }, position: position, blocking: true, focusOnRender: true }, presenterProps, { children: _jsx(Box, __assign({ sx: {
|
||||
boxShadow: "menu",
|
||||
borderRadius: "default",
|
||||
overflow: "hidden",
|
||||
// width,
|
||||
} }, { children: _jsx(EditorContext.Consumer, { children: function () {
|
||||
return renderPopup(function () { return PopupRenderer.closePopup(id); });
|
||||
} }) })) }), id));
|
||||
});
|
||||
}
|
||||
}, [PopupRenderer, isPopupOpen]);
|
||||
return null;
|
||||
|
||||
@@ -5,16 +5,19 @@ export declare const EditorContext: React.Context<Editor | null>;
|
||||
export declare type PopupRendererProps = PropsWithChildren<{
|
||||
editor: Editor;
|
||||
}>;
|
||||
declare type PopupComponent = React.FunctionComponent<{
|
||||
id: string;
|
||||
}>;
|
||||
declare type PopupRendererState = {
|
||||
popups: {
|
||||
id: string;
|
||||
popup: React.FunctionComponent;
|
||||
popup: PopupComponent;
|
||||
}[];
|
||||
};
|
||||
export declare class PopupRenderer extends React.Component<PopupRendererProps, PopupRendererState, PopupRendererState> {
|
||||
popupContainer: HTMLDivElement | null;
|
||||
state: PopupRendererState;
|
||||
openPopup: (id: string, popup: React.FunctionComponent) => void;
|
||||
openPopup: (id: string, popup: PopupComponent) => void;
|
||||
closePopup: (id: string) => void;
|
||||
render(): React.ReactNode;
|
||||
}
|
||||
|
||||
@@ -73,6 +73,7 @@ var PopupRenderer = /** @class */ (function (_super) {
|
||||
_this.closePopup = function (id) {
|
||||
_this.setState(function (prev) {
|
||||
var index = prev.popups.findIndex(function (p) { return p.id === id; });
|
||||
console.log("[closePopup] ", index, id);
|
||||
if (index <= -1)
|
||||
return prev;
|
||||
var clone = prev.popups.slice();
|
||||
@@ -87,7 +88,8 @@ var PopupRenderer = /** @class */ (function (_super) {
|
||||
PopupRenderer.prototype.render = function () {
|
||||
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;
|
||||
return _jsx(Popup, {}, id);
|
||||
console.log("rendering poopup", id);
|
||||
return _jsx(Popup, { id: id }, id);
|
||||
}), _jsx("div", { id: "popup-container" })] }))] })));
|
||||
};
|
||||
return PopupRenderer;
|
||||
|
||||
@@ -14,7 +14,7 @@ export declare type ToolButtonProps = ButtonProps & {
|
||||
};
|
||||
export declare const ToolButton: React.NamedExoticComponent<ButtonProps & {
|
||||
icon: IconNames;
|
||||
iconColor?: "icon" | "text" | "blue" | "gray" | "green" | "orange" | "purple" | "red" | "yellow" | "checked" | "disabled" | "placeholder" | "background" | "border" | "overlay" | keyof import("@notesnook/theme/dist/theme/colorscheme/static").StaticColors | "primary" | "bgTransparent" | "accent" | "bgSecondary" | "bgSecondaryText" | "hover" | "fontSecondary" | "fontTertiary" | "secondary" | undefined;
|
||||
iconColor?: "text" | "background" | "border" | "blue" | "gray" | "green" | "orange" | "purple" | "red" | "yellow" | "checked" | "disabled" | "placeholder" | "icon" | "overlay" | "hover" | keyof import("@notesnook/theme/dist/theme/colorscheme/static").StaticColors | "primary" | "bgTransparent" | "accent" | "bgSecondary" | "bgSecondaryText" | "fontSecondary" | "fontTertiary" | "secondary" | undefined;
|
||||
iconSize?: number | "big" | "small" | "medium" | undefined;
|
||||
toggled: boolean;
|
||||
buttonRef?: React.MutableRefObject<HTMLButtonElement | null | undefined> | undefined;
|
||||
|
||||
@@ -139,8 +139,5 @@ export function ColorPicker(props) {
|
||||
}, onClick: function () {
|
||||
setCurrentColor(color);
|
||||
onChange(color);
|
||||
} }, color)); })] })), onClose && (_jsx(Button, __assign({ variant: "icon", sx: { display: ["block", "none"], px: 2 }, onClick: onClose, onTouchStart: function (e) { return e.preventDefault(); }, onTouchEnd: function (e) {
|
||||
e.preventDefault();
|
||||
onClose();
|
||||
} }, { children: _jsx(Icon, { path: Icons.close, size: "big" }) })))] })] })));
|
||||
} }, color)); })] })), onClose && (_jsx(Button, __assign({ variant: "icon", sx: { display: ["block", "none"], px: 2 }, onClick: onClose }, { children: _jsx(Icon, { path: Icons.close, size: "big" }) })))] })] })));
|
||||
}
|
||||
|
||||
@@ -248,30 +248,22 @@ export function PopupWrapper(props: PopupWrapperProps) {
|
||||
autoCloseOnUnmount,
|
||||
...presenterProps
|
||||
} = props;
|
||||
const closePopup = useToolbarStore((store) => store.closePopup);
|
||||
const openPopup = useToolbarStore((store) => store.openPopup);
|
||||
const closePopupGroup = useToolbarStore((store) => store.closePopupGroup);
|
||||
const isPopupOpen = useToolbarStore((store) => !!store.openedPopups[id]);
|
||||
const PopupRenderer = usePopupRenderer();
|
||||
const isPopupOpen = useToolbarStore((store) => !!store.openedPopups[id]);
|
||||
const openPopup = useToolbarStore((store) => store.openPopup);
|
||||
const closePopup = useToolbarStore((store) => store.closePopup);
|
||||
const closePopupGroup = useToolbarStore((store) => store.closePopupGroup);
|
||||
|
||||
const isBottom = useToolbarStore(
|
||||
(store) => store.toolbarLocation === "bottom"
|
||||
);
|
||||
|
||||
if (isBottom) group = "popup";
|
||||
|
||||
useEffect(() => {
|
||||
if (isPopupOpen) {
|
||||
closePopupGroup(group, [id]);
|
||||
}
|
||||
}, [onClosed, isPopupOpen, closePopupGroup, id, group]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isPopupOpen) onClosed?.();
|
||||
}, [isPopupOpen]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen) openPopup({ id, group });
|
||||
else closePopup(id);
|
||||
}, [isOpen, id, group, openPopup]);
|
||||
}, [isOpen, id, group, openPopup, closePopup]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!autoCloseOnUnmount) return;
|
||||
@@ -280,36 +272,60 @@ export function PopupWrapper(props: PopupWrapperProps) {
|
||||
};
|
||||
}, [autoCloseOnUnmount, id]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isPopupOpen) onClosed?.();
|
||||
}, [isPopupOpen]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isPopupOpen) {
|
||||
closePopupGroup(group, [id]);
|
||||
}
|
||||
}, [onClosed, isPopupOpen, closePopupGroup, id, group]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isOpen) closePopup(id);
|
||||
}, [isOpen, id, group, closePopup]);
|
||||
|
||||
useEffect(() => {
|
||||
if (PopupRenderer && isPopupOpen) {
|
||||
PopupRenderer.openPopup(id, () => (
|
||||
<PopupPresenter
|
||||
key={id}
|
||||
isOpen={isPopupOpen}
|
||||
onClose={() => closePopup(id)}
|
||||
position={position}
|
||||
blocking
|
||||
focusOnRender
|
||||
{...presenterProps}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
boxShadow: "menu",
|
||||
borderRadius: "default",
|
||||
overflow: "hidden",
|
||||
// width,
|
||||
}}
|
||||
PopupRenderer.openPopup(id, function Popup({ id }) {
|
||||
const isPopupOpen = useToolbarStore(
|
||||
(store) => !!store.openedPopups[id]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isPopupOpen) {
|
||||
PopupRenderer.closePopup(id);
|
||||
}
|
||||
}, [isPopupOpen]);
|
||||
|
||||
return (
|
||||
<PopupPresenter
|
||||
key={id}
|
||||
isOpen={isPopupOpen}
|
||||
onClose={() => closePopup(id)}
|
||||
position={position}
|
||||
blocking
|
||||
focusOnRender
|
||||
{...presenterProps}
|
||||
>
|
||||
<EditorContext.Consumer>
|
||||
{() => {
|
||||
return renderPopup(() => PopupRenderer.closePopup(id));
|
||||
<Box
|
||||
sx={{
|
||||
boxShadow: "menu",
|
||||
borderRadius: "default",
|
||||
overflow: "hidden",
|
||||
// width,
|
||||
}}
|
||||
</EditorContext.Consumer>
|
||||
</Box>
|
||||
</PopupPresenter>
|
||||
));
|
||||
} else if (PopupRenderer && !isPopupOpen) {
|
||||
PopupRenderer.closePopup(id);
|
||||
>
|
||||
<EditorContext.Consumer>
|
||||
{() => {
|
||||
return renderPopup(() => PopupRenderer.closePopup(id));
|
||||
}}
|
||||
</EditorContext.Consumer>
|
||||
</Box>
|
||||
</PopupPresenter>
|
||||
);
|
||||
});
|
||||
}
|
||||
}, [PopupRenderer, isPopupOpen]);
|
||||
|
||||
|
||||
@@ -9,8 +9,9 @@ export const PopupRendererContext = React.createContext<PopupRenderer | null>(
|
||||
export const EditorContext = React.createContext<Editor | null>(null);
|
||||
|
||||
export type PopupRendererProps = PropsWithChildren<{ editor: Editor }>;
|
||||
type PopupComponent = React.FunctionComponent<{ id: string }>;
|
||||
type PopupRendererState = {
|
||||
popups: { id: string; popup: React.FunctionComponent }[];
|
||||
popups: { id: string; popup: PopupComponent }[];
|
||||
};
|
||||
export class PopupRenderer extends React.Component<
|
||||
PopupRendererProps,
|
||||
@@ -22,7 +23,7 @@ export class PopupRenderer extends React.Component<
|
||||
popups: [] as PopupRendererState["popups"],
|
||||
};
|
||||
|
||||
openPopup = (id: string, popup: React.FunctionComponent) => {
|
||||
openPopup = (id: string, popup: PopupComponent) => {
|
||||
if (!popup) return;
|
||||
this.setState((prev) => {
|
||||
return {
|
||||
@@ -49,7 +50,7 @@ export class PopupRenderer extends React.Component<
|
||||
{this.props.children}
|
||||
<EditorContext.Provider value={this.props.editor}>
|
||||
{this.state.popups.map(({ id, popup: Popup }) => {
|
||||
return <Popup key={id} />;
|
||||
return <Popup key={id} id={id} />;
|
||||
})}
|
||||
<div id="popup-container" />
|
||||
</EditorContext.Provider>
|
||||
|
||||
@@ -207,11 +207,6 @@ export function ColorPicker(props: ColorPickerProps) {
|
||||
variant={"icon"}
|
||||
sx={{ display: ["block", "none"], px: 2 }}
|
||||
onClick={onClose}
|
||||
onTouchStart={(e) => e.preventDefault()}
|
||||
onTouchEnd={(e) => {
|
||||
e.preventDefault();
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
<Icon path={Icons.close} size="big" />
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user