docs(ui): expand bilingual component guides
This commit is contained in:
@@ -1,30 +1,101 @@
|
||||
---
|
||||
title: 选择组件
|
||||
description: 按职责选择基础组件,而不是导入一个庞大的统一组件入口。
|
||||
title: 组件目录
|
||||
description: 按职责查找组件入口,并理解本地 Base UI 的组合方式。
|
||||
order: 11
|
||||
toc:
|
||||
- id: forms
|
||||
title: 表单与输入
|
||||
- id: overlays
|
||||
title: 浮层与菜单
|
||||
- id: content
|
||||
- id: composition-model
|
||||
title: 组合模型
|
||||
- id: actions-and-forms
|
||||
title: 操作与表单
|
||||
- id: overlays-and-navigation
|
||||
title: 浮层与导航
|
||||
- id: content-and-feedback
|
||||
title: 内容与反馈
|
||||
- id: layout-and-data
|
||||
title: 布局与数据
|
||||
- id: icons
|
||||
title: 图标
|
||||
---
|
||||
|
||||
## 表单与输入 {#forms}
|
||||
## 组合模型 {#composition-model}
|
||||
|
||||
普通表单可使用 `Button`、`Input`、`Textarea`、`Field` 和 `Label`。选择类输入可加入 `Checkbox`、`RadioGroup`、`Switch` 或 `Slider`;更丰富的选择场景可使用 `Select`、`Combobox`、`Command` 或 `Calendar`。
|
||||
组件采用 shadcn/ui 的“复制源码并组合 primitives”模型,但本仓库选择的是 Base UI 实现。组件通常由 Root、Trigger、Content、Item 等部分组成,状态和可访问性由底层 primitive 管理,外观通过 Tailwind class 与 `data-slot` 暴露。
|
||||
|
||||
## 浮层与菜单 {#overlays}
|
||||
Base UI 使用 `render` 组合自定义元素,而不是 Radix 版本常见的 `asChild`:
|
||||
|
||||
`Dialog`、`AlertDialog`、`Sheet` 和 `Drawer` 用于模态界面。`Popover`、`HoverCard` 和 `Tooltip` 用于锚定式信息展示,菜单模块则覆盖上下文菜单、下拉菜单、菜单栏和导航模式。
|
||||
```tsx
|
||||
import { Button } from "@workspace/ui/components/button"
|
||||
import { Dialog, DialogTrigger } from "@workspace/ui/components/dialog"
|
||||
|
||||
## 内容与反馈 {#content}
|
||||
;<Dialog>
|
||||
<DialogTrigger render={<Button variant="outline" />}>编辑资料</DialogTrigger>
|
||||
</Dialog>
|
||||
```
|
||||
|
||||
卡片、列表项、表格、图表、进度条、骨架屏、加载器、空状态、消息和 Toast 构成通用展示词汇。Accordion、Collapsible、Tabs、Carousel 和 Pagination 用于组织更大规模的内容。
|
||||
只在需要替换底层元素时使用 `render`。普通内容直接作为 children 传入。
|
||||
|
||||
## 操作与表单 {#actions-and-forms}
|
||||
|
||||
| 目标 | 组件入口 |
|
||||
| -------------- | -------------------------------------------------- |
|
||||
| 按钮与成组操作 | `button`、`button-group`、`toggle`、`toggle-group` |
|
||||
| 文本输入 | `input`、`textarea`、`input-group`、`input-otp` |
|
||||
| 字段结构 | `field`、`label` |
|
||||
| 布尔与单选 | `checkbox`、`switch`、`radio-group` |
|
||||
| 范围与进度 | `slider`、`progress` |
|
||||
| 选项与命令 | `native-select`、`select`、`combobox`、`command` |
|
||||
| 日期 | `calendar` |
|
||||
|
||||
简单、移动端优先且不需要自定义浮层的选项优先用 `NativeSelect`。需要搜索、多选或自定义项时,分别选择 `Combobox`、`Select` 或 `Command`。
|
||||
|
||||
## 浮层与导航 {#overlays-and-navigation}
|
||||
|
||||
| 目标 | 组件入口 |
|
||||
| -------------- | -------------------------------------------------------- |
|
||||
| 模态确认与编辑 | `alert-dialog`、`dialog`、`sheet`、`drawer` |
|
||||
| 锚定内容 | `popover`、`hover-card`、`tooltip`、`anchored-surface` |
|
||||
| 菜单 | `dropdown-menu`、`context-menu`、`menubar` |
|
||||
| 页面导航 | `breadcrumb`、`navigation-menu`、`pagination`、`sidebar` |
|
||||
|
||||
Dialog、Sheet 与 Drawer 都提供受控状态和组合部件。重要破坏性操作使用 `AlertDialog`,短暂说明使用 `Tooltip`,需要交互控件的锚定面板使用 `Popover`。
|
||||
|
||||
## 内容与反馈 {#content-and-feedback}
|
||||
|
||||
| 目标 | 组件入口 |
|
||||
| ---------- | ----------------------------------------------------- |
|
||||
| 容器与状态 | `card`、`item`、`empty`、`alert`、`badge`、`marker` |
|
||||
| 加载与通知 | `skeleton`、`spinner`、`toast` |
|
||||
| 消息界面 | `message`、`bubble`、`attachment`、`message-scroller` |
|
||||
| 分段内容 | `accordion`、`collapsible`、`tabs`、`carousel` |
|
||||
|
||||
`Message` 负责参与者、对齐和元数据;`Bubble` 负责消息正文表面;`Attachment` 表达上传生命周期;`MessageScroller` 管理自动跟随和回到底部按钮。它们都是展示原语,不拥有会话数据。
|
||||
|
||||
## 布局与数据 {#layout-and-data}
|
||||
|
||||
| 目标 | 组件入口 |
|
||||
| -------- | ------------------------------------------------------- |
|
||||
| 数据展示 | `table`、`chart` |
|
||||
| 布局 | `separator`、`aspect-ratio`、`resizable`、`scroll-area` |
|
||||
| 方向 | `direction` |
|
||||
| 键盘提示 | `kbd` |
|
||||
| 头像 | `avatar` |
|
||||
|
||||
图表模块封装 Recharts 的容器、Tooltip、Legend 与样式映射,不替应用决定数据模型。`DirectionProvider` 直接转发 Base UI 的方向上下文;页面仍应同步设置 HTML 的 `dir` 属性。
|
||||
|
||||
## 图标 {#icons}
|
||||
|
||||
从 `@workspace/ui/components/icon` 导入具名图标。该模块统一了 `@icones/react` 的图标词汇,使应用和各个包使用同一图标来源。
|
||||
从本地 Icones 适配层导入具名图标:
|
||||
|
||||
```tsx
|
||||
import { SearchIcon, SettingsIcon } from "@workspace/ui/components/icon"
|
||||
```
|
||||
|
||||
组件会为没有显式尺寸 class 的 SVG 提供默认尺寸。图标按钮仍要提供可访问名称:
|
||||
|
||||
```tsx
|
||||
<Button size="icon" aria-label="搜索">
|
||||
<SearchIcon aria-hidden="true" />
|
||||
</Button>
|
||||
```
|
||||
|
||||
不要在新组件中重新引入 `lucide-react`;需要新增图标时,在 `components/icon.tsx` 中用 `createIcon` 统一注册。
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
---
|
||||
title: 反馈与消息
|
||||
description: 配置 Toast,并用 Message、Bubble、Attachment 和 MessageScroller 组合消息界面。
|
||||
order: 13
|
||||
toc:
|
||||
- id: toast-provider
|
||||
title: Toast Provider
|
||||
- id: send-toast
|
||||
title: 发送 Toast
|
||||
- id: message-composition
|
||||
title: 消息组合
|
||||
- id: attachments
|
||||
title: 附件状态
|
||||
- id: scrolling
|
||||
title: 消息滚动
|
||||
---
|
||||
|
||||
## Toast Provider {#toast-provider}
|
||||
|
||||
在应用根节点附近挂载一次 `Toaster`:
|
||||
|
||||
```tsx
|
||||
import { Toaster } from "@workspace/ui/components/toast"
|
||||
|
||||
export function App() {
|
||||
return (
|
||||
<>
|
||||
<Routes />
|
||||
<Toaster />
|
||||
</>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
默认 viewport 固定在小屏底部与大屏右下角。Toast 支持堆叠、展开、滑动退出、键盘焦点和 `success`、`info`、`warning`、`error`、`loading` 类型图标。
|
||||
|
||||
## 发送 Toast {#send-toast}
|
||||
|
||||
使用模块导出的 manager:
|
||||
|
||||
```tsx
|
||||
import { Button } from "@workspace/ui/components/button"
|
||||
import { toast } from "@workspace/ui/components/toast"
|
||||
|
||||
;<Button
|
||||
onClick={() =>
|
||||
toast.add({
|
||||
title: "已保存",
|
||||
description: "个人资料已经更新。",
|
||||
type: "success",
|
||||
})
|
||||
}
|
||||
>
|
||||
保存
|
||||
</Button>
|
||||
```
|
||||
|
||||
需要隔离通知区域时,用 `createToastManager()` 创建 manager,并同时传给 `Toaster` 与调用方。关闭按钮的默认可访问名称来自 UI 本地化上下文。
|
||||
|
||||
## 消息组合 {#message-composition}
|
||||
|
||||
```tsx
|
||||
import {
|
||||
Message,
|
||||
MessageContent,
|
||||
MessageFooter,
|
||||
MessageGroup,
|
||||
} from "@workspace/ui/components/message"
|
||||
import { Bubble, BubbleContent } from "@workspace/ui/components/bubble"
|
||||
|
||||
;<MessageGroup>
|
||||
<Message align="end">
|
||||
<MessageContent>
|
||||
<Bubble align="end" variant="tinted">
|
||||
<BubbleContent>明天下午三点可以。</BubbleContent>
|
||||
</Bubble>
|
||||
<MessageFooter>已读 · 14:32</MessageFooter>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
</MessageGroup>
|
||||
```
|
||||
|
||||
把消息 ID、作者、发送状态与操作保留在业务层。UI primitives 只从 props 和 `data-*` 状态决定布局。
|
||||
|
||||
## 附件状态 {#attachments}
|
||||
|
||||
`Attachment` 支持 `idle`、`uploading`、`processing`、`error` 和 `done`。`AttachmentMedia`、`AttachmentTitle`、`AttachmentDescription` 与 `AttachmentActions` 会根据状态调整外观;上传进度和重试逻辑仍由应用负责。
|
||||
|
||||
横向附件使用默认 `orientation="horizontal"`,缩略图网格可使用 `orientation="vertical"`。多个附件放入 `AttachmentGroup` 后会获得横向滚动和 snap 行为。
|
||||
|
||||
## 消息滚动 {#scrolling}
|
||||
|
||||
`MessageScrollerProvider`、`MessageScroller`、`MessageScrollerViewport` 与 `MessageScrollerContent` 应保持层级。每条消息放在 `MessageScrollerItem` 中;需要作为自动跟随目标的项传 `scrollAnchor`。`MessageScrollerButton direction="end"` 会根据当前可滚动状态自动显示或隐藏。
|
||||
|
||||
业务层追加消息时不要直接设置 `scrollTop`。使用这些 primitives 提供的 follow 和 visibility 状态,避免用户向上阅读历史内容时被强制拉回底部。
|
||||
@@ -0,0 +1,113 @@
|
||||
---
|
||||
title: 浮层与定位
|
||||
description: 使用 Base UI 的 render 组合 Dialog、Popover 与本地 AnchoredSurface。
|
||||
order: 12
|
||||
toc:
|
||||
- id: dialog
|
||||
title: Dialog
|
||||
- id: popover
|
||||
title: Popover
|
||||
- id: anchored-surface
|
||||
title: 连续尾巴
|
||||
- id: positioning
|
||||
title: 自定义定位
|
||||
- id: choosing-an-overlay
|
||||
title: 选择浮层
|
||||
---
|
||||
|
||||
## Dialog {#dialog}
|
||||
|
||||
```tsx
|
||||
import { Button } from "@workspace/ui/components/button"
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@workspace/ui/components/dialog"
|
||||
|
||||
export function ProfileDialog() {
|
||||
return (
|
||||
<Dialog>
|
||||
<DialogTrigger render={<Button variant="outline" />}>
|
||||
编辑资料
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>编辑资料</DialogTitle>
|
||||
<DialogDescription>更新公开显示的信息。</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div>表单内容</div>
|
||||
<DialogFooter>
|
||||
<Button type="submit">保存</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
`DialogContent` 已包含 Portal、Overlay 和默认关闭按钮。标题与说明会连接到底层可访问性属性,不要只用无语义的 `div` 替代。
|
||||
|
||||
## Popover {#popover}
|
||||
|
||||
```tsx
|
||||
import { Button } from "@workspace/ui/components/button"
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverDescription,
|
||||
PopoverTitle,
|
||||
PopoverTrigger,
|
||||
} from "@workspace/ui/components/popover"
|
||||
|
||||
;<Popover>
|
||||
<PopoverTrigger render={<Button variant="outline" />}>
|
||||
打开设置
|
||||
</PopoverTrigger>
|
||||
<PopoverContent align="end">
|
||||
<PopoverTitle>显示设置</PopoverTitle>
|
||||
<PopoverDescription>选择列表密度。</PopoverDescription>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
```
|
||||
|
||||
本地 API 继续转发 Base UI Popup 与 Positioner 的 props。需要受控状态时给 `Popover` 传入 `open` 和 `onOpenChange`。
|
||||
|
||||
## 连续尾巴 {#anchored-surface}
|
||||
|
||||
本仓库的 `showArrow` 不是普通三角 SVG。它让 `PopoverContent` 用 `AnchoredSurface` 渲染一个圆角表面与连续曲线尾巴:
|
||||
|
||||
```tsx
|
||||
<PopoverContent
|
||||
side="bottom"
|
||||
showArrow={{ cornerRadius: "2xl", tailSize: "sm" }}
|
||||
className="w-80 p-0"
|
||||
viewportClassName="max-h-72 p-4"
|
||||
>
|
||||
{content}
|
||||
</PopoverContent>
|
||||
```
|
||||
|
||||
外层表面保持 `overflow: visible`,避免尾巴被裁剪;滚动发生在内部 `data-slot="popover-viewport"`。因此要限制内容高度或设置 padding 时,优先使用 `viewportClassName`。
|
||||
|
||||
`AnchoredSurface` 也可以独立使用,但它只负责视觉表面,不负责测量锚点、碰撞检测、焦点或 Portal。
|
||||
|
||||
## 自定义定位 {#positioning}
|
||||
|
||||
`PopoverContent` 额外暴露 `anchor`、`positionMethod`、`arrowPadding`、`alignOffset` 和 `sideOffset`。虚拟锚点或自定义锚点应通过这些参数传给共享组件,不需要绕过它重新拼装 Base UI primitives。
|
||||
|
||||
需要从非 React 代码控制弹层时,可使用 `createPopoverHandle<Payload>()` 创建 handle,再按 Base UI 的 handle 模式传给 Root。
|
||||
|
||||
## 选择浮层 {#choosing-an-overlay}
|
||||
|
||||
- 必须阻止背景交互:`Dialog` 或 `AlertDialog`。
|
||||
- 从屏幕边缘进入的任务面板:`Sheet`;强调触摸拖拽的移动面板:`Drawer`。
|
||||
- 与一个触发点关联的交互内容:`Popover`。
|
||||
- 只在悬停或聚焦时补充预览:`HoverCard`。
|
||||
- 简短、非交互说明:`Tooltip`。
|
||||
|
||||
基础用法可与 [shadcn Popover 文档](https://ui.shadcn.com/docs/components/base/popover)对照;组合语法必须使用 Base UI 版本的 `render`。
|
||||
@@ -1,39 +1,91 @@
|
||||
---
|
||||
title: 项目配置
|
||||
description: 导入全局样式,并从显式组件子路径开始使用。
|
||||
description: 配置 workspace 依赖、全局样式、Tailwind 扫描和 shadcn CLI。
|
||||
order: 10
|
||||
toc:
|
||||
- id: import-styles
|
||||
title: 导入样式
|
||||
- id: import-a-component
|
||||
title: 导入组件
|
||||
- id: entry-points
|
||||
title: 包入口
|
||||
- id: dependency
|
||||
title: 添加依赖
|
||||
- id: global-styles
|
||||
title: 全局样式
|
||||
- id: imports
|
||||
title: 显式导入
|
||||
- id: shadcn-cli
|
||||
title: shadcn CLI
|
||||
- id: browser-components
|
||||
title: 浏览器组件
|
||||
- id: verify
|
||||
title: 验证配置
|
||||
---
|
||||
|
||||
## 导入样式 {#import-styles}
|
||||
## 添加依赖 {#dependency}
|
||||
|
||||
在应用入口中导入一次全局样式:
|
||||
应用通过 workspace 协议引用 UI 包:
|
||||
|
||||
```ts
|
||||
import "@workspace/ui/globals.css"
|
||||
```
|
||||
|
||||
它提供组件所需的共享 Tailwind 层、设计变量、字体配置和工具类。
|
||||
|
||||
## 导入组件 {#import-a-component}
|
||||
|
||||
```tsx
|
||||
import { Button } from "@workspace/ui/components/button"
|
||||
|
||||
export function SaveButton() {
|
||||
return <Button>保存</Button>
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
"@workspace/ui": "workspace:*"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 包入口 {#entry-points}
|
||||
仓库中的应用已经完成此配置。这个 package 当前是私有 workspace package,不需要从 npm 安装。
|
||||
|
||||
- `@workspace/ui/components/*` 导出单个组件模块。
|
||||
- `@workspace/ui/hooks/*` 导出可复用的交互和媒体查询状态。
|
||||
- `@workspace/ui/lib/utils` 导出共享的类名组合工具。
|
||||
- `@workspace/ui/locales/*` 导出指定语言的词典。
|
||||
## 全局样式 {#global-styles}
|
||||
|
||||
在应用的全局 CSS 中导入一次:
|
||||
|
||||
```css
|
||||
@import "@workspace/ui/globals.css";
|
||||
```
|
||||
|
||||
该入口会加载 Tailwind CSS、shadcn 的 Tailwind 扩展、动画工具、Inter Variable 字体、语义颜色、圆角变量和基础样式。主题通过根节点上的 `.ui:light` 与 `.ui:dark` class 切换;组件代码不要自行复制这些变量。
|
||||
|
||||
`globals.css` 中的 `@source` 已覆盖本仓库的 `apps` 与组件目录。如果将 package 移到另一种目录结构,应同步调整扫描路径,否则生产构建可能缺少组件使用的 utility。
|
||||
|
||||
## 显式导入 {#imports}
|
||||
|
||||
package 没有聚合式 barrel。始终从具体子路径导入,便于追踪依赖并避免意外扩大客户端 bundle:
|
||||
|
||||
```tsx
|
||||
import { Button } from "@workspace/ui/components/button"
|
||||
import { SaveIcon } from "@workspace/ui/components/icon"
|
||||
import { useIsMobile } from "@workspace/ui/hooks/use-breakpoint"
|
||||
import { cn } from "@workspace/ui/lib/utils"
|
||||
```
|
||||
|
||||
公开入口包括:
|
||||
|
||||
- `@workspace/ui/components/*`:组件与局部类型。
|
||||
- `@workspace/ui/hooks/*`:断点和波纹交互。
|
||||
- `@workspace/ui/locales`:支持的 locale 与消息 ID 类型。
|
||||
- `@workspace/ui/locales/en-US`、`@workspace/ui/locales/zh-Hans`:消息与日历 locale。
|
||||
- `@workspace/ui/globals.css`:全局样式。
|
||||
|
||||
## shadcn CLI {#shadcn-cli}
|
||||
|
||||
仓库根目录运行:
|
||||
|
||||
```sh
|
||||
bunx shadcn@latest add button -c apps/web
|
||||
```
|
||||
|
||||
应用和 UI package 的 `components.json` 使用同一套 `base-vega`、neutral、CSS variables、Lucide 词汇和 RTL 配置;别名会把生成文件放到 `packages/ui/src/components`。这与 shadcn 官方的 [monorepo 工作流](https://ui.shadcn.com/docs/monorepo)一致。
|
||||
|
||||
CLI 生成完成后必须检查 diff。生成器不知道本仓库的 Icones、国际化、波纹和 Popover 扩展,更新已有组件时可能覆盖本地适配。`components.json` 各字段的含义可参考[官方说明](https://ui.shadcn.com/docs/components-json)。
|
||||
|
||||
## 浏览器组件 {#browser-components}
|
||||
|
||||
多数交互组件依赖事件、Portal 或浏览器 API。使用 React Server Components 的消费端应从自身的客户端边界导入它们。本仓库配置为 `rsc: false`,组件文件不会统一插入框架专用指令;少数组件因自身需要显式包含 `"use client"`。
|
||||
|
||||
## 验证配置 {#verify}
|
||||
|
||||
修改组件或配置后运行:
|
||||
|
||||
```sh
|
||||
bun run --cwd packages/ui typecheck
|
||||
bun run lint
|
||||
bun run format:check
|
||||
```
|
||||
|
||||
如果改动涉及消费方式,再运行应用或文档的构建,确认 Tailwind 能扫描到新 class,并检查浅色、深色与 RTL。
|
||||
|
||||
Reference in New Issue
Block a user