export function FormDialog()

in packages/element/src/form-dialog/index.ts [91:391]


export function FormDialog(
  title: DialogTitle,
  id: string,
  content: FormDialogContent
): IFormDialog

export function FormDialog(
  title: IFormDialogProps | DialogTitle,
  id: string | symbol | FormDialogContent,
  content?: FormDialogContent
): IFormDialog {
  if (isFn(id) || isValidElement(id)) {
    content = id as FormDialogContent
    id = 'form-dialog'
  }

  const prefixCls = `${stylePrefix}-form-dialog`
  const env = {
    root: document.createElement('div'),
    form: null,
    promise: null,
    instance: null,
    openMiddlewares: [],
    confirmMiddlewares: [],
    cancelMiddlewares: [],
  }

  document.body.appendChild(env.root)

  const props = getDialogProps(title)
  const dialogProps = {
    ...props,
    onClosed: () => {
      props.onClosed?.()
      env.instance.$destroy()
      env.instance = null
      env.root?.parentNode?.removeChild(env.root)
      env.root = undefined
    },
  }

  const component = observer(
    defineComponent({
      setup() {
        return () =>
          h(
            Fragment,
            {},
            {
              default: () =>
                resolveComponent(content, {
                  form: env.form,
                }),
            }
          )
      },
    })
  )

  const render = (visible = true, resolve?: () => any, reject?: () => any) => {
    if (!env.instance) {
      const ComponentConstructor = observer(
        Vue.extend({
          props: ['dialogProps'],
          data() {
            return {
              visible: false,
            }
          },
          render() {
            const {
              onClose,
              onClosed,
              onOpen,
              onOpened,
              onOK,
              onCancel,
              title,
              footer,
              okText,
              cancelText,
              okButtonProps,
              cancelButtonProps,
              ...dialogProps
            } = this.dialogProps

            return h(
              FormProvider,
              {
                props: {
                  form: env.form,
                },
              },
              {
                default: () =>
                  h(
                    Dialog,
                    {
                      class: [`${prefixCls}`],
                      attrs: {
                        visible: this.visible,
                        ...dialogProps,
                      },
                      on: {
                        'update:visible': (val) => {
                          this.visible = val
                        },
                        close: () => {
                          onClose?.()
                        },

                        closed: () => {
                          onClosed?.()
                        },
                        open: () => {
                          onOpen?.()
                        },
                        opened: () => {
                          onOpened?.()
                        },
                      },
                    },
                    {
                      default: () => [h(component, {}, {})],
                      title: () =>
                        h(
                          'div',
                          {},
                          { default: () => resolveComponent(title) }
                        ),
                      footer: () =>
                        h(
                          'div',
                          {},
                          {
                            default: () => {
                              const FooterProtalTarget = h(
                                PortalTarget,
                                {
                                  props: {
                                    name: PORTAL_TARGET_NAME,
                                    slim: true,
                                  },
                                },
                                {}
                              )
                              if (footer === null) {
                                return [null, FooterProtalTarget]
                              } else if (footer) {
                                return [
                                  resolveComponent(footer),
                                  FooterProtalTarget,
                                ]
                              }

                              return [
                                h(
                                  Button,
                                  {
                                    attrs: {
                                      ...cancelButtonProps
                                    },
                                    on: {
                                      click: (e) => {
                                        onCancel?.(e)
                                        reject()
                                      },
                                    },
                                  },
                                  {
                                    default: () =>
                                      resolveComponent(
                                        cancelText ||
                                          t('el.popconfirm.cancelButtonText')
                                      ),
                                  }
                                ),

                                h(
                                  Button,
                                  {
                                    attrs: {
                                      type: 'primary',
                                      ...okButtonProps,
                                      loading: env.form.submitting,
                                    },
                                    on: {
                                      click: (e) => {
                                        onOK?.(e)
                                        resolve()
                                      },
                                    },
                                  },
                                  {
                                    default: () =>
                                      resolveComponent(
                                        okText ||
                                          t('el.popconfirm.confirmButtonText')
                                      ),
                                  }
                                ),
                                FooterProtalTarget,
                              ]
                            },
                          }
                        ),
                    }
                  ),
              }
            )
          },
        })
      )
      env.instance = new ComponentConstructor({
        propsData: {
          dialogProps,
        },
        parent: getProtalContext(id as string | symbol),
      })
      env.instance.$mount(env.root)
      env.root = env.instance.$el
    }

    env.instance.visible = visible
  }

  const formDialog = {
    forOpen: (middleware: IMiddleware<IFormProps>) => {
      if (isFn(middleware)) {
        env.openMiddlewares.push(middleware)
      }
      return formDialog
    },
    forConfirm: (middleware: IMiddleware<Form>) => {
      if (isFn(middleware)) {
        env.confirmMiddlewares.push(middleware)
      }
      return formDialog
    },
    forCancel: (middleware: IMiddleware<Form>) => {
      if (isFn(middleware)) {
        env.cancelMiddlewares.push(middleware)
      }
      return formDialog
    },
    open: (props: IFormProps) => {
      if (env.promise) return env.promise

      env.promise = new Promise(async (resolve, reject) => {
        try {
          props = await loading(dialogProps.loadingText, () =>
            applyMiddleware(props, env.openMiddlewares)
          )
          env.form = env.form || createForm(props)
        } catch (e) {
          reject(e)
        }

        render(
          true,
          () => {
            env.form
              .submit(async () => {
                await applyMiddleware(env.form, env.confirmMiddlewares)
                resolve(toJS(env.form.values))
                if (dialogProps.beforeClose) {
                  setTimeout(() => {
                    dialogProps.beforeClose(() => {
                      formDialog.close()
                    })
                  })
                } else {
                  formDialog.close()
                }
              })
              .catch(() => {})
          },
          async () => {
            await loading(dialogProps.loadingText, () =>
              applyMiddleware(env.form, env.cancelMiddlewares)
            )

            if (dialogProps.beforeClose) {
              dialogProps.beforeClose(() => {
                formDialog.close()
              })
            } else {
              formDialog.close()
            }
          }
        )
      })
      return env.promise
    },
    close: () => {
      if (!env.root) return
      render(false)
    },
  }
  return formDialog
}