feat(overlays): add managed overlay package

This commit is contained in:
Maofeng
2026-09-28 23:13:44 +08:00
parent bca874fd30
commit 0ec968c344
34 changed files with 2340 additions and 0 deletions
@@ -0,0 +1,136 @@
---
title: 安装与基础交互
description: 按需挂载原子 Host,并使用全局或局部 Scope 打开浮层。
order: 10
toc:
- id: atomic-hosts
title: 原子 Host
- id: global-scope
title: 默认全局 Scope
- id: local-scopes
title: 局部和命名局部
- id: message-overlays
title: 消息类浮层
- id: toast
title: Toast
---
## 原子 Host {#atomic-hosts}
在应用样式入口导入 Tailwind source:
```css
@import "@workspace/overlays/globals.css";
```
只挂载应用实际使用的 Host。下面的应用不会引入 Sheet、Drawer 或 Toast:
```tsx
import { AlertHost } from "@workspace/overlays/alert"
import { ConfirmHost } from "@workspace/overlays/confirm"
import { ModalHost } from "@workspace/overlays/modal"
export function Root({ children }: { children: React.ReactNode }) {
return (
<>
{children}
<AlertHost />
<ConfirmHost />
<ModalHost />
</>
)
}
```
确定会使用全部能力的应用也可以从 `@workspace/overlays/all` 导入便捷的 `OverlayHost`。它会主动引入所有 feature,因此不是默认推荐方式。
## 默认全局 Scope {#global-scope}
`openXxx()` 和没有 `scope` prop 的 Host 默认使用 `globalOverlayScope`。调用方不需要 React Context:
```tsx
import { openAlert } from "@workspace/overlays/alert"
await openAlert({
title: "导出完成",
description: "文件已经可以下载。",
})
```
应用仍需挂载对应的 `AlertHost`。打开请求可以发生在 Host 挂载之前,Base UI handle 会在 Host 出现后渲染它。
## 局部和命名局部 {#local-scopes}
Scope 是实际对象,不使用全局字符串注册表:
```tsx
import {
createOverlayScope,
OverlayScopeProvider,
useOverlayScope,
} from "@workspace/overlays"
import { ModalHost, openModal } from "@workspace/overlays/modal"
const editorScope = createOverlayScope({ name: "editor" })
const pickerScope = createOverlayScope({ name: "picker" })
function EditorRoot({ children }: { children: React.ReactNode }) {
return (
<OverlayScopeProvider scope={editorScope} scopes={{ picker: pickerScope }}>
{children}
<ModalHost />
<ModalHost scope={pickerScope} />
</OverlayScopeProvider>
)
}
function OpenPickerButton() {
const scope = useOverlayScope("picker")
return (
<button
onClick={() =>
openModal({ scope, title: "选择资源", content: <AssetPicker /> })
}
>
选择资源
</button>
)
}
```
`<OverlayScopeProvider name="editor">` 可以自动创建一个局部 Scope。非 React 模块应保存并显式传递 `createOverlayScope()` 返回的对象。
## 消息类浮层 {#message-overlays}
```tsx
import { openConfirm } from "@workspace/overlays/confirm"
async function removeProject() {
const accepted = await openConfirm({
title: "删除项目?",
description: "此操作无法撤销。",
destructive: true,
})
if (accepted) await deleteProject()
}
```
`openAlert()` 返回 `Promise<void>`;`openConfirm()` 返回布尔值;`openPrompt()` 返回字符串,并在取消时返回 `null`。
## Toast {#toast}
```tsx
import { dismissToast, openToast, updateToast } from "@workspace/overlays/toast"
const id = openToast({
title: "保存成功",
description: "修改已经同步。",
type: "success",
})
updateToast(id, { description: "所有设备均已同步。" })
dismissToast({ id })
```
Toast 同样按 Scope 隔离,并由对应的 `ToastHost` 渲染。