diff --git a/packages/src/context/context.ts b/packages/src/context/context.ts index ce99b3c..854cc5e 100644 --- a/packages/src/context/context.ts +++ b/packages/src/context/context.ts @@ -1,12 +1,13 @@ -import { type OverlayData } from './store'; +import { type OverlayState } from './store'; import { createSafeContext } from '../utils/create-safe-context'; -export const [OverlayContextProvider, useOverlayContext] = createSafeContext('overlay-kit/OverlayContext'); +export const [OverlayContextProvider, useOverlayContext] = + createSafeContext('overlay-kit/OverlayContext'); -export function useCurrentOverlay() { - return useOverlayContext().current; +export function useOverlayCurrentId() { + return useOverlayContext().currentId; } export function useOverlayData() { - return useOverlayContext().overlayData; + return useOverlayContext().data; } diff --git a/packages/src/context/index.ts b/packages/src/context/index.ts index 8d6608c..14ba617 100644 --- a/packages/src/context/index.ts +++ b/packages/src/context/index.ts @@ -1,2 +1,2 @@ export { OverlayProvider } from './provider'; -export { useCurrentOverlay, useOverlayData } from './context'; +export { useOverlayCurrentId, useOverlayData } from './context'; diff --git a/packages/src/context/provider.tsx b/packages/src/context/provider.tsx index 7847b32..a01ee2f 100644 --- a/packages/src/context/provider.tsx +++ b/packages/src/context/provider.tsx @@ -1,6 +1,6 @@ import { type FC, useEffect, useRef, type PropsWithChildren } from 'react'; import { OverlayContextProvider } from './context'; -import { dispatchOverlay } from './store'; +import { type OverlayItem, dispatchOverlay } from './store'; import { useSyncOverlayStore } from './use-sync-overlay-store'; import { overlay } from '../event'; @@ -16,22 +16,22 @@ export function OverlayProvider({ children }: PropsWithChildren) { return ( {children} - {overlayState.overlayOrderList.map((item) => { - const { id: currentOverlayId, isOpen, controller: currentController } = overlayState.overlayData[item]; + {overlayState.orderIds.map((orderId) => { + const { id: currentId, isOpen, controller: currentController } = overlayState.data[orderId]; return ( { requestAnimationFrame(() => { - dispatchOverlay({ type: 'OPEN', overlayId: currentOverlayId }); + dispatchOverlay({ type: 'OPEN', overlayId: currentId }); }); }} - onCloseModal={() => overlay.close(currentOverlayId)} - onExitModal={() => overlay.unmount(currentOverlayId)} + onCloseModal={() => overlay.close(currentId)} + onExitModal={() => overlay.unmount(currentId)} controller={currentController} /> ); @@ -56,8 +56,8 @@ export type OverlayAsyncControllerComponent = FC void; onCloseModal: () => void; onExitModal: () => void; @@ -66,23 +66,23 @@ type ContentOverlayControllerProps = { function ContentOverlayController({ isOpen, - current, + currentId, overlayId, onMounted, onCloseModal, onExitModal, controller: Controller, }: ContentOverlayControllerProps) { - const prevCurrent = useRef(current); + const prevCurrentId = useRef(currentId); const onMountedRef = useRef(onMounted); /** * @description Executes when closing and reopening an overlay without unmounting. */ - if (prevCurrent.current !== current) { - prevCurrent.current = current; + if (prevCurrentId.current !== currentId) { + prevCurrentId.current = currentId; - if (current === overlayId) { + if (currentId === overlayId) { onMountedRef.current(); } } diff --git a/packages/src/context/reducer.ts b/packages/src/context/reducer.ts index 53b462e..4df38b2 100644 --- a/packages/src/context/reducer.ts +++ b/packages/src/context/reducer.ts @@ -1,32 +1,32 @@ -import { type OverlayData, type OverlayItem } from './store'; +import { type OverlayState, type OverlayItem } from './store'; export type OverlayReducerAction = | { type: 'ADD'; overlay: OverlayItem } - | { type: 'OPEN'; overlayId: string } - | { type: 'CLOSE'; overlayId: string } - | { type: 'REMOVE'; overlayId: string } + | { type: 'OPEN'; overlayId: OverlayItem['id'] } + | { type: 'CLOSE'; overlayId: OverlayItem['id'] } + | { type: 'REMOVE'; overlayId: OverlayItem['id'] } | { type: 'CLOSE_ALL' } | { type: 'REMOVE_ALL' }; -export function overlayReducer(state: OverlayData, action: OverlayReducerAction): OverlayData { +export function overlayReducer(state: OverlayState, action: OverlayReducerAction): OverlayState { switch (action.type) { case 'ADD': { - const isExisted = state.overlayOrderList.includes(action.overlay.id); + const isExisted = state.orderIds.includes(action.overlay.id); - if (isExisted && state.overlayData[action.overlay.id].isOpen === true) { + if (isExisted && state.data[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, + currentId: 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: isExisted - ? state.overlayData + orderIds: [...state.orderIds.filter((orderId) => orderId !== action.overlay.id), action.overlay.id], + data: isExisted + ? state.data : { - ...state.overlayData, + ...state.data, [action.overlay.id]: action.overlay, }, }; @@ -34,20 +34,18 @@ export function overlayReducer(state: OverlayData, action: OverlayReducerAction) case 'OPEN': { return { ...state, - overlayData: { - ...state.overlayData, + data: { + ...state.data, [action.overlayId]: { - ...state.overlayData[action.overlayId], + ...state.data[action.overlayId], isOpen: true, }, }, }; } case 'CLOSE': { - const openedOverlayOrderList = state.overlayOrderList.filter( - (orderedOverlayId) => state.overlayData[orderedOverlayId].isOpen === true - ); - const targetIndexInOpenedList = openedOverlayOrderList.findIndex((item) => item === action.overlayId); + const openedOrderIds = state.orderIds.filter((orderId) => state.data[orderId].isOpen === true); + const targetOpenedOrderIdIndex = openedOrderIds.findIndex((openedOrderId) => openedOrderId === action.overlayId); /** * @description If closing the last overlay, specify the overlay before it. @@ -60,60 +58,60 @@ export function overlayReducer(state: OverlayData, action: OverlayReducerAction) * close 1 => current: null */ const currentOverlayId = - targetIndexInOpenedList === openedOverlayOrderList.length - 1 - ? openedOverlayOrderList[targetIndexInOpenedList - 1] ?? null - : openedOverlayOrderList.at(-1) ?? null; + targetOpenedOrderIdIndex === openedOrderIds.length - 1 + ? openedOrderIds[targetOpenedOrderIdIndex - 1] ?? null + : openedOrderIds.at(-1) ?? null; return { ...state, - current: currentOverlayId, - overlayData: { - ...state.overlayData, + currentId: currentOverlayId, + data: { + ...state.data, [action.overlayId]: { - ...state.overlayData[action.overlayId], + ...state.data[action.overlayId], isOpen: false, }, }, }; } case 'REMOVE': { - const remainingOverlays = state.overlayOrderList.filter((item) => item !== action.overlayId); - if (state.overlayOrderList.length === remainingOverlays.length) { + const remainingOrderIds = state.orderIds.filter((orderId) => orderId !== action.overlayId); + if (state.orderIds.length === remainingOrderIds.length) { return state; } - const copiedOverlayData = { ...state.overlayData }; - delete copiedOverlayData[action.overlayId]; + const copiedData = { ...state.data }; + delete copiedData[action.overlayId]; - const current = state.current - ? remainingOverlays.includes(state.current) + const currentId = state.currentId + ? remainingOrderIds.includes(state.currentId) ? /** * @description If `unmount` was executed after `close` */ - state.current + state.currentId : /** - * @description If you only run `unmount`, there is no `current` in `remainingOverlays` + * @description If you only run `unmount`, there is no `currentId` in `remainingOrderIds` */ - remainingOverlays.at(-1) ?? null + remainingOrderIds.at(-1) ?? null : /** - * @description The case where `current` is `null` + * @description The case where `currentId` is `null` */ null; return { - current, - overlayOrderList: remainingOverlays, - overlayData: copiedOverlayData, + currentId, + orderIds: remainingOrderIds, + data: copiedData, }; } case 'CLOSE_ALL': { return { ...state, - overlayData: Object.keys(state.overlayData).reduce( + data: Object.keys(state.data).reduce( (prev, curr) => ({ ...prev, [curr]: { - ...state.overlayData[curr], + ...state.data[curr], isOpen: false, } satisfies OverlayItem, }), @@ -122,7 +120,7 @@ export function overlayReducer(state: OverlayData, action: OverlayReducerAction) }; } case 'REMOVE_ALL': { - return { current: null, overlayOrderList: [], overlayData: {} }; + return { currentId: null, orderIds: [], data: {} }; } } } diff --git a/packages/src/context/store.ts b/packages/src/context/store.ts index 1991322..d836f9a 100644 --- a/packages/src/context/store.ts +++ b/packages/src/context/store.ts @@ -1,22 +1,22 @@ import { type OverlayControllerComponent } from './provider'; import { type OverlayReducerAction, overlayReducer } from './reducer'; -type OverlayId = string; +type OverlayItemId = string; export type OverlayItem = { - id: OverlayId; + id: OverlayItemId; isOpen: boolean; controller: OverlayControllerComponent; }; -export type OverlayData = { - current: OverlayId | null; - overlayOrderList: OverlayId[]; - overlayData: Record; +export type OverlayState = { + currentId: OverlayItemId | null; + orderIds: OverlayItemId[]; + data: Record; }; -let overlays: OverlayData = { - current: null, - overlayOrderList: [], - overlayData: {}, +let overlays: OverlayState = { + currentId: null, + orderIds: [], + data: {}, }; let listeners: Array<() => void> = []; @@ -34,7 +34,7 @@ export function dispatchOverlay(action: OverlayReducerAction) { /** * @description for useSyncExternalStorage */ -export const registerOverlaysStore = { +export const registerOverlayStore = { subscribe(listener: () => void) { listeners = [...listeners, listener]; diff --git a/packages/src/context/use-sync-overlay-store.ts b/packages/src/context/use-sync-overlay-store.ts index d7c4e5d..b50bd93 100644 --- a/packages/src/context/use-sync-overlay-store.ts +++ b/packages/src/context/use-sync-overlay-store.ts @@ -1,7 +1,7 @@ import { useSyncExternalStore } from 'use-sync-external-store/shim/index.js'; -import { registerOverlaysStore } from './store'; +import { registerOverlayStore } from './store'; export function useSyncOverlayStore() { - const { subscribe, getSnapshot } = registerOverlaysStore; + const { subscribe, getSnapshot } = registerOverlayStore; return useSyncExternalStore(subscribe, getSnapshot, getSnapshot); } diff --git a/packages/src/event.ts b/packages/src/event.ts index 2e1dd40..2a540c2 100644 --- a/packages/src/event.ts +++ b/packages/src/event.ts @@ -1,9 +1,9 @@ import { type OverlayAsyncControllerComponent, type OverlayControllerComponent } from './context/provider'; -import { dispatchOverlay } from './context/store'; +import { type OverlayItem, dispatchOverlay } from './context/store'; import { randomId } from './utils'; type OpenOverlayOptions = { - overlayId?: string; + overlayId?: OverlayItem['id']; }; function open(controller: OverlayControllerComponent, options?: OpenOverlayOptions) { @@ -40,10 +40,10 @@ async function openAsync(controller: OverlayAsyncControllerComponent, opti }); } -function close(overlayId: string) { +function close(overlayId: OverlayItem['id']) { dispatchOverlay({ type: 'CLOSE', overlayId }); } -function unmount(overlayId: string) { +function unmount(overlayId: OverlayItem['id']) { dispatchOverlay({ type: 'REMOVE', overlayId }); } function closeAll() {