全局配置(DesignProvider)
DesignProvider 是 @plaud/design 的一站式入口。在应用根部挂载一次,即可配置组件库所需的全部能力:
- 主题:light / dark,支持受控 / 持久化,并可跟随系统偏好
- 方向:
ltr/rtl,支持 RTL 布局 - 图标注入:必填的
icons注册表(design 不内置任何图标实现) - Overlay 宿主:自动挂载
<OverlayHost />,命令式弹层(Dialog.open()等)开箱即用
它的定位等同于 antd 的 ConfigProvider:一处集中配置整个设计系统。
何时使用
| Provider | 能力 | 适用场景 |
|---|---|---|
DesignProvider | 主题 + 方向 + Overlay 宿主 + 图标注入 | 业务应用入口,一站式 |
IconRegistryProvider | 仅图标注入,不管理主题 / Overlay | 主题由外部托管的场景(如本文档站的 Docusaurus) |
绝大多数应用都应使用 DesignProvider。仅当已有其他系统托管主题与 DOM 属性时,才改用轻量的
IconRegistryProvider——参见图标配置。
基础用法
在应用根部包裹一次。icons 为必填项,需提供一份覆盖全部图标 key 的注册表(契约见图标配置):
import { DesignProvider } from '@plaud/design'
import { icons } from './icons'
export const App = () => (
<DesignProvider icons={icons}>
<YourApp />
</DesignProvider>
)
这一次挂载即会把主题 token 应用到 document.documentElement、注入图标,并让命令式弹层在其下任意位置可用。
主题
DesignProvider 管理 light / dark 主题,并通过切换 <html> 上的 .dark class 与 data-theme
属性把主题反映到文档。实际颜色值来自 @plaud/design-tokens(CSS 变量),provider 只负责“拨开关”。
非受控(默认)
默认情况下主题是非受控的。用 defaultTheme 指定初始值;此后 provider 会持久化用户选择,并在没有存储值时跟随系统偏好:
<DesignProvider icons={icons} defaultTheme="light">
<YourApp />
</DesignProvider>
初始主题的解析顺序:
localStorage中存储的偏好(当persistTheme开启时)defaultTheme- 之后跟随系统偏好(
prefers-color-scheme)——只要用户没有显式选择过主题
受控
传入 theme 即可完全接管。受控模式下 provider 始终渲染该值,忽略 localStorage,也不再跟随系统偏好——状态由你掌控:
const [theme, setTheme] = useState<'light' | 'dark'>('light')
return (
<DesignProvider icons={icons} theme={theme}>
<ThemeToggle onToggle={() => setTheme((t) => (t === 'light' ? 'dark' : 'light'))} />
<YourApp />
</DesignProvider>
)
读取与切换主题 —— useTheme
在 provider 内部,useTheme() 暴露当前主题与切换方法。在 DesignProvider 外部使用会抛错。
import { useTheme } from '@plaud/design'
const ThemeToggle = () => {
const { theme, setTheme, toggleTheme } = useTheme()
return (
<button type="button" onClick={toggleTheme}>
当前主题:{theme}(点击切换)
</button>
)
}
toggleTheme():在 light / dark 之间切换setTheme('dark'):设置指定主题- 非受控模式下二者都会持久化到
localStorage(当persistTheme开启时);受控模式下theme仍由父组件掌控,请改用自己的状态驱动。
方向(RTL)
设置 dir 切换文档方向。provider 会把它写到 <html> 的 dir 属性上,useTheme() 也暴露
dir / setDir 供运行时切换:
<DesignProvider icons={icons} dir="rtl">
<YourApp />
</DesignProvider>
持久化
主题持久化默认开启,localStorage 的 key 为 plaud-design-theme。
// 完全关闭持久化(不读写 localStorage)
<DesignProvider icons={icons} persistTheme={false}>
<YourApp />
</DesignProvider>
// 或保留持久化,但使用自定义 key
<DesignProvider icons={icons} storageKey="my-app-theme">
<YourApp />
</DesignProvider>
默认的 storageKey 刻意保留为 plaud-design-theme,生产应用不建议改动——一旦修改,已上线用户在升级后会丢失主题偏好。
Overlay 宿主
DesignProvider 会在根部自动挂载 <OverlayHost />,因此 Dialog.open() / Drawer.open() 等命令式弹层无需任何额外配置即可渲染。
如果你刻意不使用 DesignProvider(例如只用 IconRegistryProvider),需要自行挂载宿主,命令式弹层才有渲染出口:
import { IconRegistryProvider, OverlayHost } from '@plaud/design'
const Root = ({ children }) => (
<IconRegistryProvider icons={icons}>
{children}
<OverlayHost />
</IconRegistryProvider>
)
详见可组合弹层。
图标注入
icons 为必填项——@plaud/design 不内置任何图标实现,组件用到的每个图标都从这里注入的注册表读取。缺失注册表或某个 key 会在渲染时抛错。契约、完整 key 列表与参考实现见图标配置。
:::info 为什么本文档站用的是 IconRegistryProvider
本 Docusaurus 站点的主题由 Docusaurus 自身托管,所以站点在 src/theme/Root.tsx 中通过轻量的
IconRegistryProvider 注入图标,而不是让 DesignProvider 去管理文档主题。你的业务应用应使用
DesignProvider。
:::
API
DesignProvider Props
| Prop | 类型 | 默认值 | 说明 |
|---|---|---|---|
icons | IconRegistry | — | 必填。 覆盖全部 key 的图标注册表,见图标配置 |
children | React.ReactNode | — | 必填。 应用子树 |
theme | 'light' | 'dark' | - | 受控主题。设置后忽略 localStorage 与系统偏好 |
defaultTheme | 'light' | 'dark' | 'light' | 非受控模式下、且无存储偏好时的初始主题 |
dir | 'ltr' | 'rtl' | 'ltr' | 文档方向,写入 <html dir> |
persistTheme | boolean | true | 是否将主题偏好持久化到 localStorage |
storageKey | string | 'plaud-design-theme' | 持久化使用的 localStorage key |
useTheme() 返回值(ThemeContextValue)
| 字段 | 类型 | 说明 |
|---|---|---|
theme | 'light' | 'dark' | 当前主题 |
setTheme | (theme: ThemeName) => void | 设置指定主题 |
toggleTheme | () => void | 在 light / dark 之间切换 |
dir | 'ltr' | 'rtl' | 当前文档方向 |
setDir | (dir: Direction) => void | 设置文档方向 |