diff --git a/.changeset/tall-flowers-trade.md b/.changeset/tall-flowers-trade.md new file mode 100644 index 0000000..5da537a --- /dev/null +++ b/.changeset/tall-flowers-trade.md @@ -0,0 +1,10 @@ +--- +"overlay-kit": patch +--- + +fix: Enhance Overlay State Management and Prevent Duplicate Entries + +This change enhances the overlay state management to ensure overlays maintain the correct state when closed and reopened, and prevents duplicate overlay entries. +It addresses issues with the overlay's `current` state not updating correctly in certain scenarios. + +**Related Issue:** Fixes # 46 diff --git a/packages/src/context/provider.tsx b/packages/src/context/provider.tsx index cc3d620..c6200c4 100644 --- a/packages/src/context/provider.tsx +++ b/packages/src/context/provider.tsx @@ -17,6 +17,7 @@ export function OverlayProvider({ children }: PropsWithChildren) { { requestAnimationFrame(() => { @@ -44,6 +45,7 @@ export type OverlayControllerComponent = FC; type ContentOverlayControllerProps = { isOpen: boolean; + current: string | null; overlayId: string; onMounted: () => void; onCloseModal: () => void; @@ -53,14 +55,27 @@ type ContentOverlayControllerProps = { function ContentOverlayController({ isOpen, + current, overlayId, onMounted, onCloseModal, onExitModal, controller: Controller, }: ContentOverlayControllerProps) { + const prevCurrent = useRef(current); const onMountedRef = useRef(onMounted); + /** + * @description Executes when closing and reopening an overlay without unmounting. + */ + if (prevCurrent.current !== current) { + prevCurrent.current = current; + + if (current === overlayId) { + onMountedRef.current(); + } + } + useEffect(() => { onMountedRef.current(); }, []); diff --git a/packages/src/context/reducer.ts b/packages/src/context/reducer.ts index 72d1820..ae3a93a 100644 --- a/packages/src/context/reducer.ts +++ b/packages/src/context/reducer.ts @@ -11,9 +11,18 @@ export type OverlayReducerAction = export function overlayReducer(state: OverlayData, action: OverlayReducerAction): OverlayData { switch (action.type) { case 'ADD': { + const isExisted = state.overlayOrderList.includes(action.overlay.id); + + if (isExisted && state.overlayData[action.overlay.id].isOpen === true) { + throw new Error("You can't open the multiple overlays with the same overlayId. Please set a different id."); + } + return { current: action.overlay.id, - overlayOrderList: [...state.overlayOrderList, action.overlay.id], + /** + * @description Brings the overlay to the front when reopened after closing without unmounting. + */ + overlayOrderList: [...state.overlayOrderList.filter((item) => item !== action.overlay.id), action.overlay.id], overlayData: { ...state.overlayData, [action.overlay.id]: action.overlay,