|
@@ -0,0 +1,124 @@
|
|
|
|
|
+import React from 'react'
|
|
|
|
|
+import { ModalContext } from './context'
|
|
|
|
|
+
|
|
|
|
|
+export interface ModalFullConfig<T = any> {
|
|
|
|
|
+ destroyOnClose?: boolean | string
|
|
|
|
|
+ visiblePropName?: string
|
|
|
|
|
+ // onClosePropName?: string
|
|
|
|
|
+ component: React.ComponentType<T>
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+export type ModalConfig<T = any> = ModalFullConfig<T> | React.ComponentType<T>
|
|
|
|
|
+
|
|
|
|
|
+export type ModalConfigMap = Record<string, ModalConfig>
|
|
|
|
|
+
|
|
|
|
|
+export interface ModalStoreProps extends Omit<ModalFullConfig, 'component'> {
|
|
|
|
|
+ children: React.ReactNode
|
|
|
|
|
+ modalMap: ModalConfigMap
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+export interface ModalItem extends Record<string, any> {
|
|
|
|
|
+ key: string
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+export interface ModalStoreState {
|
|
|
|
|
+ currentModal: ModalItem[]
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+class ModalStore extends React.Component<ModalStoreProps, ModalStoreState> {
|
|
|
|
|
+ constructor(props: ModalStoreProps) {
|
|
|
|
|
+ super(props)
|
|
|
|
|
+ this.state = {
|
|
|
|
|
+ currentModal: []
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 获取modal的config
|
|
|
|
|
+ private getModalConfig(key: string) {
|
|
|
|
|
+ const { modalMap = {}, visiblePropName = 'visible', destroyOnClose = true } = this.props
|
|
|
|
|
+ let config = modalMap[key]
|
|
|
|
|
+ if (typeof config === 'function') config = { component: config }
|
|
|
|
|
+ const onClosePropName = key.startsWith('M') ? 'onCancel' : 'onClose'
|
|
|
|
|
+
|
|
|
|
|
+ return { visiblePropName, onClosePropName, destroyOnClose, config }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private setModalState(fn: (prev: ModalItem[]) => ModalItem[]) {
|
|
|
|
|
+ this.setState(prev => ({ currentModal: fn(prev.currentModal) }))
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private getCloseFunction(key: string, cb?: (...args: any[]) => void) {
|
|
|
|
|
+ return (...args: any[]) => {
|
|
|
|
|
+ const { visiblePropName } = this.getModalConfig(key)
|
|
|
|
|
+ this.setModalState(prev => {
|
|
|
|
|
+ return prev.map(item => {
|
|
|
|
|
+ if (item.key === key) {
|
|
|
|
|
+ return { ...item, [visiblePropName]: false }
|
|
|
|
|
+ }
|
|
|
|
|
+ return item
|
|
|
|
|
+ })
|
|
|
|
|
+ })
|
|
|
|
|
+ if (typeof cb === 'function') {
|
|
|
|
|
+ cb(...args)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private getDestroyFunction(key: string, cb?: (...args: any[]) => void) {
|
|
|
|
|
+ return (...args: any[]) => {
|
|
|
|
|
+ this.setModalState(prev => prev.filter(v => v.key !== key))
|
|
|
|
|
+ if (typeof cb === 'function') {
|
|
|
|
|
+ cb(...args)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private push = (key: string, state: any) => {
|
|
|
|
|
+ const { visiblePropName, onClosePropName, destroyOnClose } = this.getModalConfig(key)
|
|
|
|
|
+
|
|
|
|
|
+ this.setModalState(prevModals => {
|
|
|
|
|
+ const defaultProps: any = {
|
|
|
|
|
+ [visiblePropName]: true,
|
|
|
|
|
+ [onClosePropName]: this.getCloseFunction(key, state[onClosePropName])
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (destroyOnClose) {
|
|
|
|
|
+ const prop = typeof destroyOnClose === 'string' ? destroyOnClose : onClosePropName
|
|
|
|
|
+ defaultProps[prop] = this.getDestroyFunction(key)
|
|
|
|
|
+ }
|
|
|
|
|
+ const newModal = { ...state, ...defaultProps, key }
|
|
|
|
|
+ const nextModals = prevModals.slice()
|
|
|
|
|
+ const index = nextModals.findIndex(item => item.key === key)
|
|
|
|
|
+ if (index !== -1) nextModals.splice(index, 1)
|
|
|
|
|
+ nextModals.push(newModal)
|
|
|
|
|
+
|
|
|
|
|
+ return nextModals
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private renderModal = (item: ModalItem) => {
|
|
|
|
|
+ const { config } = this.getModalConfig(item.key)
|
|
|
|
|
+ if (config) {
|
|
|
|
|
+ // 弹窗
|
|
|
|
|
+ if ('component' in config) {
|
|
|
|
|
+ return React.createElement(config.component, item)
|
|
|
|
|
+ }
|
|
|
|
|
+ // 抽屉
|
|
|
|
|
+ return React.createElement(config, item)
|
|
|
|
|
+ }
|
|
|
|
|
+ return null
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ render() {
|
|
|
|
|
+ const { currentModal } = this.state
|
|
|
|
|
+ const { children } = this.props
|
|
|
|
|
+ return (
|
|
|
|
|
+ <ModalContext.Provider value={this.push}>
|
|
|
|
|
+ {children}
|
|
|
|
|
+ {currentModal.map(this.renderModal)}
|
|
|
|
|
+ </ModalContext.Provider>
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+export default ModalStore
|