mcpField
M
modal

modal

github.com/lobehub开发83.6k4.2k 次安装今天更新
代码仓库

关于 modal

modal 是一份使用 @lobehub/ui 实现命令式模态框的指南,主要采用 base-ui API。内容涵盖设置、模态框内容、确认对话框、国际化及回调行为,面向相关应用的开发者。

主要功能

  1. 01使用 base-ui 的 createModal 和 confirmModal
  2. 02要求挂载全局 ModalHost
  3. 03说明模态框内容与调用方式
  4. 04记录关闭回调行为
  5. 05介绍国际化与常用选项

适用场景

  1. 01在应用中添加命令式模态框
  2. 02配置模态框关闭后的清理逻辑
  3. 03创建确认对话框
  4. 04将用法迁移到 base-ui

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/lobehub/lobehub --skill modal

安装后在 Claude Code 中输入/modal确认已加载。

详细介绍

Modal 命令式 API 指南

推荐:@lobehub/ui/base-ui

新代码应使用 base-ui 模态框体系(无头原语,而非 antd Modal):

  • 从 @lobehub/ui/base-ui 导入 createModal、confirmModal、ModalHost
  • 在模态框内容中从 @lobehub/ui/base-ui 导入 useModalContext

主体插槽:传入 content(或 children;运行时使用 content ?? children)。

全局 ModalHost(必需)

Base-ui 的 createModal 通过与根包分开的宿主渲染。应用必须在靠近根节点的位置挂载一次来自 @lobehub/ui/base-ui 的 ModalHost(例如,与其他全局宿主并列)。若没有它,createModal 调用将不会显示。

如果项目只挂载了来自 @lobehub/ui 的 ModalHost,请额外挂载第二个来自 @lobehub/ui/base-ui 的懒加载 ModalHost,直到所有命令式模态框完成迁移。

为什么使用命令式方式?
模式特点推荐
声明式open 状态 + <Modal />❌
命令式调用 createModal(),无需本地状态✅
文件结构
features/
└── MyFeatureModal/
    ├── index.tsx            # export createXxxModal
    └── MyFeatureContent.tsx # modal body
1. 内容(MyFeatureContent.tsx)
'use client';

import { useModalContext } from '@lobehub/ui/base-ui';
import { useTranslation } from 'react-i18next';

export const MyFeatureContent = () => {
  const { t } = useTranslation('namespace');
  const { close } = useModalContext();

  return <div>{/* ... */}</div>;
};
2. createModal(index.tsx)
'use client';

import { createModal } from '@lobehub/ui/base-ui';
import { t } from 'i18next';

import { MyFeatureContent } from './MyFeatureContent';

export const createMyFeatureModal = () =>
  createModal({
    content: <MyFeatureContent />,
    footer: null,
    maskClosable: true,
    styles: {
      content: { overflow: 'hidden', padding: 0 },
    },
    title: t('myFeature.title', { ns: 'setting' }),
    width: 'min(80%, 800px)',
  });
3. 用法
import { createMyFeatureModal } from '@/features/MyFeatureModal';

const handleOpen = useCallback(() => {
  createMyFeatureModal();
}, []);

return <Button onClick={handleOpen}>Open</Button>;
国际化
  • 内容:在组件中使用 useTranslation。
  • createModal 选项:在无法使用 Hook 的位置,执行 import { t } from 'i18next'。
useModalContext
const { close, setCanDismissByClickOutside } = useModalContext();
关闭时:实际触发的回调

在内容中通过 useModalContext() 调用的 close(),或通过返回的 ModalInstance 调用的 close(),只会将堆栈条目的 open 设为 false。它不会经过 base-ui 的关闭处理流程,因此:

回调用户关闭(Esc / 背景遮罩 / 标题栏 ✕)内容或实例调用 close()
onOpenChange触发不会触发
onOpenChangeComplete以 false 触发以 false 触发

将调用方的清理逻辑(清除编辑标记、重置提供方的 open 状态)放在 onOpenChangeComplete 中。将其绑定到 onOpenChange 看起来没问题,直到页脚按钮关闭模态框时,调用方才会发现它已经关闭——通常会导致标记仍处于设置状态,从而无法重新打开模态框。

createModal 完成时只会传入 false(命令式渲染器会自行提供参数,并且绝不会将该属性转发给 base-ui),但仍应对此进行判断——其他 base-ui 原语(例如 DropdownMenu)会报告两个方向的变化;添加判断可避免调用处依赖这一差异:

onOpenChangeComplete: (open) => {
  if (!open) onClosed?.();
},
常用选项(base-ui)

ImperativeModalProps 基于 BaseModalProps 构建:title、width、maskClosable、open、onOpenChange、footer、styles / classNames(键:backdrop、popup、header、title、close、content、……)。

属性说明
content主体内容(相比 children,优先使用此名称)
maskClosable点击外部区域关闭
styles.*语义区域,而非 antd 的 styles.body
确认框
import { confirmModal } from '@lobehub/ui/base-ui';

confirmModal({
  title: '…',
  content: '…',
  okText: '…',
  cancelText: '…',
  onOk: async () => {},
});

旧版:@lobehub/ui(根包)

根入口 @lobehub/ui 中的 createModal 类型为 antd Modal 属性(children、allowFullscreen、getContainer、destroyOnHidden、styles.body 等)。应用代码已不再导入它;请勿重新引入——应使用 @lobehub/ui/base-ui。


示例

  • Base-ui(首选):遵循以上章节;确保已挂载 base-ui ModalHost。
  • Base-ui 调用位置:src/features/SkillStore/index.tsx、src/features/LibraryModal/CreateNew/index.tsx

评论

支持 Markdown