UNPKG

@react-crates/modal

Version:

리액트 모달을 쉽게 등록하고 사용가능한 라이브러리입니다.

507 lines (486 loc) 20.3 kB
/// <reference types="react" /> import * as react from 'react'; import { FC, ReactNode, CSSProperties, FocusEventHandler, ReactElement, ButtonHTMLAttributes, ElementType, ComponentPropsWithoutRef, Fragment } from 'react'; type ModalLifecycleState = "open" | "active" | "close"; interface ModalTransition { transitionProperty: string; transitionDuration: string; transitionTimingFunction: string; transitionDelay: string; } type ModalTransitionProps = { [key in keyof ModalTransition]?: ModalTransition[key]; }; type DefaultModalPosition = "default" | "bottom" | "top" | "left" | "right" | "center" | "leftTop" | "leftBottom" | "rightTop" | "rightBottom"; interface PositionStyle { left?: string; right?: string; top?: string; bottom?: string; transform?: string; opacity?: number; background?: string; className?: string; } type ModalPositionStyle = { [key in ModalLifecycleState]: PositionStyle; }; type ModalPositionTable<T extends string = string> = { [key in DefaultModalPosition | T]: ModalPositionStyle; }; type ModalPositionMap<T extends string = string> = Map<T | DefaultModalPosition, ModalPositionStyle>; type CombinedPosition<T extends string> = T | `${T}-${T}` | `${T}-${T}-${T}`; type ModalPosition<T extends string = DefaultModalPosition> = ((breakPoint: number) => CombinedPosition<DefaultModalPosition | T>) | CombinedPosition<DefaultModalPosition | T>; type ModalTransitionOptions = Omit<ModalTransitionProps, "transitionDuration">; type ModalConfirmType = string | boolean; type ModalActionState = "initial" | "pending" | "success" | "error" | "final"; interface ComponentPropsOptions { title?: ReactNode; subTitle?: ReactNode; content?: ReactNode; subContent?: ReactNode; confirmContent?: ReactNode; cancelContent?: ReactNode; customActionContent?: ReactNode; } interface ModalComponentProps<T = any> extends ComponentPropsOptions { action: (confirm?: string | boolean) => void; actionState: ModalActionState; currentPosition: string; lifecycleState: ModalLifecycleState; payload?: T; } type ModalComponent<T = any> = FC<ModalComponentProps<T>>; interface ModalState { component: ModalComponent; isOpened: boolean; isActive: boolean; actionState: ModalActionState; modalClassName?: string; modalStyle: CSSProperties; backCoverStyle: CSSProperties; componentProps: ModalComponentProps; isEscKeyActive: boolean; label: string; role: string; disableFocusHandling: boolean; } interface ModalProps { id: number; modalKey: string | null; name: string; component: ModalComponent; options: ModalOptions<any>; } declare class Modal$1 { private manager; private lifecycleState; private actionState; private actionCallback; private afterCloseCallback; private listeners; private breakPoint; private isInitial; private stateResponsive; private initialComponent; private currentComponent; private componentProps; private escKeyActive; private role; private label; private isOpened; private isPostOpened; private _id; private _modalKey; private _name; private _options; private _isCurrent; private _isAwaitingConfirm; private _isCloseDelay; private _closeDelayDuration; private _confirm; private _onOpenAutoFocus; private _state; private _currentPosition; private _disableFocusHandling; componentRef: HTMLDivElement | null; constructor({ id, modalKey, name, component, options }: ModalProps, manager: ModalManagerInterface); private bind; private setOption; private initComponent; get id(): number; get options(): ModalOptions<any, string>; get modalKey(): string | null; get name(): string; get component(): ModalComponent; get confirm(): ModalConfirmType | undefined; get isCurrent(): boolean; get isAwaitingConfirm(): boolean; get isCloseDelay(): boolean; get closeDelayDuration(): number; get callback(): ModalCallback; get onOpenAutoFocus(): FocusEventHandler<HTMLDivElement> | undefined; get state(): ModalState; get currentPosition(): string; private setComponentProps; /** * TO-DO * modal에서는 그냥 바꾸는 로직만 있고 modalManager에서 처리할 것. */ private changeComponent; private changeStateResponsiveComponent; private changeState; edit({ component, ...contents }: Omit<ModalEditOptions, 'zIndex'>): void; getActionState(): ModalActionState; getLifecycleState(): ModalLifecycleState; init(): Promise<void>; postOpen(callback?: () => void): void; active(): void; close(): Promise<boolean>; blockCloseDelay(): this; setCloseDelay(duration?: number): this; updateIsCurrent(isCurrent: boolean): this; getState(): ModalState; subscribe(listener: (state: ModalState) => void): this; unsubscribe(listener: (state: ModalState) => void): this; notify(): this; getMiddlewareProps(): ModalMiddlewareProps; action(confirm?: ModalConfirmType, callback?: ModalCallback): Promise<boolean>; initial(): this; pending(message?: string | Omit<StateControllerOptions, "afterCloseCallback" | "isAwaitingConfirm">): this; success(message?: string | StateControllerOptions | ((confirm?: ModalConfirmType) => void)): this; error(message?: string | StateControllerOptions | ((confirm?: ModalConfirmType) => void)): this; end(message?: string | Omit<StateControllerOptions, "component"> | ((confirm?: ModalConfirmType) => void)): this; getModalStyle(): { className?: string; style: CSSProperties; }; getBackCoverStyle(): CSSProperties; setBreakPoint(breakPoint: number): void; } interface StateControllerOptions { afterCloseCallback?: (confirm?: ModalConfirmType) => void; isAwaitingConfirm?: boolean; component?: string | ModalComponent; options?: ComponentPropsOptions; } interface StateController { initial: () => void; pending: (message?: string | Omit<StateControllerOptions, "afterCloseCallback" | "isAwaitingConfirm">) => void; success: (message?: string | StateControllerOptions | ((confirm?: ModalConfirmType) => unknown)) => void; error: (message?: string | StateControllerOptions | ((confirm?: ModalConfirmType) => unknown)) => void; end: (message?: string | StateControllerOptions | ((confirm?: ModalConfirmType) => unknown)) => void; getLifecycleState: () => ModalLifecycleState; getActionState: () => ModalActionState; } interface ModalMiddlewareProps { modalState: Modal$1; } type ModalMiddleware = (props: ModalMiddlewareProps) => Promise<boolean>; type ModalCallback = (confirm: ModalConfirmType | undefined, stateController: StateController) => any | Promise<any>; type ModalTransactionState = "idle" | "standby" | "active"; interface ModalManagerState { modalStack: Modal$1[]; breakPoint: number; isOpen: boolean; transactionState: ModalTransactionState; currentModalId: number; zIndex: number; } type ModalListener = (state: ModalManagerState) => void; type ReservedModalName = "clear" | "unknown" | "open" | "close" | "edit" | "remove" | "action"; type ModalRemovedName = ReservedModalName | string | string[]; interface ModalManagerOptionsProps<T extends ModalPositionTable = ModalPositionTable> { position?: T; transition?: ModalTransitionOptions; duration?: number; backCoverColor?: string; backCoverOpacity?: number; stateResponsiveComponent?: boolean; zIndex?: number; } type CloseModalProps = ModalRemovedName | number | [number, ModalRemovedName]; /** * modalKey는 중복 방지 */ interface ModalDispatchOptions<T = any, P extends string = string> extends ComponentPropsOptions { modalKey?: string; action?: ModalCallback; middleware?: ModalMiddleware; backCoverConfirm?: ModalConfirmType | null; backCoverColor?: string; backCoverOpacity?: number; escKeyActive?: boolean; payload?: T; closeDelay?: number; duration?: number; transitionOptions?: ModalTransitionOptions; position?: ModalPosition<P>; stateResponsiveComponent?: boolean; role?: string; label?: string; onOpenAutoFocus?: FocusEventHandler<HTMLDivElement>; zIndex?: number; disableFocusHandling?: boolean; required?: boolean; } type ModalClose = (callback?: (confirm?: ModalConfirmType) => void, confirm?: ModalConfirmType) => Promise<boolean>; interface ModalOptions<T = any, P extends string = string> extends ModalDispatchOptions<T, P> { closeModal: ModalClose; middleware: ModalMiddleware; } interface ModalEditOptions<T extends string = string> extends ComponentPropsOptions { component?: ModalComponent; action?: ModalCallback; backCoverConfirm?: ModalConfirmType | null; backCoverColor?: string; backCoverOpacity?: number; escKeyActive?: boolean; closeDelay?: number; duration?: number; transitionOptions?: ModalTransitionOptions; position?: ModalPosition<T>; stateResponsiveComponent?: boolean; payload?: any; onOpenAutoFocus?: FocusEventHandler<HTMLDivElement>; zIndex?: number; } interface ModalComponentSeed<T extends any = any, P extends string = string> { name: string; component: ModalComponent; defaultOptions?: ModalDispatchOptions<T, P>; } interface ModalSeed<T extends ModalDispatchOptions = ModalOptions> { id: number; modalKey: string | null; name: string; component: ModalComponent<any>; options: T; } type ModalMeta<T, P extends string = DefaultModalPosition> = { component: ModalComponent<T>; defaultOptions?: ModalDispatchOptions<T, P>; }; type ModalComponentSeedTable<T extends string = string, P extends string = string> = { [name in T]: ModalMeta<any, P>; }; interface ModalManagerInterface { getTransactionState: () => ModalTransactionState; getCurrentModalPosition: (positionState: ModalLifecycleState, position?: string) => [PositionStyle, string]; getModalTransition: (duration?: number, options?: ModalTransitionOptions) => ModalTransition; getModalComponentSeed: (name: string) => ModalComponentSeed | undefined; executeAsync: <F = any, P = any>(asyncCallback: (props: P) => Promise<F>, asyncCallbackProps: P) => Promise<F>; executeWithTransaction: <T = any>(asyncCallback: (props: T) => Promise<boolean>, asyncCallbackProps: T) => Promise<boolean>; } type Controller<T extends ModalComponentSeedTable, P extends ModalPositionTable> = { [K in keyof T]: (options?: (T[K]["defaultOptions"] extends { payload: infer R; } ? Omit<ModalDispatchOptions<R, Exclude<Extract<keyof P, string>, "backCover" | "default">>, "required"> : Omit<ModalDispatchOptions<any, Exclude<Extract<keyof P, string>, "backCover" | "default">>, "required">) | ModalCallback | string) => number; }; type ModalController<T extends ModalComponentSeedTable, P extends ModalPositionTable> = { open: <K = any>(name: string | ModalComponent | ReactElement, options?: Omit<ModalDispatchOptions<K, Exclude<Extract<keyof P, string>, "backCover" | "default">>, "required"> | ModalCallback | string) => number; remove: (closeTarget?: CloseModalProps) => number; action: (targetModalId: number, confirm?: boolean | string) => Promise<boolean>; } & Controller<T, P>; declare class ModalManager<T extends ModalPositionTable = ModalPositionTable> implements ModalManagerInterface { private currentId; private transactionCount; private transactionState; private modalStack; private listeners; private modalComponentSeedMap; private modalPositionMap; private modalTransition; private modalDuration; private stateResponsiveComponent; private breakPoint; private originZindex; private zIndex; private modalManagerState; constructor(baseModalComponentSeed?: ModalComponentSeed[], options?: ModalManagerOptionsProps<T>); private bind; initModalOptions(optionsProps: ModalManagerOptionsProps<T>): void; private setModalManagerState; private setModalComponentSeedMap; setZIndex(zIndex?: number): void; resetZIndex(): void; setModalComponent(componentSeed: ModalComponentSeed | ModalComponentSeed[]): this; removeModalComponent(name: string | string[]): this; getModalComponentSeed(name: string): ModalComponentSeed<any, string> | undefined; private createModalCloser; setModalTransition(transitionProps?: ModalTransitionProps): this; setModalDuration(duration?: number): this; setModalPosition(modalPositionTable: ModalPositionTable): this; setModalOptions<P extends ModalPositionTable = ModalPositionTable>(optionsProps: ModalManagerOptionsProps<T & P>): void; getModalTransition(duration?: number, options?: ModalTransitionOptions): ModalTransition; getModalPosition(key?: string): ModalPositionStyle; getModalPositionMap(): ModalPositionMap; getCurrentModalPosition(positionState: ModalLifecycleState, position?: string): [PositionStyle, string]; setTransactionState(transactionState: ModalTransactionState): number; startTransaction(): number; endTransaction(): number; getTransactionState(): ModalTransactionState; executeAsync<F = any, P = any>(asyncCallback: (props: P) => Promise<F>, asyncCallbackProps: P): Promise<F>; executeWithTransaction<T = any>(callback: (props: T) => Promise<boolean>, callbackProps: T): Promise<boolean>; subscribe(listener: ModalListener): this; unsubscribe(listener: ModalListener): void; notify(): void; getState(): ModalManagerState; getModalStack(): Modal$1[]; private createModal; filterModalByName(name: string | string[]): this; pushModal(modalSeed: ModalSeed<ModalDispatchOptions> | ModalSeed<ModalDispatchOptions>[]): void; popModal(removedName?: ModalRemovedName): this; clearModalStack(): this; getCurrentModalId(): number; /** * action이 실행되지 않으면 false * 성공적으로 실행되면 true; * @param targetModalId * @param confirm * @returns */ action(targetModalId?: number, confirm?: ModalConfirmType): Promise<boolean>; /** * @param name * @param options * @returns 현재 등록된 모달의 id를 반환합니다. 만약 등록되지 않은 모달이라면 0을 반환합니다. */ open<P = any>(name: string | ModalComponent | ReactElement, action?: Omit<ModalDispatchOptions<P, Extract<keyof T, string>>, "required"> | ModalCallback | string): number; /** * @param closeTarget * @returns 마지막으로 등록된 모달의 id를 반환합니다. 만약 등록된 모달이 없다면 0을 반환합니다. */ remove(closeTarget?: CloseModalProps): number; edit(id: number, options: ModalEditOptions<Extract<keyof T, string>>): boolean; setBreakPoint(breakPoint: number): void; } interface ModalProviderProps { disableInteraction?: boolean; children?: ReactNode; } interface ModalActionProps extends ButtonHTMLAttributes<HTMLButtonElement> { confirmType?: ModalConfirmType; } interface ModalCustomActionProps extends ButtonHTMLAttributes<HTMLButtonElement> { confirmType: ModalConfirmType; } interface DynamicModalTriggerProps extends ButtonHTMLAttributes<HTMLButtonElement> { } interface DynamicModalElementProps { children: ReactElement; } interface DynamicModalProps<T extends string> extends ModalDispatchOptions<any, T> { children: ReactNode; } type AsProp<T extends ElementType> = { as?: T; children?: ReactNode; }; type PolymorphicComponentPropsWithoutRef<T extends ElementType> = AsProp<T> & ComponentPropsWithoutRef<T>; type ModalContentElement = "div" | "p" | typeof Fragment; type ModalTitleElement = "div" | "h1" | "h2" | "h3" | "h4" | typeof Fragment; declare const Modal: { Title: { <T extends ModalTitleElement = "h2">({ as, children, ...restProps }: PolymorphicComponentPropsWithoutRef<T>): JSX.Element | null; displayName: string; Sub: { <T_1 extends ModalTitleElement = "h3">({ as, children, ...restProps }: PolymorphicComponentPropsWithoutRef<T_1>): JSX.Element | null; displayNmae: string; }; }; Content: { <T_2 extends ModalContentElement = "div">({ as, children, ...restProps }: PolymorphicComponentPropsWithoutRef<T_2>): JSX.Element | null; displayName: string; Sub: { <T_3 extends ModalContentElement = "div">({ as, children, ...restProps }: PolymorphicComponentPropsWithoutRef<T_3>): JSX.Element | null; displayName: string; }; }; Action: { ({ onClick, children, confirmType, ...restProps }: ModalActionProps): JSX.Element | null; displayName: string; Confirm: react.ForwardRefExoticComponent<react.ButtonHTMLAttributes<HTMLButtonElement> & react.RefAttributes<HTMLButtonElement>>; Cancel: react.ForwardRefExoticComponent<react.ButtonHTMLAttributes<HTMLButtonElement> & react.RefAttributes<HTMLButtonElement>>; Custom: react.ForwardRefExoticComponent<ModalCustomActionProps & react.RefAttributes<HTMLButtonElement>>; }; }; declare const modalCollection: { confirm: { component: ModalComponent; defaultOptions: { backCoverConfirm: boolean; escKeyActive: boolean; role: string; label: string; }; }; alert: { component: ModalComponent; defaultOptions: { backCoverConfirm: boolean; escKeyActive: boolean; role: string; label: string; }; }; prompt: { component: ModalComponent; defaultOptions: { backCoverConfirm: undefined; escKeyActive: boolean; role: string; label: string; }; }; }; interface TemplateProps { children: ReactNode; } interface ModalTemplateProps extends TemplateProps { className?: string; } declare const ModalTemplate: { ({ className, children }: ModalTemplateProps): JSX.Element; Header: { ({ children }: TemplateProps): JSX.Element; displayName: string; }; Main: { ({ children }: TemplateProps): JSX.Element; displayName: string; }; Footer: { ({ children }: TemplateProps): JSX.Element; displayName: string; }; }; type ExtractPositionType<T extends ModalManagerOptionsProps> = T extends { position?: infer R; } ? R : ModalPositionTable<DefaultModalPosition>; declare function generateModal<T extends ModalComponentSeedTable<string, Extract<keyof ExtractPositionType<P>, string>>, P extends ModalManagerOptionsProps = ModalManagerOptionsProps<ModalPositionTable<DefaultModalPosition>>>(modalComponentSeedTable?: T, options?: P): { modalManager: ModalManager<ModalPositionTable>; modalCtrl: ModalController<T, ExtractPositionType<P>>; ModalProvider: (props: ModalProviderProps) => JSX.Element; DynamicModal: { ({ children, ...options }: DynamicModalProps<Extract<keyof ExtractPositionType<P>, string>>): JSX.Element; displayName: string; Trigger: { ({ onClick, ...restProps }: DynamicModalTriggerProps): JSX.Element; displayName: string; }; Element: { ({ children }: DynamicModalElementProps): null; displayName: string; }; Action: { ({ onClick, children, confirmType, ...restProps }: ModalActionProps): JSX.Element | null; displayName: string; Confirm: react.ForwardRefExoticComponent<react.ButtonHTMLAttributes<HTMLButtonElement> & react.RefAttributes<HTMLButtonElement>>; Cancel: react.ForwardRefExoticComponent<react.ButtonHTMLAttributes<HTMLButtonElement> & react.RefAttributes<HTMLButtonElement>>; Custom: react.ForwardRefExoticComponent<ModalCustomActionProps & react.RefAttributes<HTMLButtonElement>>; }; }; useIsOpenModal: () => boolean; }; export { Modal, ModalCallback, ModalComponentSeed, ModalConfirmType, ModalComponent as ModalFC, ModalOptions, ModalTemplate, generateModal, modalCollection };