diff --git a/packages/src/context/provider/content-overlay-controller.tsx b/packages/src/context/provider/content-overlay-controller.tsx index 4f72cfd..0c73620 100644 --- a/packages/src/context/provider/content-overlay-controller.tsx +++ b/packages/src/context/provider/content-overlay-controller.tsx @@ -1,30 +1,33 @@ import { type FC, useEffect, useRef } from 'react'; +import { type OverlayItemContext } from '../store'; -type OverlayControllerProps = { +type OverlayControllerProps = { overlayId: string; isOpen: boolean; close: () => void; unmount: () => void; + context: C; }; -type OverlayAsyncControllerProps = Omit & { +type OverlayAsyncControllerProps = Omit, 'close'> & { close: (param: T) => void; }; -export type OverlayControllerComponent = FC; -export type OverlayAsyncControllerComponent = FC>; +export type OverlayControllerComponent = FC>; +export type OverlayAsyncControllerComponent = FC>; -type ContentOverlayControllerProps = { +type ContentOverlayControllerProps = { isOpen: boolean; current: string | null; overlayId: string; onMounted: () => void; onCloseModal: () => void; onExitModal: () => void; - controller: OverlayControllerComponent; + controller: OverlayControllerComponent; + context: C; }; -export function ContentOverlayController({ +export function ContentOverlayController({ isOpen, current, overlayId, @@ -32,7 +35,8 @@ export function ContentOverlayController({ onCloseModal, onExitModal, controller: Controller, -}: ContentOverlayControllerProps) { + context, +}: ContentOverlayControllerProps) { const prevCurrent = useRef(current); const onMountedRef = useRef(onMounted); @@ -51,5 +55,7 @@ export function ContentOverlayController({ onMountedRef.current(); }, []); - return ; + return ( + + ); } diff --git a/packages/src/context/provider/index.tsx b/packages/src/context/provider/index.tsx index b7b2ce5..2a7f48a 100644 --- a/packages/src/context/provider/index.tsx +++ b/packages/src/context/provider/index.tsx @@ -35,6 +35,7 @@ export function createOverlayProvider(overlayStore: OverlayStore) { overlayStore.dispatchOverlay({ type: 'OPEN', overlayId: currentOverlayId }); }); }} + context={overlayState.overlayData[currentOverlayId].context} onCloseModal={() => overlay.close(currentOverlayId)} onExitModal={() => overlay.unmount(currentOverlayId)} controller={currentController} diff --git a/packages/src/context/reducer.ts b/packages/src/context/reducer.ts index 6b4ebb7..8b5bc72 100644 --- a/packages/src/context/reducer.ts +++ b/packages/src/context/reducer.ts @@ -1,10 +1,11 @@ -import { type OverlayData, type OverlayItem } from './store'; +import { type OverlayItemContext, type OverlayData, type OverlayItem } from './store'; export type OverlayReducerAction = - | { type: 'ADD'; overlay: OverlayItem } + | { type: 'ADD'; overlay: OverlayItem } | { type: 'OPEN'; overlayId: string } | { type: 'CLOSE'; overlayId: string } | { type: 'REMOVE'; overlayId: string } + | { type: 'UPDATE_CONTEXT'; overlayId: string; context: OverlayItemContext } | { type: 'CLOSE_ALL' } | { type: 'REMOVE_ALL' }; @@ -147,14 +148,23 @@ export function overlayReducer(state: OverlayData, action: OverlayReducerAction) [curr]: { ...state.overlayData[curr], isOpen: false, - } satisfies OverlayItem, + } satisfies OverlayItem, }), - {} satisfies Record + {} satisfies Record> ), }; } case 'REMOVE_ALL': { return { current: null, overlayOrderList: [], overlayData: {} }; } + case 'UPDATE_CONTEXT': { + return { + ...state, + overlayData: { + ...state.overlayData, + [action.overlayId]: { ...state.overlayData[action.overlayId], context: action.context }, + }, + }; + } } } diff --git a/packages/src/context/store.ts b/packages/src/context/store.ts index f6eb902..796aac7 100644 --- a/packages/src/context/store.ts +++ b/packages/src/context/store.ts @@ -2,15 +2,20 @@ import { type OverlayControllerComponent } from './provider/content-overlay-cont import { type OverlayReducerAction, overlayReducer } from './reducer'; type OverlayId = string; -export type OverlayItem = { + +export type OverlayItemContext = Record; + +export type OverlayItem = { id: OverlayId; isOpen: boolean; - controller: OverlayControllerComponent; + controller: OverlayControllerComponent; + context: C; }; + export type OverlayData = { current: OverlayId | null; overlayOrderList: OverlayId[]; - overlayData: Record; + overlayData: Record>; }; export type OverlayStore = ReturnType; diff --git a/packages/src/event.ts b/packages/src/event.ts index db6cc6c..f98d306 100644 --- a/packages/src/event.ts +++ b/packages/src/event.ts @@ -2,30 +2,39 @@ import { type OverlayAsyncControllerComponent, type OverlayControllerComponent, } from './context/provider/content-overlay-controller'; -import { type OverlayStore } from './context/store'; +import { type OverlayItemContext, type OverlayStore } from './context/store'; import { randomId } from './utils/random-id'; -type OpenOverlayOptions = { +type OpenOverlayOptions = { overlayId?: string; + context?: C; }; export function createOverlay(overlayStore: OverlayStore) { - function open(controller: OverlayControllerComponent, options?: OpenOverlayOptions) { + function open( + controller: OverlayControllerComponent, + options?: OpenOverlayOptions + ) { const overlayId = options?.overlayId ?? randomId(); + const context = options?.context; overlayStore.dispatchOverlay({ type: 'ADD', overlay: { id: overlayId, isOpen: false, - controller: controller, + controller: controller as OverlayControllerComponent, + context: context ?? ({} as C), }, }); return overlayId; } - async function openAsync(controller: OverlayAsyncControllerComponent, options?: OpenOverlayOptions) { + async function openAsync( + controller: OverlayAsyncControllerComponent, + options?: OpenOverlayOptions + ) { return new Promise((resolve) => { open((overlayProps, ...deprecatedLegacyContext) => { /** @@ -56,6 +65,9 @@ export function createOverlay(overlayStore: OverlayStore) { function unmountAll() { overlayStore.dispatchOverlay({ type: 'REMOVE_ALL' }); } + function updateContext(overlayId: string, context: C) { + overlayStore.dispatchOverlay({ type: 'UPDATE_CONTEXT', overlayId, context }); + } return { open, @@ -64,5 +76,6 @@ export function createOverlay(overlayStore: OverlayStore) { closeAll, unmountAll, openAsync, + updateContext, }; } diff --git a/packages/src/hook/use-overlay.ts b/packages/src/hook/use-overlay.ts new file mode 100644 index 0000000..dccfd6d --- /dev/null +++ b/packages/src/hook/use-overlay.ts @@ -0,0 +1,29 @@ +import { useEffect, useState } from 'react'; +import { + type OverlayAsyncControllerComponent, + type OverlayControllerComponent, +} from '../context/provider/content-overlay-controller'; +import { type OverlayItemContext } from '../context/store'; +import { overlay } from '../utils'; +import { randomId } from '../utils/random-id'; + +export interface UseOverlayProps { + context?: C; + overlayId?: string; +} + +export function useOverlay({ context, overlayId }: UseOverlayProps) { + const [id] = useState(() => overlayId ?? randomId()); + + useEffect(() => { + overlay.updateContext(id, context ?? ({} as C)); + }, [context, id]); + + return { + open: (controller: OverlayControllerComponent) => overlay.open(controller, { overlayId: id, context }), + openAsync: (controller: OverlayAsyncControllerComponent) => + overlay.openAsync(controller, { overlayId: id, context }), + close: () => overlay.close(id), + unmount: () => overlay.unmount(id), + }; +} diff --git a/packages/src/index.ts b/packages/src/index.ts index 04bca77..0133e1c 100644 --- a/packages/src/index.ts +++ b/packages/src/index.ts @@ -1 +1,2 @@ export * from './utils'; +export * from './hook/use-overlay'; \ No newline at end of file