'use client'; import React from 'react'; import type { ModalRef, ModalModalOptions, ModalRefDynamic } from './types/modal'; import type { CreateRefComponentOptions, } from './types/refComponentMount'; import type { UrlListenerAdapter } from './types/urlListener'; import { getUrlListener } from './url'; import { getRefComponentMountAdapter, isDefaultDomMountAdapter, createImperativeMountEnvironmentError, } from './core/refComponentMountRegistry'; export type { CreateRefComponentOptions, RefComponentMountAdapter } from './types/refComponentMount'; /** * 命令式挂载带 ref 的 React 组件。 * @param RefComponent - 转发 ref 的组件,ref 类型应为 ModalRef * @param props - 组件 props * @param options - 容器与生命周期选项; * 可通过 mountAdapter 或 mergeNativeAdapter / mergeRefComponentMount 注入非 DOM 实现 * @returns ref 实例与 destroy 方法 */ function createRefComponent< M extends ModalRef, P extends Record = Record, >( RefComponent: React.ForwardRefExoticComponent

>, props?: React.PropsWithoutRef

| null, options: CreateRefComponentOptions = {}, ): Promise<[ref: M, destroy: () => void]> { const { mountAdapter, ...restOptions } = options; if (isDefaultDomMountAdapter(mountAdapter) && typeof document === 'undefined') { return Promise.reject(createImperativeMountEnvironmentError('createRefComponent')); } return getRefComponentMountAdapter(mountAdapter).mount({ RefComponent, props, options: restOptions, }); } /** * 命令式打开 ref 弹窗并等待结果。 * @param RefModal - 弹窗组件 * @param modalData - 打开时传入的数据 * @param options - 挂载与 modal 选项 * @returns 弹窗结果 Promise */ function showRefModal< M extends ModalRef, D extends M extends ModalRef ? TD extends Record ? TD : Record : Record, U extends M extends ModalRef ? TU : any, P extends Record = Record, >( RefModal: React.ForwardRefExoticComponent

>, modalData?: D, options: CreateRefComponentOptions & { props?: Record, cancelMethod?: string, modalMethod?: string, modalOptions?: ModalModalOptions closeWhenUrlChange?: boolean, /** 单次覆盖全局 URL 监听器适配器(如 React Navigation) */ urlListenerAdapter?: UrlListenerAdapter, } = {}, ): Promise { const { modalMethod = 'modal', props, modalOptions, closeWhenUrlChange, cancelMethod = 'cancelModal', mountAdapter, urlListenerAdapter, ...restOptions } = options; if (isDefaultDomMountAdapter(mountAdapter) && typeof document === 'undefined') { return Promise.reject(createImperativeMountEnvironmentError('showRefModal')); } return new Promise((resolve, reject) => { createRefComponent( RefModal, props as React.PropsWithoutRef

| null | undefined, { ...restOptions, mountAdapter }, ).then(([ref, destroy]) => { const dynRef = ref as ModalRefDynamic; let unwatch: () => void | undefined; if (closeWhenUrlChange) { unwatch = getUrlListener(urlListenerAdapter).addListener( () => dynRef[cancelMethod](), { once: true }, ); } dynRef[modalMethod](modalData || {}, modalOptions).then((result: any) => { destroy(); unwatch?.(); resolve(result); }).catch((error: any) => { destroy(); unwatch?.(); reject(error); }); }).catch(reject); }); } export { createRefComponent, showRefModal, };