From 852b0e7f465f5c0b34995b631ca01b6516c29f6b Mon Sep 17 00:00:00 2001 From: unsalgel Date: Mon, 27 Apr 2026 15:16:48 +0300 Subject: [PATCH 1/3] refactor: use ID-based closing logic in CustomPortal for better reliability --- .../ui/custom-portal/CustomPortal.tsx | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/components/ui/custom-portal/CustomPortal.tsx b/src/components/ui/custom-portal/CustomPortal.tsx index 84ff8c83..abab2574 100644 --- a/src/components/ui/custom-portal/CustomPortal.tsx +++ b/src/components/ui/custom-portal/CustomPortal.tsx @@ -31,7 +31,7 @@ interface PortalBaseValue { id?: string, toggle?: boolean ) => number | undefined; - closePortal: (index: number) => void; + closePortal: (id: string) => void; closePortalById: (id: string) => void; isPortalOpened: (id: string) => boolean; openedPortals: () => { @@ -63,6 +63,7 @@ interface Item { const [elements, setElements] = createStore([]); export const toast = (body: string, title?: string, icon?: string) => { + const id = "toast-" + Math.random(); setElements((e) => [ ...e, { @@ -74,7 +75,7 @@ export const toast = (body: string, title?: string, icon?: string) => { title={title || "Alert"} /> ), - id: "toast-" + Math.random() + id: id } ]); }; @@ -85,6 +86,7 @@ export const prompt = ( icon?: string, onSubmit?: (value: string) => void ) => { + const id = "prompt-" + Math.random(); setElements((e) => [ ...e, { @@ -98,7 +100,7 @@ export const prompt = ( prompt /> ), - id: "prompt-" + Math.random() + id: id } ]); }; @@ -128,6 +130,7 @@ export function CustomPortalProvider(props: CustomPortalProps) { id?: string, toggle?: boolean ) => { + const portalId = id || "portal-" + Math.random(); if (id && toggle) { if (isPortalOpened(id)) { closePortalById(id); @@ -135,11 +138,12 @@ export function CustomPortalProvider(props: CustomPortalProps) { } } if (id && isPortalOpened(id)) return; - setElements([...elements, { element, id }]); - return elements.length - 1; + setElements([...elements, { element, id: portalId }]); + return portalId; }; - const closePortal = async (index: number) => { + const closePortal = async (id: string) => { + const index = elements.findIndex((e) => e.id === id); const element = elements[index]; if (!element) return; if (element?.closing) return; @@ -183,10 +187,9 @@ export function CustomPortalProvider(props: CustomPortalProps) { {props.children} - {(item, i) => ( + {(item) => ( @@ -198,16 +201,20 @@ export function CustomPortalProvider(props: CustomPortalProps) { const PortalItem = (props: { item: Item; - i: number; - closePortal: (index: number) => void; + closePortal: (id: string) => void; setElements: SetStoreFunction; }) => { const close = () => { - props.closePortal(props.i); + if (props.item.id) { + props.closePortal(props.item.id); + } }; const setCustomCloseHandler = (customCloseHandler: () => void) => { - props.setElements(props.i, "customCloseHandler", () => customCloseHandler); + const index = elements.findIndex((e) => e.id === props.item.id); + if (index !== -1) { + props.setElements(index, "customCloseHandler", () => customCloseHandler); + } }; return ( From e05f557aa4c65638ff8cfc4549ae98869565d09e Mon Sep 17 00:00:00 2001 From: unsalgel Date: Mon, 27 Apr 2026 15:17:27 +0300 Subject: [PATCH 2/3] fix: ensure portal closing is safe against index shifts during async handlers --- src/components/ui/custom-portal/CustomPortal.tsx | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/components/ui/custom-portal/CustomPortal.tsx b/src/components/ui/custom-portal/CustomPortal.tsx index abab2574..c35e85f6 100644 --- a/src/components/ui/custom-portal/CustomPortal.tsx +++ b/src/components/ui/custom-portal/CustomPortal.tsx @@ -149,17 +149,9 @@ export function CustomPortalProvider(props: CustomPortalProps) { if (element?.closing) return; setElements(index, "closing", true); await element?.customCloseHandler?.(); - setElements(produce((elements) => elements.splice(index, 1))); - }; - const closePortalById = async (id: string) => { - const element = elements.find((e) => e.id === id); - if (!element) return; - if (element?.closing) return; - const index = elements.findIndex((e) => e.id === id); - setElements(index, "closing", true); - await element?.customCloseHandler?.(); setElements(elements.filter((e) => e.id !== id)); }; + const closePortalById = closePortal; const isPortalOpened = (id: string) => elements.find((e) => e.id === id) !== undefined; From b304b336435a94de1a4a7ab35bd5557b7a45ee4d Mon Sep 17 00:00:00 2001 From: unsalgel Date: Mon, 27 Apr 2026 15:29:34 +0300 Subject: [PATCH 3/3] fix: update createPortal interface return type to string --- src/components/ui/custom-portal/CustomPortal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ui/custom-portal/CustomPortal.tsx b/src/components/ui/custom-portal/CustomPortal.tsx index c35e85f6..00bba58e 100644 --- a/src/components/ui/custom-portal/CustomPortal.tsx +++ b/src/components/ui/custom-portal/CustomPortal.tsx @@ -30,7 +30,7 @@ interface PortalBaseValue { element: (close: () => void) => JSX.Element, id?: string, toggle?: boolean - ) => number | undefined; + ) => string | undefined; closePortal: (id: string) => void; closePortalById: (id: string) => void; isPortalOpened: (id: string) => boolean;