fix: orphaned popup cannot be closed

This commit is contained in:
thecodrr
2022-06-28 06:46:29 +05:00
parent 21c16b8f73
commit a1f45ee0b0
8 changed files with 106 additions and 82 deletions

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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" }) })))] })] })));
}

View File

@@ -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]);

View File

@@ -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>

View File

@@ -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>