---
url: /guide/components-json.md
---
# components.json 配置
`components.json` 文件用于配置你的项目,使 Codebase Kit 能够理解你的项目设置并生成定制化组件。
:::tip 注意
`components.json` 文件是可选的,**仅在使用 CLI 添加组件时才需要**。如果你使用复制粘贴的方式,则不需要此文件。
:::
## 初始化
你可以使用以下命令在项目中创建 `components.json` 文件:
```sh [npx]
npx shadcn@latest init
```
```sh [yarn]
yarn dlx shadcn@latest init
```
```sh [pnpm]
pnpm dlx shadcn@latest init
```
```sh [bunx]
bunx shadcn@latest init
```
```sh [deno]
deno run npm:shadcn@latest npm:init
```
## $schema
`$schema` 属性用于指定 `components.json` 文件的 JSON Schema。
```json title="components.json"
{
"$schema": "https://ui.shadcn.com/schema.json"
}
```
## style
组件的样式风格。**初始化后无法更改此配置。**
```json title="components.json"
{
"style": "default"
}
```
Codebase Kit 基于 [UnoCSS](https://unocss.dev/) 和 [Ant Design](https://ant.design/) 构建,提供了简洁的默认样式和主题系统。
## framework
指定使用的框架类型。
```json title="components.json"
{
"framework": "react"
}
```
目前 Codebase Kit 支持 React 框架。
## aliases
CLI 使用这些值和 `tsconfig.json` 或 `jsconfig.json` 文件中的 `paths` 配置来确定生成组件的正确位置。
路径别名必须在 `tsconfig.json` 或 `jsconfig.json` 文件中设置。
:::tip 重要
如果你使用 `src` 目录,请确保将其包含在 `tsconfig.json` 或 `jsconfig.json` 文件的 `paths` 下。
:::
### aliases.utils
工具函数的导入别名。
```json title="components.json"
{
"aliases": {
"utils": "@/lib/utils"
}
}
```
### aliases.components
组件的导入别名。
```json title="components.json"
{
"aliases": {
"components": "@/components"
}
}
```
### aliases.ui
`ui` 组件的导入别名。
CLI 将使用 `aliases.ui` 值来确定放置 `ui` 组件的位置。如果你想自定义 `ui` 组件的安装目录,请使用此配置。
```json title="components.json"
{
"aliases": {
"ui": "@/components"
}
}
```
### aliases.lib
`lib` 函数的导入别名,例如 `format-date` 或 `generate-id`。
```json title="components.json"
{
"aliases": {
"lib": "@/lib"
}
}
```
### aliases.hooks
`hooks` 的导入别名,例如 `use-media-query` 或 `use-toast`。
```json title="components.json"
{
"aliases": {
"hooks": "@/hooks"
}
}
```
## registries
为你的项目配置多个资源注册表。这允许你从各种源(包括私有注册表)安装组件、库、工具和其他资源。
### 基础配置
使用 URL 模板配置注册表:
```json title="components.json"
{
"registries": {
"@v0": "https://v0.dev/chat/b/{name}",
"@acme": "https://registry.acme.com/{name}.json",
"@internal": "https://internal.company.com/{name}.json"
}
}
```
`{name}` 占位符将在安装时被资源名称替换。
### 高级配置 - 带身份验证
对于需要身份验证的私有注册表:
```json title="components.json"
{
"registries": {
"@private": {
"url": "https://api.company.com/registry/{name}.json",
"headers": {
"Authorization": "Bearer ${REGISTRY_TOKEN}",
"X-API-Key": "${API_KEY}"
},
"params": {
"version": "latest"
}
}
}
}
```
格式为 `${VAR_NAME}` 的环境变量将从你的环境中自动展开。
### 使用命名空间注册表
配置完成后,使用命名空间语法安装资源:
```bash
# 从配置的注册表安装
npx shadcn@latest add @v0/dashboard
# 从私有注册表安装
npx shadcn@latest add @private/button
# 安装多个资源
npx shadcn@latest add @acme/header @internal/auth-utils
```
### 示例:多注册表设置
```json title="components.json"
{
"registries": {
"@shadcn": "https://ui.shadcn.com/r/{name}.json",
"@company-ui": {
"url": "https://registry.company.com/ui/{name}.json",
"headers": {
"Authorization": "Bearer ${COMPANY_TOKEN}"
}
},
"@team": {
"url": "https://team.company.com/{name}.json",
"params": {
"team": "frontend",
"version": "${REGISTRY_VERSION}"
}
}
}
}
```
此配置允许你:
- 从 shadcn/ui 安装公共组件
- 使用身份验证访问私有公司 UI 组件
- 使用带版本控制的团队特定资源
## 完整示例
以下是一个完整的 `components.json` 配置示例:
```json title="components.json" showLineNumbers
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "default",
"framework": "react",
"aliases": {
"utils": "@/lib/utils",
"components": "@/components",
"ui": "@/components",
"lib": "@/lib",
"hooks": "@/hooks"
},
"registries": {
"@codebase-kit": "https://codebase.anyask.dev/r/{name}.json"
}
}
```
## tsconfig.json 配置
为了使路径别名正常工作,你还需要在 `tsconfig.json` 中配置路径映射:
```json title="tsconfig.json" showLineNumbers
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@/components/*": ["./src/components/*"],
"@/lib/*": ["./src/lib/*"],
"@/hooks/*": ["./src/hooks/*"]
}
}
}
```
---
url: /guide/get-started.md
---
# 快速开始
**这不是一个传统组件库。它是你构建自己组件库的方式。**
你知道大多数传统组件库是如何工作的:从 NPM 安装一个包,导入组件,然后在应用中使用它们。
这种方式在你需要定制组件以适应你的设计系统,或者需要库中没有包含的组件时,就会遇到问题。**你最终不得不包装库组件、编写覆盖样式的工作代码,或者混合使用来自不同库的 API 不兼容的组件。**
这就是 Codebase Kit 要解决的问题。它基于以下原则构建:
- **开放代码:** 组件的顶层代码开放,可修改。
- **可组合性:** 每个组件使用通用、可组合的接口,使它们可预测。
- **易于分发:** 扁平文件模式和命令行工具使组件分发变得简单。
- **精致默认:** 精心选择的默认样式,开箱即用即可获得出色设计。
- **面向 AI:** 开放代码供 LLMs 读取、理解和改进。
## 安装
### 1. 初始化配置
运行以下命令在你的项目中创建 `components.json` 配置文件:
```sh [npm]
npm shadcn@latest init
```
```sh [yarn]
yarn shadcn@latest init
```
```sh [pnpm]
pnpm shadcn@latest init
```
```sh [bun]
bun shadcn@latest init
```
```sh [deno]
deno shadcn@latest npm:init
```
这将引导你完成配置过程,包括:
- 选择样式风格
- 配置路径别名
- 设置 TypeScript 选项
:::tip 提示
详细了解 `components.json` 的所有配置选项,请参阅 [components.json 配置](/guide/components-json.md) 文档。
:::
### 2. 安装组件
配置完成后,你可以使用 CLI 安装组件:
```bash
# 安装单个组件
npx shadcn@latest add https://codebase.anyask.dev/r/button.json
# 安装多个组件
npx shadcn@latest add @xuanyuan/search-form @xuanyuan/descriptions
```
## 开放代码
Codebase Kit 为你提供实际的组件代码。你拥有完全的控制权来定制和扩展组件以满足你的需求。这意味着:
- **完全透明:** 你可以精确地看到每个组件是如何构建的。
- **轻松定制:** 修改组件的任何部分以适应你的设计和功能要求。
- **AI 集成:** 访问代码使 LLMs 能够直接读取、理解甚至改进你的组件。
_在典型的库中,如果你需要更改按钮的行为,你必须覆盖样式或包装组件。使用 Codebase Kit,你只需直接编辑按钮代码。_
## 可组合性
Codebase Kit 中的每个组件都共享一个通用的、可组合的接口。**如果某个组件不存在,我们会引入它,使其可组合,并调整其样式以匹配并与设计系统的其余部分一起工作。**
_共享的可组合接口意味着它对你的团队和 LLMs 都是可预测的。你不会为每个新组件学习不同的 API。即使是第三方组件也是如此。_
## 易于分发
Codebase Kit 也是一个代码分发系统。它定义了组件的模式和用于分发它们的 CLI。
- **模式:** 定义组件、其依赖项和属性的扁平文件结构。
- **CLI:** 用于跨项目分发和安装组件的命令行工具,支持跨框架。
_你可以使用该模式将组件分发到其他项目,或者让 AI 基于现有模式生成全新的组件。_
## 精致默认
Codebase Kit 提供了大量具有精心选择的默认样式的组件。它们的设计本身就很好看,并且作为一个一致的系统协同工作:
- **开箱即用:** 无需额外工作,你的 UI 就拥有简洁的外观。
- **统一设计:** 组件自然地相互配合。每个组件都是为了与其他组件匹配而构建的,保持 UI 的一致性。
- **易于定制:** 如果你想改变什么,覆盖和扩展默认值很简单。
## 面向 AI
Codebase Kit 的设计使 AI 工具能够轻松地与你的代码协作。其开放代码和一致的 API 允许 AI 模型读取、理解甚至生成新组件。
_AI 模型可以学习你的组件如何工作,并提出改进建议,甚至创建与你现有设计集成的新组件。_
---
url: /guide/index.md
---
# Markdown & MDX
Rspress supports not only Markdown but also [MDX](https://mdxjs.com/), a powerful way to develop content.
## Markdown
MDX is a superset of Markdown, which means you can write Markdown files as usual. For example:
```md
# Hello world
```
## Use component
When you want to use React components in Markdown files, you should name your files with `.mdx` extension. For example:
```mdx
// docs/index.mdx
import { CustomComponent } from './custom';
# Hello world
```
## Front matter
You can add Front Matter at the beginning of your Markdown file, which is a YAML-formatted object that defines some metadata. For example:
```yaml
---
title: Hello world
---
```
> Note: By default, Rspress uses h1 headings as html headings.
You can also access properties defined in Front Matter in the body, for example:
```markdown
---
title: Hello world
---
# {frontmatter.title}
```
The previously defined properties will be passed to the component as `frontmatter` properties. So the final output will be:
```html
Hello world
```
## Custom container
You can use the `:::` syntax to create custom containers and support custom titles. For example:
**Input:**
```markdown
:::tip
This is a `block` of type `tip`
:::
:::info
This is a `block` of type `info`
:::
:::warning
This is a `block` of type `warning`
:::
:::danger
This is a `block` of type `danger`
:::
::: details
This is a `block` of type `details`
:::
:::tip Custom Title
This is a `block` of `Custom Title`
:::
:::tip{title="Custom Title"}
This is a `block` of `Custom Title`
:::
```
**Output:**
:::tip
This is a `block` of type `tip`
:::
:::info
This is a `block` of type `info`
:::
:::warning
This is a `block` of type `warning`
:::
:::danger
This is a `block` of type `danger`
:::
::: details
This is a `block` of type `details`
:::
:::tip Custom Title
This is a `block` of `Custom Title`
:::
:::tip\{title="Custom Title"}
This is a `block` of `Custom Title`
:::
## Code block
### Basic usage
You can use the \`\`\` syntax to create code blocks and support custom titles. For example:
**Input:**
````md
```js
console.log('Hello World');
```
```js title="hello.js"
console.log('Hello World');
```
````
**Output:**
```js
console.log('Hello World');
```
```js title="hello.js"
console.log('Hello World');
```
### Show line numbers
If you want to display line numbers, you can enable the `showLineNumbers` option in the config file:
```ts title="rspress.config.ts"
export default {
// ...
markdown: {
showLineNumbers: true,
},
};
```
### Wrap code
If you want to wrap long code line by default, you can enable the `defaultWrapCode` option in the config file:
```ts title="rspress.config.ts"
export default {
// ...
markdown: {
defaultWrapCode: true,
},
};
```
### Line highlighting
You can also apply line highlighting and code block title at the same time, for example:
**Input:**
````md
```js title="hello.js"
console.log('Hello World'); // [\!code highlight]
// [\!code highlight:3]
const a = 1;
console.log(a);
const b = 2;
console.log(b);
```
````
:::warning
The backslash (`\`) in `[\!code highlight]` is for Markdown escaping to display the raw syntax. Do not include it when using this notation in your actual code.
:::
**Output:**
```js title="hello.js"
console.log('Hello World'); // [!code highlight]
// [!code highlight:3]
const a = 1;
console.log(a);
const b = 2;
console.log(b);
```
## Rustify MDX compiler
You can enable Rustify MDX compiler by following config:
---
url: /guide/llms.md
---
# LLMs.txt
本指南介绍如何让 Cursor、Windsurf 和 Claude 等 AI 工具更好地理解 Codebase Kit。
## 什么是 LLMs.txt?
我们支持通过 [LLMs.txt](https://llmstxt.org/) 文件向大语言模型(LLMs)提供 Codebase Kit 文档。此功能可帮助 AI 工具更好地理解我们的组件库、API 及使用模式。
## 可用资源
我们提供多个 LLMs.txt 路由来帮助 AI 工具访问文档:
- [llms.txt](https://codebase.anyask.dev/llms.txt) - 包含所有组件及其文档链接的结构化概览
- [llms-full.txt](https://codebase.anyask.dev/llms-full.txt) - 提供包含实现细节和示例的完整文档
## 在 AI 工具中的使用
### Cursor
在 Cursor 中使用 `@Docs` 功能将 LLMs.txt 文件包含到您的项目中。这有助于 Cursor 为 Codebase Kit 组件提供更准确的代码建议和文档。
[详细了解 Cursor 中的 @Docs 功能](https://docs.cursor.com/zh/context/@-symbols/@-docs)
### Windsurf
通过 `@` 引用或在 `.windsurf/rules` 文件中配置 LLMs.txt 文件,以增强 Windsurf 对 Codebase Kit 组件的理解。
[详细了解 Windsurf Memories 功能](https://docs.windsurf.com/windsurf/cascade/memories)
### Claude Code
在 Claude Code 中,将 `LLMs.txt` 添加到工作区的知识库(Docs / Context Files)配置中,即可在代码补全与解释时引用其中的内容,从而提升对 Codebase Kit 组件的理解。
[详细了解 Claude Code 文档上下文配置](https://code.claude.com/docs)
### Gemini CLI
在 Gemini CLI 中,可以通过 `--context` 参数或在 `.gemini/config.json` 中指定 `LLMs.txt` 文件路径,让 Gemini 在回答和生成代码时参考该文档。
[详细了解 Gemini CLI 上下文配置](https://ai.google.dev/gemini-api/docs?hl=zh-cn)
### Trae
在 Trae 中,将 `LLMs.txt` 文件放入项目的 knowledge sources 并在设置里开启引用,即可让 Trae 在生成或分析代码时更好地支持 Codebase Kit 组件。
[详细了解 Trae 的知识源功能](https://trae.ai/docs)
### Qoder
在 Qoder 中,可以在 `.qoder/config.yml` 中添加 `LLMs.txt` 作为外部知识文件,或在对话中通过 `@docs LLMs.txt` 进行临时引用,增强对 Codebase Kit 组件的支持。
[详细了解 Qoder 配置方法](https://docs.qoder.com/)
### 其他 AI 工具
任何支持 LLMs.txt 的 AI 工具均可使用以上路径来更好地理解 Codebase Kit。
---
url: /components/AIFormFill.md
---
# AIFormFill AI 智能表单填写
AI 智能表单填写组件,可以自动分析表单字段并智能填写合适的测试数据。
## 安装
```sh [npx]
npx shadcn@latest add https://codebase.anyask.dev/r/ai-form-fill.json
```
```sh [yarn]
yarn dlx shadcn@latest add https://codebase.anyask.dev/r/ai-form-fill.json
```
```sh [pnpm]
pnpm dlx shadcn@latest add https://codebase.anyask.dev/r/ai-form-fill.json
```
```sh [bunx]
bunx shadcn@latest add https://codebase.anyask.dev/r/ai-form-fill.json
```
```sh [deno]
deno run npm:shadcn@latest npm:add https://codebase.anyask.dev/r/ai-form-fill.json
```
## 基础用法
最简单的用法,将 `Form.Item` 包裹在 `AIFormFill` 组件中即可。
```tsx file="/demos/components/AIFormFill/basic.demo.tsx" preview
import React from 'react';
import { DatePicker, Form, Input, message } from 'antd';
import AIFormFill from '@/components/AIFormFill';
const Demo: React.FC = () => {
const [form] = Form.useForm();
const handleFillComplete = (values: Record) => {
console.log('AI Fill Complete:', values);
message.success('AI 已完成表单填写');
};
const handleFillError = (error: Error) => {
console.error('AI Fill Error:', error);
message.error(`AI 填写失败: ${error.message}`);
};
return (
);
};
export default Demo;
```
## 与 SearchForm 组合使用
`AIFormFill` 可以与 `SearchForm` 组件完美配合使用。只需将 `AIFormFill` 包裹在 `SearchForm` 外层即可。
```tsx file="/demos/components/AIFormFill/with-search-form.demo.tsx" preview
import React from 'react';
import { DatePicker, Form, Input, message } from 'antd';
import AIFormFill from '@/components/AIFormFill';
import SearchForm from '@/components/SearchForm';
const Demo: React.FC = () => {
const [form] = Form.useForm();
const handleSearch = (values: Record) => {
console.log('Search:', values);
message.success(`查询成功: ${JSON.stringify(values)}`);
};
const handleReset = () => {
console.log('Reset');
message.info('表单已重置');
};
const handleFillComplete = (values: Record) => {
console.log('AI Fill Complete:', values);
message.success('AI 已完成表单填写');
};
const handleFillError = (error: Error) => {
console.error('AI Fill Error:', error);
message.error(`AI 填写失败: ${error.message}`);
};
return (
);
};
export default Demo;
```
## 自定义按钮
你可以通过 `renderButton` 属性完全自定义按钮的渲染方式,或者通过 `buttonIcon`、`buttonType` 等属性调整样式。
```tsx file="/demos/components/AIFormFill/custom-button.demo.tsx" preview
import React from 'react';
import { Button, DatePicker, Form, Input, message, Space } from 'antd';
import { RobotOutlined } from '@ant-design/icons';
import AIFormFill from '@/components/AIFormFill';
const Demo: React.FC = () => {
const [form] = Form.useForm();
const handleFillComplete = (values: Record) => {
console.log('AI Fill Complete:', values);
message.success('AI 已完成表单填写');
};
const handleFillError = (error: Error) => {
console.error('AI Fill Error:', error);
message.error(`AI 填写失败: ${error.message}`);
};
return (
🎨 自定义按钮样式
你可以通过 renderButton 属性完全自定义按钮的渲染方式,或者通过 buttonIcon、buttonType 等属性调整样式。
);
};
export default Demo;
```
## 智能识别字段类型
组件会自动识别以下类型的字段并生成相应的测试数据:
| 字段类型/名称 | 示例数据 |
| ---------------------------------------- | ---------------------- |
| ID 字段 (包含 `id` 或 `ID`) | `"12345"` |
| 姓名字段 (包含 `name`、`姓名`、`名称`) | `"张三"`、`"李四"` |
| 邮箱字段 (包含 `email`、`邮箱`) | `"test123@gmail.com"` |
| 日期字段 (DatePicker 或包含 `date`、`日期`、`time`) | `moment('2024-01-15')` |
| 数字字段 (InputNumber 或包含 `number`、`数量`) | `123` |
| 其他文本字段 | `"{标签} - 测试数据 42"` |
## API
---
url: /components/AsyncDescriptions.md
---
# AsyncDescriptions 异步描述列表
支持异步数据加载的描述列表组件,集成了 BoundaryBlock 的加载、错误、空状态处理。
## 安装
```sh [npx]
npx shadcn@latest add https://codebase.anyask.dev/r/async-descriptions.json
```
```sh [yarn]
yarn dlx shadcn@latest add https://codebase.anyask.dev/r/async-descriptions.json
```
```sh [pnpm]
pnpm dlx shadcn@latest add https://codebase.anyask.dev/r/async-descriptions.json
```
```sh [bunx]
bunx shadcn@latest add https://codebase.anyask.dev/r/async-descriptions.json
```
```sh [deno]
deno run npm:shadcn@latest npm:add https://codebase.anyask.dev/r/async-descriptions.json
```
## 基础用法
```tsx file="/demos/components/AsyncDescriptions/basic.demo.tsx" preview
import React from 'react';
import AsyncDescriptions from '@/components/AsyncDescriptions';
const Demo: React.FC = () => {
const fetchUserInfo = async () => {
// 模拟异步请求
await new Promise((resolve) => setTimeout(resolve, 1000));
return {
name: '张三',
age: 28,
email: 'zhangsan@example.com',
status: 'active',
createTime: '2024-01-15',
};
};
return (
);
};
export default Demo;
```
## 自定义头部渲染
通过 `renderHeader` 自定义头部区域,可以显示更丰富的信息。
```tsx file="/demos/components/AsyncDescriptions/custom-render.demo.tsx" preview
import React from 'react';
import { Button } from 'antd';
import { ReloadOutlined } from '@ant-design/icons';
import AsyncDescriptions from '@/components/AsyncDescriptions';
const Demo: React.FC = () => {
const fetchUserInfo = async () => {
await new Promise((resolve) => setTimeout(resolve, 1000));
return {
name: '李四',
salary: 15000,
phone: '13800138000',
status: 'active',
};
};
return (
(
{data.name}
} onClick={refresh}>
刷新
)}
items={[
{ dataIndex: 'name', label: '姓名' },
{ dataIndex: 'salary', label: '薪资', unit: '元', precision: 0 },
{ dataIndex: 'phone', label: '手机号' },
{
dataIndex: 'status',
label: '状态',
enum: { active: 启用 , inactive: 禁用 },
},
]}
/>
);
};
export default Demo;
```
## Features
- **自动请求**: 组件挂载时自动调用 `request` 函数获取数据
- **状态处理**: 集成 BoundaryBlock,自动处理加载中、错误、空状态
- **自定义头部**: 支持 `title` 或 `renderHeader` 自定义头部
- **Descriptions支持**: 完全支持 Descriptions 的所有配置项
## API
### [#](#asyncdescriptions)AsyncDescriptions
| 属性 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| request*** | 请求函数 | `() => Promise` | `-` |
| descriptionsClassName | Descriptions className | `string` | `-` |
| title | 标题 | `ReactNode` | `-` |
| renderHeader | 自定义渲染 header | `(data: T, result: Result) => ReactNode` | `-` |
继承 [BoundaryBlock](/components/BoundaryBlock.md#boundaryblock) 的属性(除 `header`)。
---
url: /components/AsyncSelect.md
---
# AsyncSelect 异步选择器
支持异步数据加载和远程搜索的选择器组件。
## 安装
```sh [npx]
npx shadcn@latest add https://codebase.anyask.dev/r/async-select.json
```
```sh [yarn]
yarn dlx shadcn@latest add https://codebase.anyask.dev/r/async-select.json
```
```sh [pnpm]
pnpm dlx shadcn@latest add https://codebase.anyask.dev/r/async-select.json
```
```sh [bunx]
bunx shadcn@latest add https://codebase.anyask.dev/r/async-select.json
```
```sh [deno]
deno run npm:shadcn@latest npm:add https://codebase.anyask.dev/r/async-select.json
```
## 基础用法
传入 `service` 函数异步加载选项数据。
```tsx file="/demos/components/AsyncSelect/basic.demo.tsx" preview
import React from 'react';
import AsyncSelect from '@/components/AsyncSelect';
// 模拟接口返回数据
const fetchOptions = async () => {
await new Promise((resolve) => setTimeout(resolve, 500));
return {
data: [
{ label: '选项一', value: '1' },
{ label: '选项二', value: '2' },
{ label: '选项三', value: '3' },
],
};
};
const Demo: React.FC = () => {
return ;
};
export default Demo;
```
## 远程搜索
启用 `enableRemoteSearch` 后,用户输入时会调用 `service` 函数进行远程搜索。支持防抖配置 `searchDebounceWait`。
```tsx file="/demos/components/AsyncSelect/remote-search.demo.tsx" preview
import React from 'react';
import AsyncSelect from '@/components/AsyncSelect';
// 模拟搜索接口
const searchOptions = async (searchText: string) => {
await new Promise((resolve) => setTimeout(resolve, 500));
const allOptions = [
{ label: '苹果', value: 'apple' },
{ label: '香蕉', value: 'banana' },
{ label: '橙子', value: 'orange' },
{ label: '葡萄', value: 'grape' },
{ label: '西瓜', value: 'watermelon' },
];
const filtered = allOptions.filter((item) => item.label.includes(searchText) || item.value.includes(searchText));
// 如果没有匹配结果,返回用户输入作为提示
if (filtered.length === 0 && searchText) {
return {
data: [
{
label: `搜索 "${searchText}" 无结果`,
value: searchText,
disabled: true,
},
],
};
}
return { data: filtered };
};
const Demo: React.FC = () => {
return (
);
};
export default Demo;
```
## 允许空搜索
通过 `allowEmptySearch` 控制搜索值为空时是否允许搜索。配合 `initialLoad` 可实现聚焦时加载全部数据。
```tsx file="/demos/components/AsyncSelect/allow-empty-search.demo.tsx" preview
import React from 'react';
import AsyncSelect from '@/components/AsyncSelect';
// 模拟搜索 API(允许空搜索时返回所有数据)
const mockSearchProducts = async (searchText?: string) => {
return new Promise<{ data: any[] }>((resolve) => {
setTimeout(() => {
const allProducts = [
{ id: '1', name: 'iPhone 15', code: 'IP15' },
{ id: '2', name: 'MacBook Pro', code: 'MBP' },
{ id: '3', name: 'AirPods Pro', code: 'APP' },
{ id: '4', name: 'iPad Air', code: 'IPA' },
{ id: '5', name: 'Apple Watch', code: 'AW' },
];
// 允许空搜索时,searchText 为空也会返回所有数据
const filtered = searchText
? allProducts.filter(
(product) =>
product.name.toLowerCase().includes(searchText.toLowerCase()) ||
product.code.toLowerCase().includes(searchText.toLowerCase()),
)
: allProducts;
resolve({ data: filtered });
}, 300);
});
};
const Demo: React.FC = () => {
return (
);
};
export default Demo;
```
## 数据依赖
通过 `deps` 监听依赖变化,当依赖项变化时会自动重新请求数据。
```tsx file="/demos/components/AsyncSelect/deps.demo.tsx" preview
import React, { useState } from 'react';
import { Select } from 'antd';
import AsyncSelect from '@/components/AsyncSelect';
// 模拟根据分类获取选项
const fetchOptionsByCategory = async (category: string) => {
await new Promise((resolve) => setTimeout(resolve, 500));
const optionsMap: Record = {
fruit: [
{ label: '苹果', value: 'apple' },
{ label: '香蕉', value: 'banana' },
],
vegetable: [
{ label: '胡萝卜', value: 'carrot' },
{ label: '西红柿', value: 'tomato' },
],
drink: [
{ label: '可乐', value: 'cola' },
{ label: '橙汁', value: 'orange-juice' },
],
};
return { data: optionsMap[category] || [] };
};
const Demo: React.FC = () => {
const [category, setCategory] = useState('fruit');
return (
fetchOptionsByCategory(category)}
deps={[category]}
/>
);
};
export default Demo;
```
## 全部选项
设置 `hasAllOption` 为 `true` 会自动在选项列表顶部添加"全部"选项,其值默认为 `null`。
```tsx file="/demos/components/AsyncSelect/all-option.demo.tsx" preview
import React from 'react';
import AsyncSelect from '@/components/AsyncSelect';
// 模拟接口返回数据
const fetchOptions = async () => {
await new Promise((resolve) => setTimeout(resolve, 500));
return {
data: [
{ label: '选项一', value: '1' },
{ label: '选项二', value: '2' },
{ label: '选项三', value: '3' },
],
};
};
const Demo: React.FC = () => {
return ;
};
export default Demo;
```
## API
### [#](#asyncselect)AsyncSelect
**异步选择器**
| 属性 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| service*** | 请求函数 | `(searchText?: string) => Promise<{ data: any[]; }>` | `-` |
| deps | 数据依赖项 | `any[]` | `-` |
| ready | 是否准备好请求,默认 true | `boolean` | `-` |
| hasAllOption | 是否显示全部选项 | `boolean` | `-` |
| allOptionText | 全部选项的文案 | `string` | `-` |
| fieldNames | 字段名映射 | `FieldNames` | `-` |
| enableRemoteSearch | 是否启用远程搜索 | `boolean` | `-` |
| searchDebounceWait | 搜索防抖延迟时间(毫秒),默认 500 | `number` | `-` |
| initialLoad | 开启远程搜索时是否初始加载数据,默认为 false | `boolean` | `-` |
| allowEmptySearch | 搜索值为空时是否允许搜索,默认 false | `boolean` | `-` |
继承 Ant Design [Select](https://ant.design/components/select-cn#api) 组件的其他属性(除 `options`)。
---
url: /components/BoundaryBlock.md
---
# BoundaryBlock 边界区块
内容边界处理组件,用于处理加载中、空数据、错误等边界状态。
## 安装
```sh [npx]
npx shadcn@latest add https://codebase.anyask.dev/r/boundary-block.json
```
```sh [yarn]
yarn dlx shadcn@latest add https://codebase.anyask.dev/r/boundary-block.json
```
```sh [pnpm]
pnpm dlx shadcn@latest add https://codebase.anyask.dev/r/boundary-block.json
```
```sh [bunx]
bunx shadcn@latest add https://codebase.anyask.dev/r/boundary-block.json
```
```sh [deno]
deno run npm:shadcn@latest npm:add https://codebase.anyask.dev/r/boundary-block.json
```
## 基础用法
组件支持 `loading`、`empty`、`error` 三种边界状态,通过设置对应 prop 即可切换显示。
```tsx file="/demos/components/BoundaryBlock/basic.demo.tsx" preview
import React, { useState } from 'react';
import { Button, Table, Tag } from 'antd';
import BoundaryBlock from '@/components/BoundaryBlock';
const Demo: React.FC = () => {
const [loading, setLoading] = useState(false);
const [empty, setEmpty] = useState(false);
const [error, setError] = useState(null);
const mockFetch = (type: 'success' | 'empty' | 'error') => {
setLoading(true);
setError(null);
setEmpty(false);
setTimeout(() => {
setLoading(false);
if (type === 'empty') {
setEmpty(true);
} else if (type === 'error') {
setError(new Error('网络连接失败,请稍后重试'));
}
}, 1000);
};
const columns = [
{ title: 'Key', dataIndex: 'key', key: 'key' },
{ title: 'Name', dataIndex: 'name', key: 'name' },
{ title: 'Age', dataIndex: 'age', key: 'age' },
{ title: 'Address', dataIndex: 'address', key: 'address' },
{
title: 'Tags',
key: 'tags',
render: (_: any, record: any) => (
<>
{record.tags[0]}
>
),
},
];
const data = [
{ key: '1', name: 'John Brown', age: 32, address: 'New York No. 1 Lake Park', tags: ['nice', 'developer'] },
{ key: '2', name: 'Jim Green', age: 42, address: 'London No. 1 Lake Park', tags: ['loser'] },
{ key: '3', name: 'Joe Black', age: 32, address: 'Sydney No. 1 Lake Park', tags: ['cool', 'teacher'] },
];
return (
mockFetch('success')}>
加载成功
mockFetch('empty')}>加载为空
mockFetch('error')}>加载失败
mockFetch('success')}>
);
};
export default Demo;
```
## 尺寸
### small
```tsx file="/demos/components/BoundaryBlock/small.demo.tsx" preview
import React, { useState } from 'react';
import { Button } from 'antd';
import BoundaryBlock from '@/components/BoundaryBlock';
const Demo: React.FC = () => {
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const [empty, setEmpty] = useState(false);
const mockFetch = (type: 'success' | 'empty' | 'error') => {
setLoading(true);
setError(null);
setEmpty(false);
setTimeout(() => {
setLoading(false);
if (type === 'empty') {
setEmpty(true);
} else if (type === 'error') {
setError(new Error('请求失败'));
}
}, 1000);
};
return (
mockFetch('success')}>
加载成功
mockFetch('empty')}>加载为空
mockFetch('error')}>加载失败
mockFetch('success')} size="small">
内容区域
);
};
export default Demo;
```
### default
```tsx file="/demos/components/BoundaryBlock/default.demo.tsx" preview
import React, { useState } from 'react';
import { Button } from 'antd';
import BoundaryBlock from '@/components/BoundaryBlock';
const Demo: React.FC = () => {
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const [empty, setEmpty] = useState(false);
const mockFetch = (type: 'success' | 'empty' | 'error') => {
setLoading(true);
setError(null);
setEmpty(false);
setTimeout(() => {
setLoading(false);
if (type === 'empty') {
setEmpty(true);
} else if (type === 'error') {
setError(new Error('请求失败'));
}
}, 1000);
};
return (
mockFetch('success')}>
加载成功
mockFetch('empty')}>加载为空
mockFetch('error')}>加载失败
mockFetch('success')} size="default">
内容区域
);
};
export default Demo;
```
## 行内模式
`inline` 模式仅在错误状态下生效,显示简洁的内联错误提示,适合在文字或行内区块中使用。
```tsx file="/demos/components/BoundaryBlock/inline.demo.tsx" preview
import React, { useState } from 'react';
import { Button } from 'antd';
import BoundaryBlock from '@/components/BoundaryBlock';
const Demo: React.FC = () => {
const [error, setError] = useState(null);
const mockFetch = () => {
setError(new Error('数据加载失败'));
};
const refresh = () => {
setError(null);
};
return (
);
};
export default Demo;
```
## 骨架屏模式
通过 `skeleton` prop 启用骨架屏模式,此时 loading 状态下会显示骨架屏而非 Spin,且子元素会被阻塞不渲染。
```tsx file="/demos/components/BoundaryBlock/skeleton.demo.tsx" preview
import React, { useState } from 'react';
import { Button } from 'antd';
import BoundaryBlock from '@/components/BoundaryBlock';
const Demo: React.FC = () => {
const [loading, setLoading] = useState(false);
const mockFetch = () => {
setLoading(true);
setTimeout(() => setLoading(false), 2000);
};
return (
}>
这是实际内容,会在 loading 结束后显示
骨架屏模式会阻塞子元素渲染
);
};
export default Demo;
```
## API
### [#](#boundaryblock)BoundaryBlock
| 属性 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| loading | 是否显示加载中状态 | `boolean` | `-` |
| error | 错误对象 | `Error` | `-` |
| errorComponent | 自定义错误组件 | `ReactNode` | `-` |
| empty | 是否显示空状态 | `boolean` | `-` |
| emptyText | 空状态文本 | `ReactNode` | `-` |
| emptyComponent | 自定义空状态组件 | `ReactNode` | `-` |
| refresh | 点击重试的回调 | `() => void` | `-` |
| header | 头部内容 | `ReactNode` | `-` |
| children | 子元素 | `ReactNode` | `-` |
| size | 尺寸模式 | `"small" | "default" | "inline"` | `-` |
| wrapperClassName | Spin 包裹层类名 | `string` | `-` |
| loadingClassName | loading 状态类名 | `string` | `-` |
| errorClassName | error 状态类名 | `string` | `-` |
| emptyClassName | empty 状态类名 | `string` | `-` |
| loadingComponent | 自定义 loading 组件 | `ReactNode` | `-` |
| skeleton | 骨架屏模式 | `boolean` | `-` |
---
url: /components/Button.md
---
# ~~Button 按钮~~
deprecated
```sh [npm]
npm install antd -S
```
```sh [yarn]
yarn add antd -S
```
```sh [pnpm]
pnpm add antd -S
```
```sh [bun]
bun add antd -S
```
```sh [deno]
deno add npm:antd -S
```
Primary
Secondary
Danger
---
url: /components/DescriptionItem.md
---
# DescriptionItem 描述项
描述项配置类型,用于配置 Descriptions 组件的每一项。
## API
### DescriptionItem
| 属性 | 说明 | 类型 | 默认值 |
| ------------ | ------------------------ | -------------------------------------- | --- |
| key | 字段的键值,支持嵌套路径,有类型提示 | `Paths \| AutoCompletableString` | - |
| label | 显示的标签 | `ReactNode` | - |
| render | 自定义渲染函数 | `(value: any, record: T) => ReactNode` | - |
| tooltip | 是否显示省略号 | `boolean \| TooltipProps` | - |
| className | 自定义类名 | `string` | - |
| visible | 条件渲染,返回 false 时不显示该项 | `(record: T) => boolean` | - |
| defaultValue | 默认值,当获取的值为 undefined 时使用 | `any` | - |
| enum | 枚举值映射 | `Record` | - |
| format | 日期时间格式 | `string` | - |
| onClick | 点击事件处理函数 | `(value: any, record: T) => void` | - |
| unit | 单位符号,如 "元" | `string` | - |
| precision | 数字小数位数 | `number` | `2` |
| imageGroup | 图片组渲染 | `boolean \| ImageGroupProps` | - |
| fileList | 文件列表 | `boolean` | - |
---
url: /components/Descriptions.md
---
# Descriptions 描述列表
配置化的描述列表组件,通过 items 配置自动渲染数据。
## 安装
```sh [npx]
npx shadcn@latest add https://codebase.anyask.dev/r/descriptions.json
```
```sh [yarn]
yarn dlx shadcn@latest add https://codebase.anyask.dev/r/descriptions.json
```
```sh [pnpm]
pnpm dlx shadcn@latest add https://codebase.anyask.dev/r/descriptions.json
```
```sh [bunx]
bunx shadcn@latest add https://codebase.anyask.dev/r/descriptions.json
```
```sh [deno]
deno run npm:shadcn@latest npm:add https://codebase.anyask.dev/r/descriptions.json
```
## 基础用法
```tsx file="/demos/components/Descriptions/basic.demo.tsx" preview
import React from 'react';
import Descriptions from '@/components/Descriptions';
const Demo: React.FC = () => {
const data = {
name: '张三',
age: 28,
email: 'zhangsan@example.com',
status: 'active',
createTime: '2024-01-15',
tags: ['开发者', '管理员'],
avatar: ['https://api.dicebear.com/7.x/avataaars/svg?seed=Felix'],
};
return (
启用, inactive: 禁用 },
},
{ dataIndex: 'createTime', label: '创建时间', format: 'YYYY-MM-DD HH:mm:ss' },
{ dataIndex: 'tags', label: '标签', defaultValue: '-' },
{
key: 'custom-avatar-key',
dataIndex: 'avatar',
label: '头像',
render: (value: string[]) => value?.[0] || '-',
},
]}
/>
);
};
export default Demo;
```
## 自定义渲染
支持自定义渲染函数、枚举映射、日期格式化、单位等功能。
```tsx file="/demos/components/Descriptions/custom-render.demo.tsx" preview
import React from 'react';
import { message, Progress } from 'antd';
import { EasyButton } from '@alife/alsc-ele-components';
import Descriptions from '@/components/Descriptions';
const Demo: React.FC = () => {
const data = {
name: '李四',
salary: 15000,
phone: '13800138000',
description:
'这是一段很长的文本内容,用于演示省略号效果。当文本内容超过一定长度时,应该显示省略号并且支持 tooltip 查看完整内容。',
progress: 75,
actions: [],
};
return (
{
message.success(`拨打电话: ${value}`);
},
},
{
dataIndex: 'description',
label: '描述',
tooltip: true,
defaultValue: '暂无描述',
},
{
dataIndex: 'progress',
label: '进度',
render: (value: number) => ,
},
{
key: 'actions-key',
dataIndex: 'actions',
label: '操作',
render: () => (
编辑
删除
),
},
]}
/>
);
};
export default Demo;
```
## Features
- **自定义渲染**: 通过 `render` 函数自定义内容
- **枚举映射**: 通过 `enum` 将值映射为 ReactNode
- **日期格式化**: 通过 `format` 格式化日期
- **数字单位**: 通过 `unit` 和 `precision` 处理数字
- **可点击文本**: 通过 `onClick` 处理点击事件
- **tooltip**: 通过 `tooltip` 或 `tooltip: true` 启用省略号 tooltip
- **条件显示**: 通过 `visible` 函数控制是否显示
## API
### [#](#descriptions)Descriptions
**配置化的描述列表组件**
| 属性 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| data*** | 数据源 | `Record` | `-` |
| items*** | 配置项列表 [DescriptionItem[]](#descriptionitem) | `DescriptionItem[]` | `-` |
| className | 自定义类名 | `string` | `-` |
### DescriptionItem
| 属性 | 说明 | 类型 | 默认值 |
| ------------ | ----------------------------------- | ------------------------------------- | --------- |
| key | 唯一标识符,用于 React key,不提供则使用 dataIndex | `string` | dataIndex |
| dataIndex | 字段路径,支持嵌套路径,有类型提示 | `Paths` | - |
| label | 显示的标签 | `ReactNode` | - |
| render | 自定义渲染函数 | `(value, record) => ReactNode` | - |
| tooltip | 省略号 tooltip | `boolean \| TooltipProps` | - |
| className | 自定义类名 | `string` | - |
| visible | 条件渲染,返回 false 时不显示 | `(record: T) => boolean` | - |
| defaultValue | 默认值,当值为 undefined 时使用 | `any` | - |
| enum | 枚举值映射 | `Record` | - |
| format | 日期时间格式 | `string` | - |
| onClick | 点击事件处理函数 | `(value, record) => void` | - |
| unit | 单位符号,如 "元" | `string` | - |
| precision | 数字小数位数 | `number` | 2 |
| imageGroup | 图片组渲染 | `boolean \| ImageGroupProps` | - |
| fileList | 文件列表 | `boolean` | - |
---
url: /components/DownloadManager.md
---
# DownloadManager 下载管理
管理下载任务的组件,支持任务列表、下载状态追踪、下载进度提示等功能。
## 安装
```sh [npx]
npx shadcn@latest add https://codebase.anyask.dev/r/download-manager.json
```
```sh [yarn]
yarn dlx shadcn@latest add https://codebase.anyask.dev/r/download-manager.json
```
```sh [pnpm]
pnpm dlx shadcn@latest add https://codebase.anyask.dev/r/download-manager.json
```
```sh [bunx]
bunx shadcn@latest add https://codebase.anyask.dev/r/download-manager.json
```
```sh [deno]
deno run npm:shadcn@latest npm:add https://codebase.anyask.dev/r/download-manager.json
```
## 基础用法
传入 `getDownloadTaskList` 和 `download` 两个必需的异步函数,分别用于获取下载任务列表和触发下载。组件会显示「下载管理」和「下载」两个按钮,点击「下载」后会弹出成功通知,提示文件已生成。
```tsx file="/demos/components/DownloadManager/basic.demo.tsx" preview
import React from 'react';
import DownloadManager from '@/components/DownloadManager';
const mockFetchTaskList = async (params: { pageNum: number; pageSize: number }) => {
await new Promise((resolve) => setTimeout(resolve, 500));
const tasks = [
{
id: 1,
fileName: '数据导出_20260101.xlsx',
gmtCreate: '2026-01-01 10:00:00',
gmtModified: '2026-01-01 10:05:00',
status: 'CREATED',
url: 'https://example.com/file1.xlsx',
},
{
id: 2,
fileName: '数据导出_20260102.xlsx',
gmtCreate: '2026-01-02 14:30:00',
gmtModified: '2026-01-02 14:35:00',
status: 'PROCESSING',
},
{
id: 3,
fileName: '数据导出_20260103.xlsx',
gmtCreate: '2026-01-03 09:15:00',
gmtModified: '2026-01-03 09:20:00',
status: 'FAILED',
},
];
return {
data: tasks.slice((params.pageNum - 1) * params.pageSize, params.pageNum * params.pageSize),
total: tasks.length,
};
};
const mockTriggerDownload = async () => {
await new Promise((resolve) => setTimeout(resolve, 1000));
return { data: '数据已生成' };
};
const Demo: React.FC = () => {
const handleDownload = async () => {
await mockTriggerDownload();
};
return ;
};
export default Demo;
```
### Ref 方法
通过 `ref` 可以调用 `showSuccessNotification` 方法显示下载成功通知,可自定义通知消息。
```tsx pure
const downloadManagerRef = useRef(null);
// 触发下载后显示通知
downloadManagerRef.current?.showSuccessNotification('数据已生成');
```
## 自定义配置
### 文件有效期
通过 `expireDays` 设置下载文件的有效期(天数),默认为 3 天。通知中会提示用户有效期信息。
```tsx file="/demos/components/DownloadManager/custom.demo.tsx" preview
import React from 'react';
import DownloadManager from '@/components/DownloadManager';
const mockFetchTaskList = async (params: { pageNum: number; pageSize: number }) => {
await new Promise((resolve) => setTimeout(resolve, 500));
return {
data: [
{
id: 1,
fileName: '自定义配置_导出.xlsx',
gmtCreate: '2026-01-12 10:00:00',
gmtModified: '2026-01-12 10:02:00',
status: 'CREATED',
url: 'https://example.com/file.xlsx',
},
],
total: 1,
};
};
const mockTriggerDownload = async () => {
await new Promise((resolve) => setTimeout(resolve, 1000));
return { data: '数据已生成' };
};
const Demo: React.FC = () => {
return (
);
};
export default Demo;
```
### 下载提示文案
通过 `downloadTooltip` 自定义「下载」按钮的悬停提示文案。
### 通知配置
通过 `notificationProps` 配置 Ant Design Notification 组件的属性,如位置 `placement`、显示时长 `duration` 等。
## 下载状态
组件支持三种下载任务状态:
| 状态 | 说明 | 操作 |
| ------------ | ------- | -------- |
| `CREATED` | 已完成,可下载 | 显示「下载」按钮 |
| `PROCESSING` | 处理中 | 下载按钮禁用 |
| `FAILED` | 失败 | 下载按钮禁用 |
## API
### DownloadManagerProps
| 属性 | 说明 | 类型 | 默认值 |
| --------------------- | --------------- | --------------------------------------------------------------------- | --- |
| className | 自定义类名 | `string` | - |
| notificationProps | 通知配置 | `ArgsProps` | - |
| downloadTriggerSpmKey | 触发下载的埋点 key | `string` | - |
| downloadFileSpmKey | 文件列表下载文件的埋点 key | `string` | - |
| downloadManagerSpmKey | 下载管理按钮的埋点 key | `string` | - |
| getDownloadTaskList | 下载任务列表请求方法 | `(params: DownloadTaskListParams) => Promise` | - |
| download | 触发下载请求方法 | `() => Promise` | - |
| expireDays | 下载文件有效期(天数) | `number` | 3 |
| downloadTooltip | 下载按钮的提示文案 | `ReactNode` | - |
### DownloadManagerRef
| 方法 | 说明 | 类型 |
| ----------------------- | ------ | ---------------------------- |
| showSuccessNotification | 显示成功通知 | `(message?: string) => void` |
### DownloadTaskListResult
| 属性 | 说明 | 类型 |
| ----- | ------ | ---------------- |
| data | 下载任务列表 | `DownloadTask[]` |
| total | 总条数 | `number` |
### DownloadTask
| 属性 | 说明 | 类型 |
| -------------- | ----- | -------------------- |
| id | 任务 ID | `string \| number` |
| fileName | 文件名 | `string` |
| gmtCreate | 提交时间 | `string \| number` |
| gmtModified | 生成时间 | `string \| number` |
| status | 状态 | `DownloadStatusEnum` |
| url | 下载地址 | `string` |
| \[key: string] | 其他字段 | `any` |
---
url: /components/FilePreview.md
---
# FilePreview 文件预览
文件预览组件,支持文件列表展示和下载。
## 安装
```sh [npx]
npx shadcn@latest add https://codebase.anyask.dev/r/file-preview.json
```
```sh [yarn]
yarn dlx shadcn@latest add https://codebase.anyask.dev/r/file-preview.json
```
```sh [pnpm]
pnpm dlx shadcn@latest add https://codebase.anyask.dev/r/file-preview.json
```
```sh [bunx]
bunx shadcn@latest add https://codebase.anyask.dev/r/file-preview.json
```
```sh [deno]
deno run npm:shadcn@latest npm:add https://codebase.anyask.dev/r/file-preview.json
```
## FilePreviewList 基础用法
```tsx pure
import { FilePreviewList } from '@/components/FilePreview';
function Demo() {
const fileList = [
{ fileHash: 'hash1', fileName: '文档.pdf' },
{ fileHash: 'hash2', fileName: '表格.xlsx' },
];
return (
);
}
```
## FilePreviewItem 基础用法
```tsx pure
import { FilePreviewItem } from '@/components/FilePreview';
function Demo() {
const fileItem = { fileHash: 'hash1', fileName: '文档.pdf' };
return (
);
}
```
## 自定义文件 URL 获取
```tsx pure
function Demo() {
const customFileUrlFetcher = async (fileHash: string) => {
const res = await customApi.getFileUrl(fileHash);
return res.url;
};
return (
);
}
```
## API
### FilePreviewListProps
| 属性 | 说明 | 类型 | 默认值 |
| -------------- | -------------- | --------------------------------- | ----------------------------- |
| fileList | 文件列表 | `FileItem[] \| null \| undefined` | - |
| downloadable | 是否可下载 | `boolean` | - |
| fileIcon | 文件 icon | `ReactNode` | - |
| fileUrlFetcher | 自定义文件 URL 获取函数 | `FileUrlFetcher` | 默认使用 `FileApi.batchCreateUrl` |
继承原生 `div` 的 HTML 属性。
### FilePreviewItemProps
| 属性 | 说明 | 类型 | 默认值 |
| -------------- | -------------- | ----------------------- | ----------------------------- |
| fileItem | 文件信息 | `FileItem \| undefined` | - |
| downloadable | 是否可下载 | `boolean` | - |
| fileIcon | 文件 icon | `ReactNode` | - |
| fileUrlFetcher | 自定义文件 URL 获取函数 | `FileUrlFetcher` | 默认使用 `FileApi.batchCreateUrl` |
继承原生 `div` 的 HTML 属性。
### FileItem
| 属性 | 说明 | 类型 |
| --------------- | ------------------------- | -------- |
| fileHash | 文件 hash | `string` |
| fileName | 文件名 | `string` |
| displayFileName | 展示名;下载时若未指定文件名,将作为默认文件名使用 | `string` |
### FileUrlFetcher
```ts pure
type FileUrlFetcher = (fileHash: string) => Promise;
```
### [#](#filepreviewlist)FilePreviewList
| 属性 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| fileList*** | 文件列表 | `FileItem[]` | `-` |
| downloadable | 是否可下载 | `boolean` | `-` |
| fileIcon | 文件 icon | `ReactNode` | `-` |
| fileUrlFetcher | 自定义文件URL获取函数,如果不提供则使用默认的 | `FileUrlFetcher` | `-` |
### [#](#fileurlfetcher)FileUrlFetcher
**自定义文件获取函数的类型**
| 属性 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
### [#](#filepreviewitem)FilePreviewItem
| 属性 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| fileItem*** | 文件信息 | `FileItem` | `-` |
| downloadable | 是否可下载 | `boolean` | `-` |
| fileIcon | 文件 icon | `ReactNode` | `-` |
| fileUrlFetcher | 自定义文件URL获取函数,如果不提供则使用默认的 | `FileUrlFetcher` | `-` |
---
url: /components/FilePreviewList.md
---
# FilePreviewList 文件预览列表
文件列表展示组件,支持点击下载。
## 安装
```sh [npx]
npx shadcn@latest add https://codebase.anyask.dev/r/file-preview-list.json
```
```sh [yarn]
yarn dlx shadcn@latest add https://codebase.anyask.dev/r/file-preview-list.json
```
```sh [pnpm]
pnpm dlx shadcn@latest add https://codebase.anyask.dev/r/file-preview-list.json
```
```sh [bunx]
bunx shadcn@latest add https://codebase.anyask.dev/r/file-preview-list.json
```
```sh [deno]
deno run npm:shadcn@latest npm:add https://codebase.anyask.dev/r/file-preview-list.json
```
## 基础用法
```tsx file="/demos/components/FilePreviewList/basic.demo.tsx" preview
import React from 'react';
import FilePreviewList, { type FileItem } from '@/components/FilePreviewList';
const Demo: React.FC = () => {
const fileList: FileItem[] = [
{ fileHash: 'abc123', fileName: '示例文件1.pdf' },
{ fileHash: 'def456', fileName: '示例文件2.docx' },
{ fileHash: 'ghi789', fileName: '示例文件3.jpg' },
];
return ;
};
export default Demo;
```
## 自定义显示名称
通过 `displayFileName` 自定义文件显示名称,不传则使用 `fileName`。
```tsx file="/demos/components/FilePreviewList/display-name.demo.tsx" preview
import React from 'react';
import FilePreviewList, { type FileItem } from '@/components/FilePreviewList';
const Demo: React.FC = () => {
const fileList: FileItem[] = [
// 不传 displayFileName,使用 fileName
{ fileHash: 'abc123', fileName: 'report_2024_01.pdf' },
// 传入 displayFileName,显示自定义名称
{ fileHash: 'def456', fileName: '原始文件名_abc.pdf', displayFileName: '年度报告.pdf' },
// 两者都不传,显示"未知文件"
{ fileHash: 'ghi789' },
];
return ;
};
export default Demo;
```
## 自定义配置
通过 `downloadable` 禁用下载,通过 `fileIcon` 自定义或隐藏图标。`FilePreviewItem` 也支持单独使用。
```tsx file="/demos/components/FilePreviewList/custom.demo.tsx" preview
import React from 'react';
import { FileImageOutlined } from '@ant-design/icons';
import FilePreviewList, { type FileItem, FilePreviewItem } from '@/components/FilePreviewList';
const Demo: React.FC = () => {
const fileList: FileItem[] = [
{ fileHash: 'abc123', fileName: '示例文件.pdf' },
{ fileHash: 'def456', fileName: '文档.docx' },
];
return (
禁用下载
隐藏图标
自定义图标
} />
单独使用 FilePreviewItem
);
};
export default Demo;
```
## 自定义接口
通过 `fileUrlFetcher` 自定义文件 URL 获取函数。
```tsx file="/demos/components/FilePreviewList/custom-fetcher.demo.tsx" preview
import React from 'react';
import FilePreviewList, { type FileItem, type FileUrlFetcher } from '@/components/FilePreviewList';
const Demo: React.FC = () => {
const fileList: FileItem[] = [
{ fileHash: 'file1', fileName: '文件1.pdf' },
{ fileHash: 'file2', fileName: '文件2.pdf' },
];
// 自定义文件 URL 获取函数
const customFetcher: FileUrlFetcher = async (fileHash: string) => {
// 模拟自定义接口逻辑
await new Promise((resolve) => setTimeout(resolve, 500));
return `https://custom-api.example.com/files/${fileHash}`;
};
return ;
};
export default Demo;
```
## API
### [#](#filepreviewlist)FilePreviewList
| 属性 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| fileList*** | 文件列表 | `FileItem[]` | `-` |
| downloadable | 是否可下载 | `boolean` | `-` |
| fileIcon | 文件 icon | `ReactNode` | `-` |
| fileUrlFetcher | 自定义文件URL获取函数,如果不提供则使用默认的 | `FileUrlFetcher` | `-` |
### [#](#fileurlfetcher)FileUrlFetcher
**自定义文件获取函数的类型**
| 属性 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
### [#](#filepreviewitem)FilePreviewItem
| 属性 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| fileItem*** | 文件信息 | `FileItem` | `-` |
| downloadable | 是否可下载 | `boolean` | `-` |
| fileIcon | 文件 icon | `ReactNode` | `-` |
| fileUrlFetcher | 自定义文件URL获取函数,如果不提供则使用默认的 | `FileUrlFetcher` | `-` |
---
url: /components/HighlightText.md
---
# HighlightText 文本高亮
对文本中的关键词进行高亮显示的组件。
## 安装
```sh [npx]
npx shadcn@latest add https://codebase.anyask.dev/r/highlight-text.json
```
```sh [yarn]
yarn dlx shadcn@latest add https://codebase.anyask.dev/r/highlight-text.json
```
```sh [pnpm]
pnpm dlx shadcn@latest add https://codebase.anyask.dev/r/highlight-text.json
```
```sh [bunx]
bunx shadcn@latest add https://codebase.anyask.dev/r/highlight-text.json
```
```sh [deno]
deno run npm:shadcn@latest npm:add https://codebase.anyask.dev/r/highlight-text.json
```
## 基础用法
```tsx file="/demos/components/HighlightText/basic.demo.tsx" preview
import React from 'react';
import HighlightText from '@/components/HighlightText';
const Demo: React.FC = () => {
return ;
};
export default Demo;
```
## 自定义高亮样式
通过 `highlightClass` 自定义高亮文本的样式类名。
```tsx file="/demos/components/HighlightText/custom-style.demo.tsx" preview
import React, { useState } from 'react';
import { Input } from 'antd';
import HighlightText from '@/components/HighlightText';
const Demo: React.FC = () => {
const [highlight, setHighlight] = useState('示例');
const text = '这是一段示例文本,用于演示高亮效果。TypeScript 是一种强类型的 JavaScript 超集。';
return (
);
};
export default Demo;
```
## API
### [#](#highlighttext)HighlightText
| 属性 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| text*** | 要显示的文本 | `string` | `-` |
| highlight*** | 要高亮的关键词 | `string` | `-` |
| highlightClass | 高亮文本的自定义样式类名 | `string` | `text-primary` |
---
url: /components/Iframe.md
---
# Iframe 内嵌框架
带有加载状态和错误处理的 iframe 组件。
## 安装
```sh [npx]
npx shadcn@latest add https://codebase.anyask.dev/r/iframe.json
```
```sh [yarn]
yarn dlx shadcn@latest add https://codebase.anyask.dev/r/iframe.json
```
```sh [pnpm]
pnpm dlx shadcn@latest add https://codebase.anyask.dev/r/iframe.json
```
```sh [bunx]
bunx shadcn@latest add https://codebase.anyask.dev/r/iframe.json
```
```sh [deno]
deno run npm:shadcn@latest npm:add https://codebase.anyask.dev/r/iframe.json
```
## 基础用法
```tsx file="/demos/components/Iframe/basic.demo.tsx" preview
import React from 'react';
import Iframe from '@/components/Iframe';
const Demo: React.FC = () => {
return ;
};
export default Demo;
```
## 受控模式
通过 `loading` 和 `error` props 直接控制组件状态。
```tsx file="/demos/components/Iframe/boundary.demo.tsx" preview
import React, { useState } from 'react';
import { Input } from 'antd';
import Iframe from '@/components/Iframe';
const Demo: React.FC = () => {
const [url, setUrl] = useState('https://example.com');
return (
);
};
export default Demo;
```
## 自定义配置
通过 `boundaryProps` 自定义错误处理和重试行为。
## API
### [#](#iframe)Iframe
| 属性 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| src*** | iframe 地址 | `string` | `-` |
| errorMessage | 加载失败时的提示文本 | `string` | `加载页面失败` |
| loadingImage | 自定义加载时的占位图 | `string` | `https://img.alicdn.com/tfs/TB1CmVgayERMeJjy0FcXXc7opXa-308-200.gif` |
| boundaryProps | BoundaryBlock 配置 | `BoundaryBlockProps` | `-` |
---
url: /components/Image.md
---
# Image 图片
支持占位符的图片组件。
## 安装
```sh [npx]
npx shadcn@latest add https://codebase.anyask.dev/r/image.json
```
```sh [yarn]
yarn dlx shadcn@latest add https://codebase.anyask.dev/r/image.json
```
```sh [pnpm]
pnpm dlx shadcn@latest add https://codebase.anyask.dev/r/image.json
```
```sh [bunx]
bunx shadcn@latest add https://codebase.anyask.dev/r/image.json
```
```sh [deno]
deno run npm:shadcn@latest npm:add https://codebase.anyask.dev/r/image.json
```
## 基础用法
```tsx file="/demos/components/Image/basic.demo.tsx" preview
import React from 'react';
import Image from '@/components/Image';
const Demo: React.FC = () => {
return (
);
};
export default Demo;
```
## 自定义尺寸
```tsx file="/demos/components/Image/size.demo.tsx" preview
import React from 'react';
import Image from '@/components/Image';
const Demo: React.FC = () => {
return (
);
};
export default Demo;
```
## 占位符与加载失败
```tsx file="/demos/components/Image/placeholder.demo.tsx" preview
import React from 'react';
import Image from '@/components/Image';
const Demo: React.FC = () => {
return (
);
};
export default Demo;
```
## API
### [#](#image)Image
| 属性 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| src*** | 图片地址 | `string` | `-` |
| alt | 图片描述 | `string` | `-` |
| size | 图片尺寸(宽高相同) | `number` | `-` |
| className | 自定义类名 | `string` | `-` |
| placeholder | 占位图地址 | `string` | `-` |
继承 Ant Design [Image](https://ant.design/components/image-cn#api) 组件的其他属性。
---
url: /components/ImageGroup.md
---
# ImageGroup 图片组
展示多张图片的组件,支持加载、错误、空状态处理。
## 安装
```sh [npx]
npx shadcn@latest add https://codebase.anyask.dev/r/image-group.json
```
```sh [yarn]
yarn dlx shadcn@latest add https://codebase.anyask.dev/r/image-group.json
```
```sh [pnpm]
pnpm dlx shadcn@latest add https://codebase.anyask.dev/r/image-group.json
```
```sh [bunx]
bunx shadcn@latest add https://codebase.anyask.dev/r/image-group.json
```
```sh [deno]
deno run npm:shadcn@latest npm:add https://codebase.anyask.dev/r/image-group.json
```
## 基础用法
```tsx file="/demos/components/ImageGroup/basic.demo.tsx" preview
import React from 'react';
import ImageGroup from '@/components/ImageGroup';
const urls = [
'https://images.unsplash.com/photo-1542291026-7eec264c27ff?w=200&h=200&fit=crop',
'https://images.unsplash.com/photo-1515886657613-9f3515b0c78f?w=200&h=200&fit=crop',
'https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=200&h=200&fit=crop',
];
const Demo: React.FC = () => {
return ;
};
export default Demo;
```
## 自定义图片尺寸
```tsx file="/demos/components/ImageGroup/size.demo.tsx" preview
import React from 'react';
import ImageGroup from '@/components/ImageGroup';
const urls = [
'https://images.unsplash.com/photo-1542291026-7eec264c27ff?w=200&h=200&fit=crop',
'https://images.unsplash.com/photo-1515886657613-9f3515b0c78f?w=200&h=200&fit=crop',
'https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=200&h=200&fit=crop',
];
const Demo: React.FC = () => {
return (
);
};
export default Demo;
```
## 限制显示数量
通过 `showCount` 限制显示的图片数量,超出部分会显示"共 N 张"提示。
```tsx file="/demos/components/ImageGroup/show-count.demo.tsx" preview
import React from 'react';
import ImageGroup from '@/components/ImageGroup';
const urls = [
'https://images.unsplash.com/photo-1542291026-7eec264c27ff?w=200&h=200&fit=crop',
'https://images.unsplash.com/photo-1515886657613-9f3515b0c78f?w=200&h=200&fit=crop',
'https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=200&h=200&fit=crop',
'https://images.unsplash.com/photo-1507003211169-0a1dd7228d2d?w=200&h=200&fit=crop',
'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=200&h=200&fit=crop',
];
const Demo: React.FC = () => {
return ;
};
export default Demo;
```
## 自定义间距
```tsx file="/demos/components/ImageGroup/gap.demo.tsx" preview
import React from 'react';
import ImageGroup from '@/components/ImageGroup';
const urls = [
'https://images.unsplash.com/photo-1542291026-7eec264c27ff?w=200&h=200&fit=crop',
'https://images.unsplash.com/photo-1515886657613-9f3515b0c78f?w=200&h=200&fit=crop',
'https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=200&h=200&fit=crop',
];
const Demo: React.FC = () => {
return (
);
};
export default Demo;
```
## API
### [#](#imagegroup)ImageGroup
| 属性 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| className | 节点类名 | `string` | `-` |
| urls | 图片 URL 数组,传入后跳过 API 请求 | `string[]` | `-` |
| hashList | 图片 hash 列表(需要配合内部 API 使用) | `string[]` | `-` |
| imageSize | 图片大小 | `number` | `-` |
| showCount | 显示数量,超出则折叠 | `number` | `-` |
| gap | 图片间距 | `number` | `-` |
继承 [BoundaryBlock](/components/BoundaryBlock.md#boundaryblock) 的其他属性。
---
url: /components/MultiButtonAction.md
---
# MultiButtonAction 多按钮操作
通用多按钮操作组件,当按钮数量超过指定数量时,超出部分收纳到下拉菜单中。
## 安装
```sh [npx]
npx shadcn@latest add https://codebase.anyask.dev/r/multi-button-action.json
```
```sh [yarn]
yarn dlx shadcn@latest add https://codebase.anyask.dev/r/multi-button-action.json
```
```sh [pnpm]
pnpm dlx shadcn@latest add https://codebase.anyask.dev/r/multi-button-action.json
```
```sh [bunx]
bunx shadcn@latest add https://codebase.anyask.dev/r/multi-button-action.json
```
```sh [deno]
deno run npm:shadcn@latest npm:add https://codebase.anyask.dev/r/multi-button-action.json
```
## 基础用法
```tsx file="/demos/components/MultiButtonAction/basic.demo.tsx" preview
import React from 'react';
import { message } from 'antd';
import MultiButtonAction from '@/components/MultiButtonAction';
const Demo: React.FC = () => {
const actions = [
{ key: 'edit', label: '编辑' },
{ key: 'delete', label: '删除', danger: true },
{ key: 'view', label: '查看' },
];
const handleAction = (code: string) => {
message.info(`点击了: ${code}`);
};
return ;
};
export default Demo;
```
## 自定义最大显示数量
通过 `maxCount` 属性设置最多显示几个主要按钮,超出部分会收纳到下拉菜单中。
```tsx file="/demos/components/MultiButtonAction/max-count.demo.tsx" preview
import React from 'react';
import { message } from 'antd';
import MultiButtonAction from '@/components/MultiButtonAction';
const Demo: React.FC = () => {
const actions = [
{ key: 'view', label: '查看' },
{ key: 'edit', label: '编辑' },
{ key: 'duplicate', label: '复制' },
{ key: 'export', label: '导出' },
{ key: 'archive', label: '归档' },
{ key: 'delete', label: '删除', danger: true },
];
const handleAction = (code: string) => {
message.info(`点击了: ${code}`);
};
return (
maxCount=2
maxCount=4(默认)
);
};
export default Demo;
```
## 自动加载状态
当 `onAction` 返回 `Promise` 时,按钮会自动显示 loading 状态,异步完成后自动关闭。
```tsx file="/demos/components/MultiButtonAction/loading.demo.tsx" preview
import React from 'react';
import { message } from 'antd';
import MultiButtonAction from '@/components/MultiButtonAction';
const Demo: React.FC = () => {
const actions = [
{ key: 'submit', label: '提交' },
{ key: 'publish', label: '发布' },
{ key: 'save', label: '保存' },
{ key: 'view', label: '查看' },
];
const handleAction = async (code: string) => {
await new Promise((resolve) => setTimeout(resolve, 2000));
message.success(`操作成功: ${code}`);
};
return ;
};
export default Demo;
```
## 排列方向
通过 `direction` 属性设置按钮排列方向,支持 `horizontal`(水平)和 `vertical`(垂直)。
```tsx file="/demos/components/MultiButtonAction/direction.demo.tsx" preview
import React, { useState } from 'react';
import { message, Radio } from 'antd';
import MultiButtonAction from '@/components/MultiButtonAction';
const Demo: React.FC = () => {
const [direction, setDirection] = useState<'horizontal' | 'vertical'>('horizontal');
const actions = [
{ key: 'edit', label: '编辑' },
{ key: 'delete', label: '删除', danger: true },
{ key: 'view', label: '查看' },
{ key: 'export', label: '导出' },
];
const handleAction = (code: string) => {
message.info(`点击了: ${code}`);
};
return (
setDirection(e.target.value)}>
水平
垂直
);
};
export default Demo;
```
## API
### [#](#multibuttonaction)MultiButtonAction
**通用多按钮操作组件**
| 属性 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| actions*** | 要渲染的操作按钮配置 | `ActionConfig[]` | `-` |
| onAction*** | 按钮点击处理函数 | `(code: string) => void | Promise` | `-` |
| maxCount | 最多显示几个主要按钮,超过则使用下拉菜单,默认为 3 | `number` | `3` |
| direction | 排列方向,默认为水平 | `"horizontal" | "vertical"` | `horizontal` |
---
url: /components/QuestionTooltip.md
---
# QuestionTooltip 提示文本
带提示文本的组件,当有提示文本时在 children 后面显示问号图标。
## 安装
```sh [npx]
npx shadcn@latest add https://codebase.anyask.dev/r/question-tooltip.json
```
```sh [yarn]
yarn dlx shadcn@latest add https://codebase.anyask.dev/r/question-tooltip.json
```
```sh [pnpm]
pnpm dlx shadcn@latest add https://codebase.anyask.dev/r/question-tooltip.json
```
```sh [bunx]
bunx shadcn@latest add https://codebase.anyask.dev/r/question-tooltip.json
```
```sh [deno]
deno run npm:shadcn@latest npm:add https://codebase.anyask.dev/r/question-tooltip.json
```
## 基础用法
```tsx file="/demos/components/QuestionTooltip/basic.demo.tsx" preview
import React from 'react';
import QuestionTooltip from '@/components/QuestionTooltip';
const Demo: React.FC = () => {
return (
标签文本
带有长提示的标签
);
};
export default Demo;
```
## 整个区域触发 Tooltip
通过 `triggerAll` prop 使整个区域都触发 Tooltip 提示。
```tsx file="/demos/components/QuestionTooltip/trigger-all.demo.tsx" preview
import React from 'react';
import QuestionTooltip from '@/components/QuestionTooltip';
const Demo: React.FC = () => {
return (
整个区域触发
自定义样式卡片
);
};
export default Demo;
```
## API
### [#](#questiontooltip)QuestionTooltip
**带提示文本的组件,当有提示文本时在 children 后面显示问号图标**
| 属性 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| tooltip | 提示文本内容 | `string` | `-` |
| children*** | 子元素 | `ReactNode` | `-` |
| className | 自定义类名 | `string` | `-` |
| triggerAll | 是否整个区域都触发 Tooltip,默认只有图标触发 | `boolean` | `-` |
---
url: /components/SearchForm.md
---
# SearchForm 搜索表单
响应式搜索表单组件,支持容器查询自适应布局、展开/收起功能。
## 安装
```sh [npx]
npx shadcn@latest add https://codebase.anyask.dev/r/search-form.json
```
```sh [yarn]
yarn dlx shadcn@latest add https://codebase.anyask.dev/r/search-form.json
```
```sh [pnpm]
pnpm dlx shadcn@latest add https://codebase.anyask.dev/r/search-form.json
```
```sh [bunx]
bunx shadcn@latest add https://codebase.anyask.dev/r/search-form.json
```
```sh [deno]
deno run npm:shadcn@latest npm:add https://codebase.anyask.dev/r/search-form.json
```
## 基础用法
```tsx file="/demos/components/SearchForm/basic.demo.tsx" preview
import React from 'react';
import { DatePicker, Form, Input } from 'antd';
import SearchForm from '@/components/SearchForm';
const Demo: React.FC = () => {
return (
console.log('Search:', values)} onReset={() => console.log('Reset')} maxCount={1}>
);
};
export default Demo;
```
## 响应式布局
组件使用 **容器查询** 实现响应式布局,根据父容器宽度自动调整列数。
| 容器宽度 | 列数 |
| --------- | --- |
| `<640px` | 1 列 |
| `≥640px` | 2 列 |
| `≥1024px` | 3 列 |
| `≥1280px` | 4 列 |
父容器需要设置 `container-type: inline-size` 才能生效容器查询。
### 最大列数
通过 `maxCols` prop 限制最大列数,默认 4 列。
```tsx file="/demos/components/SearchForm/max-cols.demo.tsx" preview
import React from 'react';
import { Form, Input, Select } from 'antd';
import SearchForm from '@/components/SearchForm';
const Demo: React.FC = () => {
return (
console.log('Search:', values)}>
);
};
export default Demo;
```
## 自定义操作按钮
通过 `actions` 属性自定义操作按钮区域。
```tsx file="/demos/components/SearchForm/custom-actions.demo.tsx" preview
import React from 'react';
import { Button, Form, Input } from 'antd';
import { SearchOutlined } from '@ant-design/icons';
import SearchForm from '@/components/SearchForm';
const Demo: React.FC = () => {
return (
);
};
export default Demo;
```
## 展开/收起
当表单项数量较多时,会自动显示展开/收起按钮。
```tsx file="/demos/components/SearchForm/collapsible.demo.tsx" preview
import React from 'react';
import { DatePicker, Form, Input, Select } from 'antd';
import SearchForm from '@/components/SearchForm';
const Demo: React.FC = () => {
return (
console.log('Search:', values)} maxCount={4}>
);
};
export default Demo;
```
## API
### [#](#searchform)SearchForm
| 属性 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| form | 表单实例,如果不传入则内部创建 | `FormInstance` | `-` |
| className | 表单的 className | `string` | `-` |
| maxCols | 最大列数,默认 4,范围 1-4 | `1 | 2 | 3 | 4` | `4` |
| maxCount | 最大显示数量 | `number` | `-` |
| defaultCollapsed | 默认是否收起,默认 true | `boolean` | `true` |
| collapsible | 是否显示展开/收起按钮 | `boolean` | `true` |
| resetText | 重置按钮文本 | `string` | `重置` |
| searchText | 查询按钮文本 | `string` | `查询` |
| onSearch | 表单提交回调 | `(values: Record) => void` | `-` |
| onReset | 表单重置回调 | `() => void` | `-` |
| renderActions | 自定义操作按钮区域 render 函数 | `(props: ActionsRenderProps) => ReactNode` | `-` |
| labelWidth | 标签宽度,默认 66 | `number` | `66` |
---
url: /components/UploadImage.md
---
# UploadImage 图片上传
支持多张图片上传的组件。
## 安装
```sh [npx]
npx shadcn@latest add https://codebase.anyask.dev/r/upload-image.json
```
```sh [yarn]
yarn dlx shadcn@latest add https://codebase.anyask.dev/r/upload-image.json
```
```sh [pnpm]
pnpm dlx shadcn@latest add https://codebase.anyask.dev/r/upload-image.json
```
```sh [bunx]
bunx shadcn@latest add https://codebase.anyask.dev/r/upload-image.json
```
```sh [deno]
deno run npm:shadcn@latest npm:add https://codebase.anyask.dev/r/upload-image.json
```
## 基础用法
```tsx pure
import { UploadImage } from '@/components/UploadImage';
function Demo() {
const [value, setValue] = useState([]);
return (
);
}
```
## 限制上传数量和大小
```tsx pure
function Demo() {
const [value, setValue] = useState([]);
return (
);
}
```
## 上传中回调
```tsx pure
function Demo() {
const [value, setValue] = useState([]);
const [uploading, setUploading] = useState(false);
return (
);
}
```
## API
### UploadImageProps
| 属性 | 说明 | 类型 | 默认值 |
| ----------- | ------------ | ---------------------------------------------------------------- | --- |
| value | 图片列表 | `Array<{ fileHash: string; fileName: string }>` | - |
| onChange | 变化回调 | `(value: Array<{ fileHash: string; fileName: string }>) => void` | - |
| maxCount | 图片最大个数 | `number` | `9` |
| fileSize | 图片大小限制(单位 M) | `number` | `5` |
| onUploading | 是否上传中的回调 | `(uploading: boolean) => void` | - |
继承 Ant Design [Upload](https://ant.design/components/upload-cn#api) 组件的其他属性(除 `value`、`onChange`、`accept`)。
---
url: /components/UploadMultiFile.md
---
# UploadMultiFile 多文件上传
支持多种文件类型上传的组件,可限制文件类型、数量和大小。
## 安装
```sh [npx]
npx shadcn@latest add https://codebase.anyask.dev/r/upload-multi-file.json
```
```sh [yarn]
yarn dlx shadcn@latest add https://codebase.anyask.dev/r/upload-multi-file.json
```
```sh [pnpm]
pnpm dlx shadcn@latest add https://codebase.anyask.dev/r/upload-multi-file.json
```
```sh [bunx]
bunx shadcn@latest add https://codebase.anyask.dev/r/upload-multi-file.json
```
```sh [deno]
deno run npm:shadcn@latest npm:add https://codebase.anyask.dev/r/upload-multi-file.json
```
## 基础用法
```tsx pure
import { UploadMultiFile } from '@/components/UploadMultiFile';
function Demo() {
const [value, setValue] = useState([]);
return (
);
}
```
## 限制文件类型
```tsx pure
function Demo() {
return (
);
}
```
## 自定义限制
```tsx pure
function Demo() {
return (
);
}
```
## 自定义按钮文案和帮助信息
```tsx pure
function Demo() {
return (
);
}
```
## 下载模板功能
```tsx pure
function Demo() {
return (
);
}
```
## API
### UploadMultiFileProps
| 属性 | 说明 | 类型 | 默认值 |
| ------------------------- | ------------ | ----------------------------------- | --------- |
| value | 文件列表 | `UploadFileInfo[]` | - |
| onChange | 变化回调 | `(value: UploadFileInfo[]) => void` | - |
| allowedTypes | 允许的文件类型 | `FileType[]` | `['all']` |
| maxCount | 文件最大个数 | `number` | `10` |
| fileSize | 文件大小限制(单位 M) | `number` | `10` |
| onUploading | 是否上传中的回调 | `(uploading: boolean) => void` | - |
| buttonText | 自定义按钮文案 | `string` | `'上传文件'` |
| help | 自定义帮助信息 | `ReactNode` | - |
| downloadTemplateSceneCode | 下载模板的场景代码 | `string` | - |
| downloadTemplateFileName | 下载模板的文件名 | `string` | - |
| downloadButtonText | 下载按钮的文案 | `string` | `'下载模板'` |
继承 Ant Design `Upload` 组件的其他属性(除 `value`、`onChange`、`accept`)。
### FileType
```ts pure
type FileType = 'image' | 'pdf' | 'excel' | 'word' | 'all';
```
### UploadFileInfo
| 属性 | 说明 | 类型 |
| -------- | ------- | -------- |
| fileHash | 文件 hash | `string` |
| fileName | 文件名 | `string` |
### FILE\_TYPE\_CONFIGS
预定义的文件类型配置:
| 类型 | MIME 类型 | 扩展名 | 显示名称 |
| ----- | ------------------------------------------------------------------------------------------- | ----------------- | ----- |
| image | image/jpeg, image/png | .jpg, .jpeg, .png | 图片 |
| pdf | application/pdf | .pdf | PDF |
| excel | application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel | .xlsx, .xls | Excel |
| word | application/vnd.openxmlformats-officedocument.wordprocessingml.document, application/msword | .docx, .doc | Word |
| all | - | - | 所有文件 |
---
url: /components/index.md
---
# Overview
## ~~Button 按钮~~
### [~~Button 按钮~~ ](/components/Button.md)
## QuestionTooltip 提示文本
### [QuestionTooltip 提示文本](/components/QuestionTooltip.md)
- [安装](/components/QuestionTooltip.md#安装)
- [基础用法](/components/QuestionTooltip.md#基础用法)
- [整个区域触发 Tooltip](/components/QuestionTooltip.md#整个区域触发-tooltip)
- [API](/components/QuestionTooltip.md#api)
## BoundaryBlock 边界区块
### [BoundaryBlock 边界区块](/components/BoundaryBlock.md)
- [安装](/components/BoundaryBlock.md#安装)
- [基础用法](/components/BoundaryBlock.md#基础用法)
- [尺寸](/components/BoundaryBlock.md#尺寸)
- [行内模式](/components/BoundaryBlock.md#行内模式)
- [骨架屏模式](/components/BoundaryBlock.md#骨架屏模式)
- [API](/components/BoundaryBlock.md#api)
## Descriptions 描述列表
### [Descriptions 描述列表](/components/Descriptions.md)
- [安装](/components/Descriptions.md#安装)
- [基础用法](/components/Descriptions.md#基础用法)
- [自定义渲染](/components/Descriptions.md#自定义渲染)
- [Features](/components/Descriptions.md#features)
- [API](/components/Descriptions.md#api)
## AsyncDescriptions 异步描述列表
### [AsyncDescriptions 异步描述列表](/components/AsyncDescriptions.md)
- [安装](/components/AsyncDescriptions.md#安装)
- [基础用法](/components/AsyncDescriptions.md#基础用法)
- [自定义头部渲染](/components/AsyncDescriptions.md#自定义头部渲染)
- [Features](/components/AsyncDescriptions.md#features)
- [API](/components/AsyncDescriptions.md#api)
## Image 图片
### [Image 图片](/components/Image.md)
- [安装](/components/Image.md#安装)
- [基础用法](/components/Image.md#基础用法)
- [自定义尺寸](/components/Image.md#自定义尺寸)
- [占位符与加载失败](/components/Image.md#占位符与加载失败)
- [API](/components/Image.md#api)
## ImageGroup 图片组
### [ImageGroup 图片组](/components/ImageGroup.md)
- [安装](/components/ImageGroup.md#安装)
- [基础用法](/components/ImageGroup.md#基础用法)
- [自定义图片尺寸](/components/ImageGroup.md#自定义图片尺寸)
- [限制显示数量](/components/ImageGroup.md#限制显示数量)
- [自定义间距](/components/ImageGroup.md#自定义间距)
- [API](/components/ImageGroup.md#api)
## HighlightText 文本高亮
### [HighlightText 文本高亮](/components/HighlightText.md)
- [安装](/components/HighlightText.md#安装)
- [基础用法](/components/HighlightText.md#基础用法)
- [自定义高亮样式](/components/HighlightText.md#自定义高亮样式)
- [API](/components/HighlightText.md#api)
## FilePreviewList 文件预览列表
### [FilePreviewList 文件预览列表](/components/FilePreviewList.md)
- [安装](/components/FilePreviewList.md#安装)
- [基础用法](/components/FilePreviewList.md#基础用法)
- [自定义显示名称](/components/FilePreviewList.md#自定义显示名称)
- [自定义配置](/components/FilePreviewList.md#自定义配置)
- [自定义接口](/components/FilePreviewList.md#自定义接口)
- [API](/components/FilePreviewList.md#api)
## AIFormFill AI 智能表单填写
### [AIFormFill AI 智能表单填写](/components/AIFormFill.md)
- [安装](/components/AIFormFill.md#安装)
- [基础用法](/components/AIFormFill.md#基础用法)
- [与 SearchForm 组合使用](/components/AIFormFill.md#与-searchform-组合使用)
- [自定义按钮](/components/AIFormFill.md#自定义按钮)
- [智能识别字段类型](/components/AIFormFill.md#智能识别字段类型)
- [API](/components/AIFormFill.md#api)
## SearchForm 搜索表单
### [SearchForm 搜索表单](/components/SearchForm.md)
- [安装](/components/SearchForm.md#安装)
- [基础用法](/components/SearchForm.md#基础用法)
- [响应式布局](/components/SearchForm.md#响应式布局)
- [自定义操作按钮](/components/SearchForm.md#自定义操作按钮)
- [展开/收起](/components/SearchForm.md#展开收起)
- [API](/components/SearchForm.md#api)
## AsyncSelect 异步选择器
### [AsyncSelect 异步选择器](/components/AsyncSelect.md)
- [安装](/components/AsyncSelect.md#安装)
- [基础用法](/components/AsyncSelect.md#基础用法)
- [远程搜索](/components/AsyncSelect.md#远程搜索)
- [允许空搜索](/components/AsyncSelect.md#允许空搜索)
- [数据依赖](/components/AsyncSelect.md#数据依赖)
- [全部选项](/components/AsyncSelect.md#全部选项)
- [API](/components/AsyncSelect.md#api)
## UploadImage 图片上传
### [UploadImage 图片上传](/components/UploadImage.md)
- [安装](/components/UploadImage.md#安装)
- [基础用法](/components/UploadImage.md#基础用法)
- [限制上传数量和大小](/components/UploadImage.md#限制上传数量和大小)
- [上传中回调](/components/UploadImage.md#上传中回调)
- [API](/components/UploadImage.md#api)
## UploadMultiFile 多文件上传
### [UploadMultiFile 多文件上传](/components/UploadMultiFile.md)
- [安装](/components/UploadMultiFile.md#安装)
- [基础用法](/components/UploadMultiFile.md#基础用法)
- [限制文件类型](/components/UploadMultiFile.md#限制文件类型)
- [自定义限制](/components/UploadMultiFile.md#自定义限制)
- [自定义按钮文案和帮助信息](/components/UploadMultiFile.md#自定义按钮文案和帮助信息)
- [下载模板功能](/components/UploadMultiFile.md#下载模板功能)
- [API](/components/UploadMultiFile.md#api)
## DownloadManager 下载管理
### [DownloadManager 下载管理](/components/DownloadManager.md)
- [安装](/components/DownloadManager.md#安装)
- [基础用法](/components/DownloadManager.md#基础用法)
- [自定义配置](/components/DownloadManager.md#自定义配置)
- [下载状态](/components/DownloadManager.md#下载状态)
- [API](/components/DownloadManager.md#api)
## Iframe 内嵌框架
### [Iframe 内嵌框架](/components/Iframe.md)
- [安装](/components/Iframe.md#安装)
- [基础用法](/components/Iframe.md#基础用法)
- [受控模式](/components/Iframe.md#受控模式)
- [自定义配置](/components/Iframe.md#自定义配置)
- [API](/components/Iframe.md#api)
## MultiButtonAction 多按钮操作
### [MultiButtonAction 多按钮操作](/components/MultiButtonAction.md)
- [安装](/components/MultiButtonAction.md#安装)
- [基础用法](/components/MultiButtonAction.md#基础用法)
- [自定义最大显示数量](/components/MultiButtonAction.md#自定义最大显示数量)
- [自动加载状态](/components/MultiButtonAction.md#自动加载状态)
- [排列方向](/components/MultiButtonAction.md#排列方向)
- [API](/components/MultiButtonAction.md#api)
---
url: /hello.md
---
# Hello world!
## Start
Write something to build your own docs! 🎁
---
url: /index.md
---
# Codebase Kit
构建你自己的组件库
> 开放代码 · 可组合 · 易分发 · 精致默认
[快速开始](/guide/get-started) | [github](https://github.com/web-infra-dev/rspress)
## Features
- 📖 **开放代码**: 组件的顶层代码完全开放,随时可修改。完全透明的实现让你可以完全掌控、自由定制和扩展,任何部分都能按需求改动。
- 🧩 **可组合性**: 所有组件共享一致、可组合的接口,行为可预期。统一的可组合接口让团队更容易上手,也方便 AI 工具理解和使用。
- 📦 **易于分发**: 基于扁平文件结构与 CLI,组件分发变得简单。你可以利用 schema 把组件分发到其他项目,或让 AI 基于既有 schema 生成全新的组件。
- ✨ **精致默认**: 默认样式经过精心打磨,开箱即用就很好看。统一的组件风格让 UI 自然协作,整体体验始终如一,同时保持轻松定制的能力。
- 🤖 **面向 AI**: 开放的代码与一致的 API 便于 AI 模型读取、理解。AI 可以学习组件的运作方式,提出改进建议,甚至创建与你现有设计完美融合的新组件。
- 🔷 **TypeScript 原生支持**: 完整的 TypeScript 类型定义,提供更好的开发体验和类型安全保障。让组件使用更加安全,IDE 智能提示更加准确。
---
url: /playground/corner-shape.md
---
# Corner Shape Playground
交互式体验 CSS border-radius 和 corner-shape 属性,探索 Superellipse 等高级圆角效果。
:::tip 提示
请使用 Chrome 139+ 或 Edge 139+ 浏览器查看最佳效果。Firefox 和 Safari 用户可能无法看到 Superellipse 效果。
:::
预览SML200×200Round显示网格显示辅助线说明##### Border Radius
设置元素的圆角半径。可以使用 px 或 % 作为单位。
##### Superellipse (N 值)
Superellipse 是一种数学曲线,通过调整 N 值可以控制角落的形状:
superellipse(-∞)**Notch**: 缺口角,带切口的形状superellipse(-1)**Scoop**: 凹角,向内凹陷的形状superellipse(0)**Bevel**: 斜角,使用直线切角superellipse(1)**Round**: 标准圆角superellipse(2)**Squircle**: 方圆形,介于圆形和方形之间superellipse(∞)**Square**: 完全方形N 值从 -∞ 到 +∞ 形成连续谱系,涵盖了从缺口到方形的各种角落形状
浏览器支持: Chrome 139+、 Edge 139+、 Firefox 不支持、Safari 实验性支持Border Radius同步单位px%圆角大小16pxSuperellipseN = 1N 值 (-10 到 10)-10-5-1012510精确输入重 置预设Notchsuperellipse(-∞)Scoopsuperellipse(-1)Bevelsuperellipse(0)Roundsuperellipse(1)Squirclesuperellipse(2)Squaresuperellipse(∞)生成的 CSS
````
/* 元素尺寸:200x200 */
border-radius: 16px;
/* Superellipse: Round */
corner-shape: superellipse(1);
````
---
url: /playground/css-anchor/annotations.md
---
# CSS Anchor 交互注释
使用 CSS Anchor Positioning 创建产品功能标注和代码注释,让内容更具交互性。
**预览**
产品功能标注超视网膜 XDR 显示屏6.9 英寸 OLED 全面屏,支持 ProMotion 自适应刷新率技术,峰值亮度 2000 尼特专业级相机系统4800 万像素主摄 + 超广角 + 5 倍长焦,支持 ProRAW 和 ProRes 视频拍摄A18 Pro 芯片最新一代仿生芯片,6 核 CPU + 6 核 GPU + 16 核神经网络引擎全天候续航最长可达 29 小时视频播放,支持 MagSafe 15W 无线快充超视网膜专业级相机系统A18全天候续航点击标注点或下方按钮查看功能详情代码行注释greeting.js1const greeting = (name) => {箭头函数定义,接收 name 参数2 const time = new Date().getHours();获取当前小时数(0-23)3 let message = '';初始化问候语变量4 5 if (time < 12) {判断是否为上午6 message = 'Good morning';7 } else if (time < 18) {判断是否为下午8 message = 'Good afternoon';9 } else {10 message = 'Good evening';11 }12 13 return `${message}, ${name}!`;模板字符串拼接问候语14};点击高亮行查看代码注释。注释框使用 CSS Anchor 精确定位到对应代码行。
**annotations.demo.tsx**
```tsx file="/demos/playground/css-anchor/annotations.demo.tsx" lineNumbers
import React, { useState } from 'react';
interface Annotation {
id: string;
x: number;
y: number;
title: string;
description: string;
color: 'blue' | 'emerald' | 'amber' | 'rose';
}
const productAnnotations: Annotation[] = [
{
id: 'screen',
x: 50,
y: 20,
title: '超视网膜 XDR 显示屏',
description: '6.9 英寸 OLED 全面屏,支持 ProMotion 自适应刷新率技术,峰值亮度 2000 尼特',
color: 'blue',
},
{
id: 'camera',
x: 25,
y: 15,
title: '专业级相机系统',
description: '4800 万像素主摄 + 超广角 + 5 倍长焦,支持 ProRAW 和 ProRes 视频拍摄',
color: 'emerald',
},
{
id: 'chip',
x: 50,
y: 55,
title: 'A18 Pro 芯片',
description: '最新一代仿生芯片,6 核 CPU + 6 核 GPU + 16 核神经网络引擎',
color: 'amber',
},
{
id: 'battery',
x: 50,
y: 75,
title: '全天候续航',
description: '最长可达 29 小时视频播放,支持 MagSafe 15W 无线快充',
color: 'rose',
},
];
const colorClasses = {
blue: { bg: 'bg-brand-5', ring: 'ring-brand-2', text: 'text-brand-6', cardBg: 'bg-brand-1', border: 'border-brand-3' },
emerald: { bg: 'bg-success', ring: 'ring-success-1', text: 'text-success', cardBg: 'bg-success-1', border: 'border-success-2' },
amber: { bg: 'bg-warning', ring: 'ring-warning-1', text: 'text-warning', cardBg: 'bg-warning-1', border: 'border-warning-2' },
rose: { bg: 'bg-error', ring: 'ring-error-1', text: 'text-error', cardBg: 'bg-error-1', border: 'border-error-2' },
};
function AnnotationPoint({ annotation, isActive, onClick }: { annotation: Annotation; isActive: boolean; onClick: () => void }) {
const colors = colorClasses[annotation.color];
const anchorName = `--anchor-point-${annotation.id}`;
const isOnLeft = annotation.x < 50;
return (
<>
{annotation.title}
{annotation.description}
>
);
}
function ProductShowcase() {
const [activeAnnotation, setActiveAnnotation] = useState('screen');
return (
{productAnnotations.map((annotation) => (
setActiveAnnotation(activeAnnotation === annotation.id ? null : annotation.id)}
/>
))}
{productAnnotations.map((annotation) => {
const colors = colorClasses[annotation.color];
return (
setActiveAnnotation(activeAnnotation === annotation.id ? null : annotation.id)}
className={`rd-full flex items-center gap-2 px-3 py-1.5 text-#242424! text-xs transition-all ${
activeAnnotation === annotation.id ? `${colors.cardBg} ${colors.border} border` : 'hover:bg-gray-1'
}`}
>
{annotation.title.split(' ')[0]}
);
})}
);
}
function CodeAnnotation() {
const [activeLines, setActiveLines] = useState([2]);
const codeLines = [
{ num: 1, code: 'const greeting = (name) => {', annotation: '箭头函数定义,接收 name 参数' },
{ num: 2, code: ' const time = new Date().getHours();', annotation: '获取当前小时数(0-23)' },
{ num: 3, code: " let message = '';", annotation: '初始化问候语变量' },
{ num: 4, code: ' ', annotation: null },
{ num: 5, code: ' if (time < 12) {', annotation: '判断是否为上午' },
{ num: 6, code: " message = 'Good morning';", annotation: null },
{ num: 7, code: ' } else if (time < 18) {', annotation: '判断是否为下午' },
{ num: 8, code: " message = 'Good afternoon';", annotation: null },
{ num: 9, code: ' } else {', annotation: null },
{ num: 10, code: " message = 'Good evening';", annotation: null },
{ num: 11, code: ' }', annotation: null },
{ num: 12, code: ' ', annotation: null },
{ num: 13, code: ' return `${message}, ${name}!`;', annotation: '模板字符串拼接问候语' },
{ num: 14, code: '};', annotation: null },
];
const toggleLine = (num: number) => {
setActiveLines((prev) => (prev.includes(num) ? prev.filter((n) => n !== num) : [...prev, num]));
};
return (
{codeLines.map((line) => {
const hasAnnotation = line.annotation !== null;
const isActive = activeLines.includes(line.num);
const anchorName = `--anchor-code-${line.num}`;
return (
{line.num}
hasAnnotation && toggleLine(line.num)}
>
{line.code}
{hasAnnotation && (
{line.annotation}
)}
);
})}
);
}
const Demo: React.FC = () => {
return (
代码行注释
点击高亮行查看代码注释。注释框使用 CSS Anchor 精确定位到对应代码行。
);
};
export default Demo;
```
## 核心特性
### 1. 产品功能标注
在产品图片上添加交互式标注点,点击后显示详细说明:
- 标注点使用 `ring` 和 `animate-ping` 实现呼吸效果
- 根据标注点位置(左/右)自动调整说明框方向
- 连接线精确指向标注点位置
```tsx
style={{
positionAnchor: `--anchor-point-${id}`,
...(isOnLeft
? { left: 'anchor(right)', translate: '16px -50%' }
: { right: 'anchor(left)', translate: '-16px -50%' }
),
top: 'anchor(center)',
positionTryFallbacks: 'flip-inline, flip-block',
}}
```
### 2. 代码行注释
为代码编辑器添加交互式注释功能:
- 点击可注释的代码行显示说明
- 注释框定位到代码行右侧
- 三角形箭头指向对应代码行
- 支持多行同时激活
```tsx
style={{
positionAnchor: `--anchor-code-${lineNum}`,
left: 'anchor(right)',
top: 'anchor(center)',
translate: '18px -50%',
positionTryFallbacks: 'flip-inline',
}}
```
### 3. 颜色系统
使用不同颜色区分不同类型的标注:
- 蓝色:显示屏相关
- 绿色:相机功能
- 黄色:性能芯片
- 红色:电池续航
## 应用场景
- **产品展示页面**:为产品图片添加功能标注
- **在线教程**:为代码添加分步说明
- **技术文档**:为示例代码添加详细注释
- **设计评审**:为设计稿添加批注
---
url: /playground/css-anchor/dropdown.md
---
# CSS Anchor 下拉菜单
使用 CSS Anchor Positioning 实现精准定位的下拉菜单,支持子菜单与自动翻转。
**预览**
基础下拉菜单文件操作新建文件⌘N新建文件夹⇧⌘N上传文件下载⌘S分享⌘⇧S复制链接删除⌘⌫用户菜单个人资料设置⌘,通知帮助中心退出登录嵌套子菜单显示选项视图列表视图网格视图画廊视图看板视图排序按名称按日期按大小按类型筛选全部文档图片视频悬停在菜单项上可以看到子菜单。子菜单使用 CSS Anchor 定位到父级菜单项的右侧。
**dropdown.demo.tsx**
```tsx file="/demos/playground/css-anchor/dropdown.demo.tsx" lineNumbers
/** biome-ignore-all lint/suspicious/noArrayIndexKey: */
import React, { useEffect, useRef, useState } from 'react';
import {
Bell,
Copy,
Download,
File,
Folder,
HelpCircle,
Layout,
LogOut,
Settings,
Share2,
Trash2,
Upload,
User,
} from 'lucide-react';
interface MenuItem {
icon: React.ReactNode;
label: string;
shortcut?: string;
danger?: boolean;
divider?: boolean;
}
const fileMenuItems: MenuItem[] = [
{ icon: , label: '新建文件', shortcut: '⌘N' },
{ icon: , label: '新建文件夹', shortcut: '⇧⌘N' },
{ divider: true, icon: null as any, label: '' },
{ icon: , label: '上传文件' },
{ icon: , label: '下载', shortcut: '⌘S' },
{ divider: true, icon: null as any, label: '' },
{ icon: , label: '分享', shortcut: '⌘⇧S' },
{ icon: , label: '复制链接' },
{ divider: true, icon: null as any, label: '' },
{ icon: , label: '删除', shortcut: '⌘⌫', danger: true },
];
const userMenuItems: MenuItem[] = [
{ icon: , label: '个人资料' },
{ icon: , label: '设置', shortcut: '⌘,' },
{ icon: , label: '通知' },
{ divider: true, icon: null as any, label: '' },
{ icon: , label: '帮助中心' },
{ icon: , label: '退出登录', danger: true },
];
function AnchorDropdown({
trigger,
items,
align = 'start',
}: {
trigger: React.ReactNode;
items: MenuItem[];
align?: 'start' | 'end';
}) {
const [isOpen, setIsOpen] = useState(false);
const id = useRef(`dropdown-${Math.random().toString(36).substr(2, 9)}`).current;
const anchorName = `--anchor-${id}`;
const dropdownRef = useRef(null);
const triggerRef = useRef(null);
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (
dropdownRef.current &&
!dropdownRef.current.contains(event.target as Node) &&
triggerRef.current &&
!triggerRef.current.contains(event.target as Node)
) {
setIsOpen(false);
}
};
if (isOpen) {
document.addEventListener('mousedown', handleClickOutside);
}
return () => document.removeEventListener('mousedown', handleClickOutside);
}, [isOpen]);
return (
setIsOpen(!isOpen)}
className="rd-lg inline-flex items-center gap-2 border border-gray-3 bg-white px-4 py-2 transition-colors hover:bg-gray-1 dark:border-[#424242] dark:bg-[#262626] dark:hover:bg-[#404040]"
style={{ anchorName } as React.CSSProperties}
>
{trigger}
{items.map((item, index) =>
item.divider ? (
) : (
setIsOpen(false)}
>
{item.icon}
{item.label}
{item.shortcut && {item.shortcut} }
),
)}
);
}
function NestedDropdown() {
const [isOpen, setIsOpen] = useState(false);
const [activeSubmenu, setActiveSubmenu] = useState(null);
const anchorName = '--anchor-nested-main';
const dropdownRef = useRef(null);
const triggerRef = useRef(null);
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (
dropdownRef.current &&
!dropdownRef.current.contains(event.target as Node) &&
triggerRef.current &&
!triggerRef.current.contains(event.target as Node)
) {
setIsOpen(false);
setActiveSubmenu(null);
}
};
if (isOpen) {
document.addEventListener('mousedown', handleClickOutside);
}
return () => document.removeEventListener('mousedown', handleClickOutside);
}, [isOpen]);
const mainItems = [
{ id: 'view', label: '视图', hasSubmenu: true },
{ id: 'sort', label: '排序', hasSubmenu: true },
{ id: 'filter', label: '筛选', hasSubmenu: true },
];
const submenus: Record = {
view: ['列表视图', '网格视图', '画廊视图', '看板视图'],
sort: ['按名称', '按日期', '按大小', '按类型'],
filter: ['全部', '文档', '图片', '视频'],
};
return (
setIsOpen(!isOpen)}
className="rd-lg inline-flex items-center gap-2 border border-gray-3 bg-white px-4 py-2 transition-colors hover:bg-gray-1 dark:border-[#424242] dark:bg-[#262626] dark:hover:bg-[#404040]"
style={{ anchorName } as React.CSSProperties}
>
显示选项
{mainItems.map((item) => (
setActiveSubmenu(item.id)}
>
{item.label}
setActiveSubmenu(null)}
>
{submenus[item.id].map((subItem, idx) => (
{
setIsOpen(false);
setActiveSubmenu(null);
}}
>
{subItem}
))}
))}
);
}
const Demo: React.FC = () => {
return (
基础下拉菜单
文件操作
>
}
items={fileMenuItems}
align="start"
/>
用户菜单
>
}
items={userMenuItems}
align="start"
/>
嵌套子菜单
悬停在菜单项上可以看到子菜单。子菜单使用 CSS Anchor 定位到父级菜单项的右侧。
);
};
export default Demo;
```
## 核心特性
### 1. 精确定位
下拉菜单使用 `anchor()` 函数精确定位到触发按钮的下方:
```tsx
style={{
positionAnchor: anchorName,
top: 'anchor(bottom)',
left: 'anchor(left)',
translate: '0 8px',
positionTryFallbacks: 'flip-block',
}}
```
### 2. 自动翻转
使用 `position-try-fallbacks: flip-block` 实现自动翻转。当菜单在视口底部溢出时,会自动翻转到按钮上方显示。
### 3. 嵌套子菜单
子菜单定位到父菜单项的右侧:
```tsx
style={{
positionAnchor: `--anchor-submenu-${item.id}`,
top: 'anchor(top)',
left: 'anchor(right)',
translate: '4px 0',
positionTryFallbacks: 'flip-inline',
}}
```
### 4. 点击外部关闭
使用 `useEffect` 监听点击事件,点击菜单外部时自动关闭。
## 实现要点
- 为每个下拉菜单生成唯一的锚点名称
- 使用 `useRef` 管理 DOM 引用
- 通过 `transition-all` 实现平滑的显示/隐藏动画
- 支持键盘快捷键显示(可选)
- 支持危险操作样式(如删除)
---
url: /playground/css-anchor/index.md
---
# CSS Anchor Positioning Playground
交互式体验 CSS Anchor Positioning API,学习如何使用原生 CSS 实现精确的锚点定位效果,无需 JavaScript 计算。
:::tip 浏览器支持
- **Chrome 125+** · 完全支持
- **Edge 125+** · 完全支持
- **Safari 26.0+** · 完全支持
- **Firefox 147+** · 完全支持
- **Opera 111+** · 完全支持
此组件使用 CSS [Anchor Positioning API](https://developer.chrome.com/blog/anchor-positioning-api)。如使用不支持此功能的浏览器,部分效果可能无法正常显示。
:::
## 什么是 CSS Anchor Positioning?
CSS Anchor Positioning API 是一个强大的新特性,让你能够将一个元素相对于另一个元素精确定位,无需 JavaScript:
- **`anchor-name`**: 为锚点元素命名
- **`position-anchor`**: 指定要锚定到哪个元素
- **`anchor()`**: 函数用于获取锚点元素的位置信息
- **`position-try-fallbacks`**: 自动处理视口溢出,切换备选位置
通过这些 CSS 属性,你可以实现工具提示、下拉菜单、链接预览等复杂的定位效果。
## 示例演示
### 精美的链接预览卡片
使用 CSS Anchor Positioning API 实现的优雅链接预览效果,鼠标悬停即可查看链接详情。预览卡片会自动相对于链接定位,并在空间不足时自动切换到合适的位置。
📖示例文章在现代 Web 开发中,[Next.js](https://nextjs.org)nextjs.orgNext.js by Vercel - The React FrameworkThe React Framework for the Web. Used by some of the world's largest companies, Next.js enables you to create high-quality web applications. 已经成为构建 React 应用的首选框架。它提供了服务端渲染、静态生成等强大功能。
样式方面,[Tailwind CSS](https://tailwindcss.com)tailwindcss.comTailwind CSS - Rapidly build modern websites without ever leaving your HTMLA utility-first CSS framework packed with classes that can be composed to build any design, directly in your markup. 提供了一套实用的工具类,让开发者能够快速构建精美的用户界面,而无需编写大量自定义 CSS。
对于组件库,[shadcn/ui](https://ui.shadcn.com)ui.shadcn.comshadcn/ui - Beautifully designed componentsBeautifully designed components that you can copy and paste into your apps. Accessible. Customizable. Open Source. 是一个绝佳选择,它提供了一套精心设计、高度可定制的组件,让你的应用既美观又易于维护。
如果你对人工智能感兴趣,[Vercel AI SDK](https://sdk.vercel.ai)sdk.vercel.aiVercel AI SDK - Build AI-powered applicationsThe AI Toolkit for TypeScript. Build AI-powered products with React, Next.js, Vue, Svelte, Node.js, and more. 可以帮助你轻松集成 AI 功能到你的应用中。
最后,别忘了关注 [GitHub](https://github.com)github.comGitHub: Let's build from hereGitHub is where over 100 million developers shape the future of software, together. Contribute to the open source community, manage your Git repositories. 上的开源项目,与全球开发者一起协作!
原生 CSS无需 JavaScript 计算位置,纯 CSS 实现锚点定位自动调整使用 position-try-fallbacks 自动避免视口溢出精确定位anchor() 函数提供精确的位置控制能力
:::details 展开查看源码
```tsx file="/demos/playground/css-anchor/link-preview.demo.tsx" pure lineNumbers
import React, { useState } from 'react';
interface LinkPreviewProps {
href: string;
title: string;
description: string;
image?: string;
domain?: string;
children: React.ReactNode;
}
const LinkPreview: React.FC = ({ href, title, description, image, domain, children }) => {
const [isHovered, setIsHovered] = useState(false);
const timeoutRef = React.useRef(null);
const anchorId = React.useId().replace(/:/g, '');
const anchorName = `--anchor-${anchorId}`;
const handleMouseEnter = () => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
timeoutRef.current = null;
}
setIsHovered(true);
};
const handleMouseLeave = () => {
timeoutRef.current = window.setTimeout(() => {
setIsHovered(false);
}, 150);
};
React.useEffect(() => {
return () => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
};
}, []);
return (
{children}
{image && (
{/*
*/}
)}
{domain || new URL(href).hostname}
{title}
{description}
);
};
const Demo: React.FC = () => {
return (
在现代 Web 开发中,
Next.js
{' '}
已经成为构建 React 应用的首选框架。它提供了服务端渲染、静态生成等强大功能。
样式方面,
Tailwind CSS
{' '}
提供了一套实用的工具类,让开发者能够快速构建精美的用户界面,而无需编写大量自定义 CSS。
对于组件库,
shadcn/ui
{' '}
是一个绝佳选择,它提供了一套精心设计、高度可定制的组件,让你的应用既美观又易于维护。
如果你对人工智能感兴趣,
Vercel AI SDK
{' '}
可以帮助你轻松集成 AI 功能到你的应用中。
最后,别忘了关注{' '}
GitHub
{' '}
上的开源项目,与全球开发者一起协作!
原生 CSS
无需 JavaScript 计算位置,纯 CSS 实现锚点定位
自动调整
使用 position-try-fallbacks 自动避免视口溢出
精确定位
anchor() 函数提供精确的位置控制能力
);
};
export default Demo;
```
:::
:::tip 💡 原理说明
**锚点定位核心**:
- 链接元素通过 `anchor-name: --anchor-{id}` 注册为锚点
- 预览卡片通过 `position-anchor: --anchor-{id}` 绑定到对应的链接
- 使用 `top: anchor(bottom)` 和 `left: anchor(center)` 精确定位到链接下方中央
- `position-try-fallbacks: flip-block, flip-inline` 自动处理视口溢出,在上下左右切换位置
**视觉效果**:
- 渐变背景遮罩层提升图片的可读性
- 平滑的透明度和缩放过渡效果,提升交互体验
- 响应式图片加载和文本截断,确保卡片布局稳定
- 纯 UnoCSS 实现,无需额外 CSS 文件
**优势**:
- 无需 JavaScript 计算位置,性能更优
- 自动处理滚动和视口变化
- 原生浏览器支持,代码更简洁
:::
***
## 核心特性
### 1. 原生 CSS 定位
无需 JavaScript 计算坐标,浏览器原生处理所有定位逻辑,性能更好,代码更简洁。
### 2. 自动位置调整
使用 `position-try-fallbacks` 自动检测视口边界,智能切换最佳显示位置,避免内容被裁剪。
### 3. 精确位置控制
`anchor()` 函数提供精细的位置控制,支持 `top`、`bottom`、`left`、`right`、`center` 等多种参考点。
***
## 实际应用场景
- **链接预览卡片**: 鼠标悬停显示链接摘要信息
- **工具提示 (Tooltip)**: 显示元素的说明文字
- **下拉菜单 (Dropdown)**: 相对于按钮定位菜单
- **弹出式选择器 (Popover)**: 日期选择器、颜色选择器等
- **上下文菜单**: 右键菜单定位
- **悬浮面板**: 编辑器工具栏、格式化面板等
***
## 参考资料
- [CSS Anchor Positioning - Chrome for Developers](https://developer.chrome.com/blog/anchor-positioning-api)
- [CSS Anchor Positioning - MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_anchor_positioning)
- [Can I Use: CSS Anchor Positioning](https://caniuse.com/css-anchor-positioning)
---
url: /playground/css-anchor/text-selection.md
---
# 文本选择工具栏
使用 CSS Anchor Positioning 实现类似 Medium 的文本选择工具栏,选中文本时自动显示格式化选项。
```tsx file="/demos/playground/css-anchor/text-selection.demo.tsx" preview lineNumbers
import React, { useEffect, useRef, useState } from 'react';
import { Bold, Copy, Highlighter, Italic, Link, Underline } from 'lucide-react';
function FloatingToolbar() {
const [showToolbar, setShowToolbar] = useState(false);
const textRef = useRef(null);
const selectionRef = useRef(null);
const [selectionRect, setSelectionRect] = useState(null);
useEffect(() => {
const handleSelection = () => {
const selection = window.getSelection();
if (selection?.toString().trim() && textRef.current?.contains(selection.anchorNode)) {
const range = selection.getRangeAt(0);
setSelectionRect(range.getBoundingClientRect());
setShowToolbar(true);
} else {
setShowToolbar(false);
}
};
document.addEventListener('mouseup', handleSelection);
return () => document.removeEventListener('mouseup', handleSelection);
}, []);
const actions = [
{ icon: , label: '加粗' },
{ icon: , label: '斜体' },
{ icon: , label: '下划线' },
{ icon: , label: '高亮' },
{ icon: , label: '链接' },
{ icon: , label: '复制' },
];
return (
选择下方文本试试
CSS Anchor Positioning API 是一个革命性的 CSS 特性,它允许开发者将一个元素精确地定位到另一个元素的相对位置。 这个 API
特别适合创建工具提示、下拉菜单、弹出框等需要相对定位的 UI 组件。
通过 anchor-name 属性定义锚点元素,然后使用 position-anchor 和 anchor() 函数来定位目标元素。 配合 position-try-fallbacks
可以实现智能的位置回退,确保内容始终在视口内可见。
{/* 隐藏的锚点标记 - 用于 anchor 定位 */}
{selectionRect && (
)}
{/* 浮动工具栏 */}
{/* 箭头 */}
{actions.map((action) => (
{action.icon}
))}
);
}
const Demo: React.FC = () => {
return (
);
};
export default Demo;
```
## 核心特性
### 1. 选区检测
使用 `window.getSelection()` API 检测文本选择:
```tsx
const handleSelection = () => {
const selection = window.getSelection();
if (selection && selection.toString().trim()) {
const range = selection.getRangeAt(0);
setSelectionRect(range.getBoundingClientRect());
setShowToolbar(true);
}
};
```
### 2. 动态锚点
因为选区位置是动态的,需要创建一个隐藏的锚点元素:
```tsx
```
### 3. 工具栏定位
工具栏定位到选区上方中央:
```tsx
style={{
positionAnchor: '--selection-anchor',
bottom: 'anchor(top)',
left: 'anchor(center)',
translate: '-50% -8px',
positionTryFallbacks: 'flip-block',
}}
```
### 4. 自动翻转
当选区在页面顶部时,工具栏会自动翻转到选区下方显示(通过 `flip-block`)。
## 实现要点
- 监听 `mouseup` 事件检测文本选择
- 使用 `getBoundingClientRect()` 获取选区位置
- 创建隐藏的锚点元素作为定位参考
- 工具栏包含常用的文本格式化操作
- 点击工具栏按钮不会导致选区消失
## 应用场景
- 富文本编辑器
- 在线文档协作工具
- 内容管理系统
- 笔记应用
---
url: /playground/diffs.md
---
#
# Diff 在线体验
代码差异对比在线体验,可以实时预览和配置代码差异展示效果。
Old CodeNew Code🔤 TypeScriptUnifiedSplit Word-AltLine NumbersBackgroundsWrappingLightDark🔄 Reset Sample🗑️ Clear All
---
url: /playground/scroll-mask.md
---
# Scroll Mask Playground
交互式体验 CSS scroll mask 效果,学习如何使用 animation-timeline 创建渐变遮罩效果。
:::tip 浏览器支持
- **Chrome 115+** · 完全支持
- **Edge 115+** · 完全支持
- **Safari** · 实验性支持(需启用功能标志)
- **Firefox** · 暂不支持
此组件使用 CSS [`animation-timeline`](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/animation-timeline) API 实现滚动驱动遮罩效果。如使用不支持此功能的浏览器,遮罩效果可能无法正常显示。
:::
垂直滚动 (通知列表)●系统维护通知系统将于今晚 02:00-06:00 进行例行维护5 分钟前✓新功能发布v2.5.0 版本已发布,包含暗色模式和性能优化1 小时前!安全警告检测到您的账户在新设备登录,请确认是否本人操作2 小时前●文档更新API 文档已更新,新增了批量操作接口说明3 小时前●周报提醒请在今天 18:00 前提交本周工作周报5 小时前●会议邀请产品需求评审会 - 会议室 A302昨天●代码审查PR #234 等待您的审查:用户权限模块重构昨天✕版本回滚由于兼容性问题,已回滚到 v2.4.8 版本2 天前●假期通知端午节放假安排:6月10日-12日,共3天3 天前✓活动结束「开发者成长计划」第一季活动已圆满结束1 周前✓系统升级服务器集群已升级至新版本,性能提升 30%1 周前●工单完成您的工单 #8732 已处理完成,请确认2 周前参数配置遮罩高度pxCSS 代码
````
.masked-overflow {
--mask-height: 80px;
mask-image: linear-gradient(to top, transparent, currentColor 90%),
linear-gradient(to bottom, transparent 0, currentColor 100%),
linear-gradient(currentColor, currentColor);
mask-size: 100% var(--top-mask-height),
100% var(--bottom-mask-height),
100% 100%;
animation-name: show-top-mask, hide-bottom-mask;
animation-timeline: scroll(self), scroll(self);
animation-range: 0 100%, 0 100%;
animation-fill-mode: both;
mask-position: 0 0, 0 100%, 0 0;
mask-repeat: no-repeat, no-repeat, no-repeat;
mask-composite: exclude;
}
@keyframes show-top-mask {
0% { --top-mask-height: 0px; }
to { --top-mask-height: var(--mask-height); }
}
@keyframes hide-bottom-mask {
0% { --bottom-mask-height: var(--mask-height); }
to { --bottom-mask-height: 0px; }
}
````
水平滚动 (标签云)ReactVueAngularSvelteNext.jsNuxtTypeScriptJavaScriptTailwind CSSUnoCSSViteWebpackNode.jsBunDenoGraphQLREST APIgRPCWebSocketWebRTCPWAElectronTauriRustGoPythonJavaKotlinSwift参数配置遮罩宽度pxCSS 代码
````
.masked-overflow-x {
--mask-width: 80px;
mask-image: linear-gradient(to left, transparent, currentColor 90%),
linear-gradient(to right, transparent, currentColor 100%),
linear-gradient(currentColor, currentColor);
mask-size: var(--left-mask-width) 100%,
var(--right-mask-width) 100%,
100% 100%;
animation-name: show-left-mask, hide-right-mask;
animation-timeline: scroll(self inline), scroll(self inline);
animation-range: 0 100%, 0 100%;
mask-position: 0 0, 100% 0, 0 0;
mask-repeat: no-repeat, no-repeat, no-repeat;
mask-composite: exclude;
}
@keyframes show-left-mask {
0% { --left-mask-width: 0px; }
to { --left-mask-width: var(--mask-width); }
}
@keyframes hide-right-mask {
0% { --right-mask-width: var(--mask-width); }
to { --right-mask-width: 0px; }
}
````
---
url: /playground/scroll-state.md
---
# Scroll State Playground
交互式体验 CSS `@container scroll-state()` 查询,学习如何使用纯 CSS 实现基于滚动状态的动态样式切换。
:::tip 浏览器支持
- **Chrome 133+** · 完全支持
- **Edge 133+** · 完全支持
- **Safari** · 暂不支持
- **Firefox** · 暂不支持
此组件使用 CSS [`@container scroll-state()`](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_conditional_rules/Container_scroll-state_queries) 容器查询。如使用不支持此功能的浏览器,部分效果可能无法正常显示。
:::
## 什么是 @container scroll-state()?
`@container scroll-state()` 是 CSS 容器查询的一种,可以根据滚动状态来应用不同的样式。它可以检测三种滚动状态:
- **`stuck`**: 使用 `position: sticky` 的元素被固定时
- **`scrollable`**: 元素可以向某个方向滚动时
- **`snapped`**: 使用 `scroll-snap-type` 的元素停靠完成时
通过这些查询,你可以实现很多以前需要 JavaScript 才能完成的滚动交互效果。
## 示例演示
### 1. 智能导航栏 (Stuck Navigation)
导航栏未吸顶时仅显示"联系我们"按钮,吸顶后所有菜单项平滑展开。
CSS Container Queries# scroll-state()
当导航栏吸附到视口顶部时,使用容器查询自动调整布局状态
- [公司简介](#)
- [制作事例](#)
- [人才招聘](#)
- [联系我们](#)
01## 公司简介
我们是一家专注于创新的科技公司,致力于为客户提供最优质的数字化解决方案。 自成立以来,我们始终秉承"创新、品质、服务"的理念,帮助众多企业实现数字化转型。
02## 制作事例
我们拥有丰富的项目经验,从企业官网到复杂的Web应用, 每一个项目都倾注了我们的专业与热情。 探索我们的作品集,了解我们如何帮助客户实现目标。
03## 人才招聘
我们正在寻找富有激情和创造力的伙伴加入我们的团队。 提供具有竞争力的薪酬、完善的福利体系和良好的职业发展机会。 让我们一起创造更多可能。
04## 联系我们
无论您有任何问题或需求,欢迎随时与我们联系。 我们的专业团队将为您提供及时的回复和最合适的解决方案。
/* Navigation */
.nav-container {
container-type: scroll-state;
}
/* Scroll-state Container Queries - 关键效果 */
@container not scroll-state(stuck: top) {
.nav-list {
grid-template-columns: 0 0 0 1fr;
width: 160px;
padding: 0 8px;
}
}
@container scroll-state(not stuck: top) {
.nav-link {
opacity: 1;
transition: opacity 0.2s;
}
}
:::details 展开查看源码
```tsx file="/demos/playground/scroll-state/stuck-navigation.demo.tsx" pure lineNumbers
import { ArrowRight, Briefcase, Building2, Users } from 'lucide-react';
const StuckNavigationDemo = () => {
return (
{/* Hero Section */}
CSS Container Queries
scroll-state()
当导航栏吸附到视口顶部时,使用容器查询自动调整布局状态
{/* Navigation Container with scroll-state container-type */}
{/* Content Sections */}
01
公司简介
我们是一家专注于创新的科技公司,致力于为客户提供最优质的数字化解决方案。
自成立以来,我们始终秉承"创新、品质、服务"的理念,帮助众多企业实现数字化转型。
02
制作事例
我们拥有丰富的项目经验,从企业官网到复杂的Web应用, 每一个项目都倾注了我们的专业与热情。
探索我们的作品集,了解我们如何帮助客户实现目标。
03
人才招聘
我们正在寻找富有激情和创造力的伙伴加入我们的团队。 提供具有竞争力的薪酬、完善的福利体系和良好的职业发展机会。
让我们一起创造更多可能。
04
联系我们
无论您有任何问题或需求,欢迎随时与我们联系。 我们的专业团队将为您提供及时的回复和最合适的解决方案。
);
};
export default StuckNavigationDemo;
```
:::
:::tip 💡 原理说明
使用 `container-type: scroll-state` 和 `position: sticky` 配合。未吸顶时,通过 `grid-template-columns: 0 0 0 1fr` 隐藏前三个导航项,仅显示"联系我们"。吸顶后,Grid 列恢复为 `1fr 1fr 1fr 1fr`,所有菜单项配合 `transition-delay` 依次展开,创造优雅的交互体验。这种模式特别适合需要精简导航的长页面。
:::
***
### 2. 图片轮播 (Snapped Carousel)
横向滚动图片轮播,滚动中的卡片缩小,停靠后恢复正常大小。
- ### 山川湖海
壮丽的自然风光
01
- ### 城市夜景
繁华都市之美
02
- ### 森林秘境
神秘的绿色世界
03
- ### 沙漠奇观
金色的沙海
04
- ### 极光之夜
梦幻的光影
05
.snapped-carousel-demo {
.carousel {
display: flex;
gap: 20px;
width: 100%;
max-width: 100%;
padding: 32px 20px;
margin: 0;
overflow-x: auto;
list-style: none;
scroll-snap-type: x mandatory;
scroll-behavior: smooth;
scrollbar-width: thin;
scrollbar-color: #d9d9d9 transparent;
}
.carousel::-webkit-scrollbar {
height: 10px;
}
.carousel::-webkit-scrollbar-track {
background: #f5f5f5;
border-radius: 5px;
}
.carousel::-webkit-scrollbar-thumb {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 5px;
}
.carousel::-webkit-scrollbar-thumb:hover {
background: linear-gradient(135deg, #5568d3 0%, #65408b 100%);
}
.carousel-item {
container-type: scroll-state;
flex: 0 0 auto;
width: 400px;
scroll-snap-align: center;
scroll-snap-stop: always;
}
.image-wrapper {
display: block;
width: 100%;
height: 100%;
}
.image-placeholder {
display: block;
width: 100%;
height: 280px;
overflow: hidden;
border-radius: 16px;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
transition: scale 0.3s;
transition-delay: 0.2s;
}
@container not scroll-state(snapped: inline) {
.image-placeholder {
scale: 0.85;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
transition-delay: 0s;
}
}
.image-content {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
padding: 32px;
color: white;
text-align: center;
}
.image-title {
margin: 0 0 12px 0;
font-size: 32px;
font-weight: 700;
text-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
}
.image-desc {
margin: 0;
font-size: 16px;
font-weight: 400;
opacity: 0.95;
text-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
}
.image-number {
position: absolute;
right: 24px;
bottom: 24px;
font-size: 72px;
font-weight: 800;
color: rgba(255, 255, 255, 0.15);
line-height: 1;
}
}
:::details 展开查看源码
```tsx file="/demos/playground/scroll-state/snapped-carousel.demo.tsx" pure lineNumbers
const SnappedCarouselDemo = () => {
const images = [
{ id: 1, title: '山川湖海', desc: '壮丽的自然风光', gradient: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)' },
{ id: 2, title: '城市夜景', desc: '繁华都市之美', gradient: 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)' },
{ id: 3, title: '森林秘境', desc: '神秘的绿色世界', gradient: 'linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)' },
{ id: 4, title: '沙漠奇观', desc: '金色的沙海', gradient: 'linear-gradient(135deg, #fa709a 0%, #fee140 100%)' },
{ id: 5, title: '极光之夜', desc: '梦幻的光影', gradient: 'linear-gradient(135deg, #30cfd0 0%, #330867 100%)' },
];
return (
{images.map((image) => (
{image.title}
{image.desc}
{String(image.id).padStart(2, '0')}
))}
);
};
export default SnappedCarouselDemo;
```
:::
:::tip 💡 原理说明
每个轮播项声明 `container-type: scroll-state`,父容器使用 `scroll-snap-type: x mandatory` 和 `scroll-snap-align: center` 实现横向停靠。图片默认正常大小,通过 `@container not scroll-state(snapped: inline)` 检测**未停靠**状态,滚动中缩小到 85%。`inline` 表示检测内联方向(横向)的停靠。停靠后添加 `transition-delay: 0.2s`,创造延迟恢复的优雅效果。适合图片画廊、产品展示等场景。
:::
***
## 核心概念
### container-type: scroll-state
这是使用滚动状态查询的前提,必须在容器元素上声明:
```css
.container {
container-type: scroll-state;
}
```
### stuck: 检测 sticky 固定状态
```css
@container scroll-state(stuck: top) {
/* 元素固定到顶部时的样式 */
}
```
方向值: `top`, `bottom`, `left`, `right`, `block-start`, `block-end`, `inline-start`, `inline-end`
### scrollable: 检测可滚动状态
```css
@container scroll-state(scrollable: top) {
/* 容器可以向上滚动时的样式 */
}
```
方向值: `top`, `bottom`, `left`, `right`, `block`, `inline`
### snapped: 检测停靠状态
```css
@container scroll-state(snapped: inline) {
/* 横向滚动停靠时的样式 */
}
```
方向值: `x`, `y`, `block`, `inline`
### not 查询: 检测相反状态
```css
@container not scroll-state(snapped: x) {
/* 未停靠时的样式 */
}
```
***
## 实战技巧
### 1. 负边距技巧
当 sticky 元素需要占据空间但又不影响初始布局时:
```css
.nav {
margin-top: -72px; /* 抵消导航栏高度 */
}
```
### 2. Grid 动态列
通过改变 Grid 列定义实现元素显隐:
```css
.nav-list {
grid-template-columns: 1fr 1fr 1fr 1fr; /* 吸顶时 */
}
@container not scroll-state(stuck: top) {
.nav-list {
grid-template-columns: 0 0 0 1fr; /* 未吸顶时隐藏前三列 */
}
}
```
### 3. 过渡延迟
为不同元素设置延迟,创造序列动画:
```css
.item {
transition: all 0.3s;
transition-delay: 0.2s; /* 停靠后延迟恢复 */
}
@container not scroll-state(snapped) {
.item {
transition-delay: 0s; /* 滚动中立即缩小 */
}
}
```
***
## 参考资料
- [@container scroll-state() - MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_conditional_rules/Container_scroll-state_queries)
- [CSS scroll-state() - Chrome for Developers](https://developer.chrome.com/blog/css-scroll-state-queries)
---
url: /playground/sibling-index.md
---
# Sibling Index Playground
交互式体验 CSS `sibling-index()` 和 `sibling-count()` 函数,学习如何使用兄弟元素索引创建动态样式效果。
:::tip 浏览器支持
- **Chrome 138+** · 完全支持
- **Edge 138+** · 完全支持
- **Safari 26.2+** · 完全支持
- **Firefox** · 暂不支持
此组件使用 CSS [`sibling-index()`](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/sibling-index) 和 [`sibling-count()`](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/sibling-count) 函数。如使用不支持此功能的浏览器,部分效果可能无法正常显示。
:::
## 什么是 sibling-index() 和 sibling-count()?
这两个 CSS 函数让你能够基于元素在兄弟元素中的位置和总数来动态计算样式值:
- **`sibling-index()`**: 返回元素在兄弟元素中的索引(从 1 开始)
- **`sibling-count()`**: 返回兄弟元素的总数(包括自身)
通过这两个函数,你可以实现很多以前需要 JavaScript 或手动编写 `:nth-child()` 选择器才能完成的效果。
## 示例演示
### 1. 交错动画 (Stagger Animation)
使用 `sibling-index()` 为每个元素设置递增的延迟时间,创建波浪式动画效果。Hover 卡片可翻转查看背面,点击「播放动画」重新触发动画。
**预览**
1✨2✨3✨4✨5✨6✨7✨8✨9✨10✨11✨12✨播放动画参数配置延迟时间ms旋转角度deg
**stagger-animation.demo.tsx**
```tsx file="/demos/playground/sibling-index/stagger-animation.demo.tsx" pure lineNumbers
import React, { useState } from 'react';
import { Button, InputNumber, Slider } from 'antd';
import '@demos/playground/sibling-index/stagger-animation.less';
const Demo: React.FC = () => {
const [staggerDelay, setStaggerDelay] = useState(50);
const [staggerRotate, setStaggerRotate] = useState(3);
const [animationKey, setAnimationKey] = useState(0);
const triggerAnimation = () => {
setAnimationKey((prev) => prev + 1);
};
return (
{Array.from({ length: 12 }).map((_, i) => {
const itemKey = `stagger-${animationKey}-${i}`;
return (
);
})}
播放动画
延迟时间
setStaggerDelay(val || 50)}
min={10}
max={200}
step={10}
size="small"
className="w-25"
suffix="ms"
/>
`${val}ms` }}
/>
旋转角度
setStaggerRotate(val || 3)}
min={0}
max={15}
step={1}
size="small"
className="w-25"
suffix="deg"
/>
`${val}deg` }}
/>
);
};
export default Demo;
```
**stagger-animation.less**
```less file="/demos/playground/sibling-index/stagger-animation.less" lineNumbers
.stagger-card {
width: 90px;
height: 90px;
perspective: 1000px;
opacity: 1;
transform: translateY(0) scale(1);
transition:
opacity 0.6s cubic-bezier(0.4, 0, 0.2, 1),
transform 0.6s cubic-bezier(0.4, 0, 0.2, 1);
transition-delay: calc((var(--item-index, 1) - 1) * var(--stagger-delay, 50) * 1ms);
&:hover .stagger-card-inner {
transform: rotateY(180deg);
}
}
@supports (animation-timeline: scroll()) {
@starting-style {
.stagger-card {
opacity: 0;
transform: translateY(20px) scale(0.8) rotate(calc((var(--item-index, 1) - 1) * var(--stagger-rotate, 3) * 1deg));
}
}
}
.stagger-card-inner {
position: relative;
width: 100%;
height: 100%;
transition: transform 0.6s;
transform-style: preserve-3d;
}
.stagger-card-front,
.stagger-card-back {
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden;
display: flex;
align-items: center;
justify-content: center;
border-radius: 16px;
font-weight: 700;
font-size: 1.75rem;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
}
.stagger-card-front {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}
.stagger-card-back {
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
color: white;
transform: rotateY(180deg);
}
```
:::tip 💡 原理说明
使用 `sibling-index()` 为每个卡片计算独立的 `transition-delay`,实现交错入场效果。结合 `@starting-style` 定义元素的初始状态(透明度为 0、向下偏移 20px、缩放 0.8、根据索引旋转),配合 `transition` 属性实现平滑过渡动画。3D 翻转效果通过 `perspective` + `preserve-3d` + `rotateY(180deg)` 实现,Hover 时卡片正反面翻转。
:::
***
### 2. 渐变文字效果 (Gradient Text)
结合 `oklch()` 颜色函数,根据元素索引自动生成渐变色文字和柱状图效果。
**预览**
SIBLINGINDEXMAGIC参数配置色相步进
**gradient-text.demo.tsx**
```tsx file="/demos/playground/sibling-index/gradient-text.demo.tsx" pure lineNumbers
import React, { useState } from 'react';
import { InputNumber, Slider } from 'antd';
import '@demos/playground/sibling-index/gradient-text.less';
const Demo: React.FC = () => {
const [hueStep, setHueStep] = useState(30);
const text = 'SIBLING INDEX MAGIC';
const chars = text.split('');
return (
{chars.map((char, i) => {
const charKey = char === ' ' ? `space-${hueStep}-${i}` : `char-${hueStep}-${i}-${char}`;
if (char === ' ') {
return
;
}
return (
{char}
);
})}
{Array.from({ length: 8 }, (_, i) => {
const barKey = `bar-${hueStep}-${i}`;
return (
);
})}
色相步进
setHueStep(val || 30)}
min={10}
max={60}
step={5}
size="small"
className="w-25"
/>
);
};
export default Demo;
```
**gradient-text.less**
```less file="/demos/playground/sibling-index/gradient-text.less" lineNumbers
.gradient-char {
font-size: 2rem;
font-weight: 900;
letter-spacing: 0.05em;
opacity: 1;
transform: translateY(0) scale(1);
transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1);
transition-delay: calc((var(--char-index, 1) - 1) * 30ms);
background: linear-gradient(
135deg,
oklch(70% 0.25 calc((var(--char-index, 1) - 1) * var(--hue-step, 30))),
oklch(60% 0.2 calc((var(--char-index, 1) - 1) * var(--hue-step, 30) + 60))
);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
text-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
&:hover {
transform: translateY(-4px) scale(1.2);
}
}
@supports (animation-timeline: scroll()) {
@starting-style {
.gradient-char {
opacity: 0;
transform: translateY(20px) scale(0.5);
}
}
}
.gradient-bars {
width: 100%;
max-width: 400px;
height: 80px;
align-items: flex-end;
}
.gradient-bar {
flex: 1;
min-width: 0;
border-radius: 8px 8px 0 0;
background: linear-gradient(
to top,
oklch(70% 0.25 calc((var(--bar-index, 1) - 1) * var(--hue-step, 30))),
oklch(80% 0.2 calc((var(--bar-index, 1) - 1) * var(--hue-step, 30) + 40))
);
height: calc(30px + (var(--bar-index, 1) * 6px));
opacity: 1;
transform: scaleY(1);
transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1);
transition-delay: calc((var(--bar-index, 1) - 1) * 50ms);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
&:hover {
transform: scaleY(1.1);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
}
}
@supports (animation-timeline: scroll()) {
@starting-style {
.gradient-bar {
opacity: 0;
transform: scaleY(0);
}
}
}
```
:::tip 💡 原理说明
使用 `sibling-index()` 为每个字符计算索引值,结合 `oklch()` 色彩空间,通过 `calc((var(--char-index) - 1) * var(--hue-step))` 计算色相值,实现基于位置的渐变色效果。`oklch()` 相比 `hsl()` 颜色过渡更自然均匀。文字渐变通过 `background-clip: text` + `-webkit-text-fill-color: transparent` 实现。柱状图的高度同样基于 `sibling-index()` 计算,配合 `@starting-style` 实现从底部升起的动画效果。
:::
***
### 3. 卡牌扇形布局 (Deck of Cards)
使用 `sibling-index()` 和 `sibling-count()` 计算每张卡片的旋转角度,实现手札般的扇形排列。删除卡片后,剩余卡片会自动重新计算位置。
**预览**
1CARD #1✕2CARD #2✕3CARD #3✕4CARD #4✕5CARD #5✕6CARD #6✕7CARD #7✕重置卡片Hover 卡片查看删除按钮,点击可删除,观察剩余卡片自动重排参数配置旋转步进角度deg
**deck-of-cards.demo.tsx**
```tsx file="/demos/playground/sibling-index/deck-of-cards.demo.tsx" pure lineNumbers
import React, { useState } from 'react';
import { Button, InputNumber, Slider } from 'antd';
import '@demos/playground/sibling-index/deck-of-cards.less';
const Demo: React.FC = () => {
const [cardRotateStep, setCardRotateStep] = useState(20);
const [cards, setCards] = useState([1, 2, 3, 4, 5, 6, 7]);
const removeCard = (index: number) => {
setCards(cards.filter((_, i) => i !== index));
};
const resetCards = () => {
setCards([1, 2, 3, 4, 5, 6, 7]);
};
return (
{cards.map((card, index) => (
removeCard(index)}
type="button"
aria-label="删除卡片"
>
✕
))}
重置卡片
Hover 卡片查看删除按钮,点击可删除,观察剩余卡片自动重排
旋转步进角度
setCardRotateStep(val || 20)}
min={10}
max={40}
step={5}
size="small"
className="w-25"
suffix="deg"
/>
`${val}deg` }}
/>
);
};
export default Demo;
```
**deck-of-cards.less**
```less file="/demos/playground/sibling-index/deck-of-cards.less" lineNumbers
.deck-cards {
position: relative;
}
.deck-card {
position: absolute;
width: 140px;
height: 200px;
left: 50%;
bottom: 0;
transform-origin: center bottom;
transform: translateX(-50%)
rotate(calc((var(--card-index, 1) - (var(--card-count, 7) + 1) / 2) * var(--card-rotate-step, 20) * 1deg))
translateY(-160px);
transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
cursor: pointer;
&:hover {
transform: translateX(-50%)
rotate(calc((var(--card-index, 1) - (var(--card-count, 7) + 1) / 2) * var(--card-rotate-step, 20) * 1deg))
translateY(-180px);
z-index: 10;
}
}
.deck-card-content {
width: 100%;
height: 100%;
background: linear-gradient(135deg, #fff 0%, #fafafa 100%);
border: 2px solid #e5e7eb;
border-radius: 16px;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
position: relative;
transition: all 0.3s ease;
overflow: hidden;
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: linear-gradient(90deg, #f093fb 0%, #f5576c 50%, #4facfe 100%);
}
.dark & {
background: linear-gradient(135deg, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0.4) 100%);
border-color: rgba(255, 255, 255, 0.15);
}
.deck-card:hover & {
border-color: #fa6323;
box-shadow: 0 12px 32px rgba(250, 99, 35, 0.3);
}
}
.deck-card-close {
position: absolute;
top: 12px;
right: 12px;
width: 28px;
height: 28px;
border-radius: 50%;
background: linear-gradient(135deg, #ff3325 0%, #ff5722 100%);
color: white;
border: none;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
font-weight: 700;
transition: transform 0.2s ease;
box-shadow: 0 2px 8px rgba(255, 51, 37, 0.3);
&:hover {
transform: scale(1.15) rotate(90deg);
}
}
```
:::tip 💡 原理说明
使用 `sibling-index()` 和 `sibling-count()` 计算每张卡片的旋转角度。
公式: `(sibling-index() - (sibling-count() + 1) / 2) * 角度`
中央卡片旋转 0°,左右对称展开,卡片数量变化时自动重新计算。例如 7 张卡片时:中央位置为第 4 张 = (7+1)/2,第 1 张旋转 -60deg,第 4 张旋转 0deg,第 7 张旋转 60deg。通过设置 `transform-origin: center bottom` 使卡片以底部中心为旋转轴,实现扇形展开效果。
:::
***
## 参考资料
- [sibling-index() - CSS | MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/sibling-index)
- [sibling-count() - CSS | MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/sibling-count)
- [ICS MEDIA: sibling-index() 活用アイデア](https://ics.media/entry/260116/)
---
url: /playground/unocss.md
---
# CSS to UnoCSS Playground
这是一个 CSS 属性到 UnoCSS 类名的转换工具。输入普通的 CSS 属性,即可获得对应的 UnoCSS 工具类。
输入 CSS 属性每行一个属性,格式: 属性名: 值
## 使用示例
### 文本居中
```css
text-align: center;
```
转换为: `text-center`
### Flexbox 布局
```css
display: flex;
justify-content: center;
align-items: center;
gap: 4px;
```
转换为: `flex justify-center items-center gap-1`
### 间距
```css
padding-top: 4px;
padding-bottom: 4px;
padding-left: 8px;
padding-right: 8px;
```
转换为: `pb-1 pl-2 pr-2 pt-1`
## 关于 UnoCSS
UnoCSS 是一个即时原子化 CSS 引擎,由 [Anthony Fu](https://github.com/antfu) 创建。它具有以下特点:
- **即时按需生成** - 只生成你实际使用的类
- **高性能** - 极快的构建速度
- **完全可定制** - 可以通过规则轻松扩展
- **智能预设** - 包含 Tailwind CSS 和 Windi CSS 的兼容预设
了解更多: [unocss.dev](https://unocss.dev/)
---
url: /prompts.md
---
Prompts## Categories
All Prompts30Code12Browser3Communication3Image2Writing4Music1Ideas1Fun1Misc3Code12Act as a natural language processing software. Analyze the given text and return me only a parsable and minified JSON object.
Here's the JSON Object structure:
part
Here are the rules you must follow:
- You MUST return a valid, parsable JSON object.
- More rules...
Code: part
Natural Language ProcessingConvert the following code into Tailwind CSS classes and give me the result in a code block. Make sure to remove any browser prefixes. Only give me what I can put into my HTML elements "class" properties.
Code: part
Tailwind CSS classes:
Convert CSS to Tailwind ClassesAct as a linux terminal. Execute the following code and reply with what the terminal should show. Only reply with the terminal output inside one unique code block, and nothing else. Do not write explanations.
Code: part
Terminal:
Linux TerminalAct as a part interpreter. Execute the part code and reply with the output. Do not provide any explanations.
Code: part
Output:
Code InterpreterTranslate the text to Git commands. Only reply one unique code block, and nothing else. Do not write explanations.
Text: part
Git commands:
Git CommandsGenerate a regular expression that match the specific patterns in the text. Return the regular expression in a format that can be easily copied and pasted into a regex-enabled text editor or programming language.
Text: part
Regex:
Regex GeneratorConvert the HTML code to Markdown.
HTML code: part
Markdown:
Convert HTML to MarkdownAct as a software engineer debugging its code. Add debug statements to the code. Add as many as necessary to make debugging easier.
Code: part
Debugged code:
Add Debug StatementsAs a software developer, I am currently working on a project using Jest, TypeScript, and React Testing Library. I would like you to help me generate unit tests for the given code.
Write Testsby Alireza SheikholmoloukiWrite a docstring for the function. Make sure the documentation is detailed.
Function: part
Docstring:
Write DocstringAct as a knowledgable unix server admin. Given a cronjob schedule in natural language, respond with the correct crontab format.
Schedule: part
Crontab:
Crontab GeneratorBe brutally honest, don't be a yes man. If I am wrong, point it out bluntly.
I need honest feedback on my code and provide brutally honest feedback.
Code: part
Review:
Code ReviewBrowser3Summarize the key points from the following web page content in a clear and concise manner.
Content: part
Summary:
Summarize Web PageExtract all the URLs and links from the following content. Format them as a clean list.
Content: part
Links:
Extract LinksTranslate the following content to part. Maintain the original formatting.
Content: part
Translation:
Translate PageCommunication3Write a professional email based on the following context.
Context: part
Email:
Write EmailWrite a thoughtful reply to the following email. Match the tone of the original message.
Original Email: part
Reply:
Reply to EmailCreate a structured meeting agenda based on the following topics.
Context: part
Agenda:
Create Meeting AgendaImage2Generate a detailed image generation prompt based on the following description.
Description: part
Image prompt:
Generate Image PromptProvide a detailed description of the image for accessibility purposes.
Image context: part
Description:
Describe ImageWriting4Improve the following text while maintaining its original meaning. Fix grammar, enhance clarity.
Text: part
Improved version:
Improve WritingMake the following text more concise while preserving the key information.
Text: part
Shorter version:
Make ShorterExpand the following text with more details, examples, and explanations.
Text: part
Expanded version:
Make LongerFix all spelling and grammar errors in the following text.
Text: part
Corrected text:
Fix Spelling & GrammarMusic1Analyze the following song lyrics. Explain the themes and literary devices.
Lyrics: part
Analysis:
Song Lyrics AnalysisIdeas1Generate creative ideas based on the following topic.
Topic: part
Ideas:
Brainstorm IdeasFun1Create funny jokes or puns based on the following topic.
Topic: part
Jokes:
Create JokesMisc3Explain the following concept in simple terms that a 5-year-old could understand.
Concept: part
Explanation:
Explain Like I'm 5Provide a concise summary of the following text.
Text: part
Summary:
Summarize TextCreate comprehensive study notes from the following content.
Content: part
Study Notes:
Create Study NotesCopied to clipboard
---
url: /quicklinks.md
---
# QuickLinks
快速导航,智能搜索。按 / 开始搜索
全部网站应用系统购物## 网站与开发
[### NPM
Node 包管理器
npmnodejavascript](https://www.npmjs.com)[### GitHub
代码托管平台
git代码仓库](https://github.com)[### GitLab
DevOps 平台
git代码devops](https://gitlab.com)[### MDN Web Docs
Web 开发文档
文档htmlcss](https://developer.mozilla.org)[### Can I Use
浏览器兼容性查询
兼容性浏览器css](https://caniuse.com)[### Stack Overflow
技术问答社区
问答技术编程](https://stackoverflow.com)[### Vercel
前端部署平台
部署托管nextjs](https://vercel.com)[### Netlify
静态网站托管
部署托管jamstack](https://www.netlify.com)[### Railway
全栈部署平台
部署后端数据库](https://railway.app)[### Supabase
Firebase 替代品
数据库postgresbackend](https://supabase.com)[### Prisma
Node.js ORM
ormdatabasetypescript](https://www.prisma.io)[### Docker Hub
容器镜像仓库
docker容器部署](https://hub.docker.com)[### TypeScript
TS 官方文档
typescript类型javascript](https://www.typescriptlang.org)[### React
React 官方文档
react前端ui](https://react.dev)[### Vue.js
Vue 官方文档
vue前端ui](https://vuejs.org)[### Next.js
Next.js 官方文档
nextjsreactssr](https://nextjs.org)[### Tailwind CSS
Tailwind 文档
tailwindcss样式](https://tailwindcss.com)[### shadcn/ui
UI 组件库
ui组件react](https://ui.shadcn.com)[### Ant Design
React UI 组件库
antduireact](https://ant.design)[### Vite
前端构建工具
vite构建打包](https://vite.dev)[### pnpm
高效的包管理器
pnpm包管理node](https://pnpm.io)[### Bun
JS 运行时
bunruntimejavascript](https://bun.sh)[### Deno
JS/TS 运行时
denoruntimetypescript](https://deno.land)[### Node.js
Node.js 官网
nodejavascript后端](https://nodejs.org)[### Rust
Rust 官方文档
rust系统编程语言](https://www.rust-lang.org)[### Go
Go 语言官网
gogolang后端](https://go.dev)[### Python
Python 官网
pythonai脚本](https://www.python.org)[### Regex101
正则表达式测试
正则测试工具](https://regex101.com)[### JSON Crack
JSON 可视化
json可视化工具](https://jsoncrack.com)[### Excalidraw
手绘风格白板
白板绘图协作](https://excalidraw.com)[### Figma
设计协作工具
设计ui协作](https://www.figma.com)[### Notion
笔记与协作
笔记协作知识库](https://www.notion.so)[### Linear
项目管理工具
项目任务协作](https://linear.app)[### Raycast
macOS 效率工具
效率macos启动器](https://www.raycast.com)[### Homebrew
macOS 包管理器
homebrewmacos包管理](https://brew.sh)[### DevDocs
API 文档聚合
文档api开发](https://devdocs.io)[### Bundlephobia
包体积查询
npm体积优化](https://bundlephobia.com)[### PageSpeed Insights
网页性能测试
性能优化seo](https://pagespeed.web.dev)[### Cloudflare
CDN 与安全
cdn安全dns](https://www.cloudflare.com)[### AWS Console
亚马逊云服务
aws云服务服务器](https://console.aws.amazon.com)[### ChatGPT
OpenAI 对话 AI
aichatgpt对话](https://chat.openai.com)[### Claude
Anthropic AI 助手
aiclaude对话](https://claude.ai)[### GitHub Copilot
AI 编程助手
ai编程github](https://github.com/features/copilot)[### Hugging Face
AI 模型平台
ai模型机器学习](https://huggingface.co)[### v0.dev
AI 生成 UI
aiui生成](https://v0.dev)[### Lucide Icons
开源图标库
图标iconsvg](https://lucide.dev)[### Huge Icons
海量图标库
图标iconsvg](https://hugeicons.com)[### Phosphor Icons
灵活图标库
图标iconsvg](https://phosphoricons.com)[### Iconify
统一图标框架
图标iconsvg](https://iconify.design)[### Heroicons
Tailwind 图标
图标icontailwind](https://heroicons.com)[### Feather Icons
简洁图标库
图标iconsvg](https://feathericons.com)[### Simple Icons
品牌 Logo 图标
图标logobrand](https://simpleicons.org)[### Icon Buddy
图标搜索引擎
图标icon搜索](https://iconbuddy.com)[### TinyPNG
图片压缩工具
压缩图片优化](https://tinypng.com)[### Tinify 中文版
图片压缩工具
压缩图片优化](https://tinify.cn)[### SVGO 在线版
SVG 压缩优化
svg压缩优化](https://www.zhangxinxu.com/sp/svgo)[### Squoosh
Google 图片压缩
压缩图片webp](https://squoosh.app)[### Remove.bg
智能抠图
抠图ai图片](https://www.remove.bg)[### Carbon
代码截图工具
截图代码分享](https://carbon.now.sh)[### Ray.so
代码截图美化
截图代码raycast](https://ray.so)[### Readme.so
README 生成器
readmemarkdown文档](https://readme.so)[### Shields.io
徽章生成器
徽章badgegithub](https://shields.io)[### Transform Tools
代码转换工具
转换jsontypescript](https://transform.tools)[### CodeImage
代码截图工具
截图代码分享](https://codeimage.dev)[### QuickType
JSON 转类型
jsontypescript类型](https://quicktype.io)[### JSON Formatter
JSON 格式化
json格式化工具](https://jsonformatter.org)[### Crontab Guru
Cron 表达式
cron定时工具](https://crontab.guru)[### Cubic Bezier
贝塞尔曲线
动画css曲线](https://cubic-bezier.com)[### CSS.GG
CSS 图标库
图标iconcss](https://css.gg)[### CSS Gradient
渐变生成器
渐变css工具](https://cssgradient.io)[### Coolors
配色方案生成
配色颜色设计](https://coolors.co)[### Color Hunt
配色灵感
配色颜色灵感](https://colorhunt.co)[### uiGradients
渐变配色
渐变配色css](https://uigradients.com)[### Neumorphism.io
新拟态生成器
新拟态css阴影](https://neumorphism.io)[### Glassmorphism
玻璃态生成器
玻璃态css模糊](https://hype4.academy/tools/glassmorphism-generator)[### Animista
CSS 动画库
动画css效果](https://animista.net)[### Haikei
SVG 背景生成
svg背景生成](https://haikei.app)[### PatternPad
图案生成器
图案背景设计](https://patternpad.com)[### Hero Patterns
SVG 背景图案
图案svg背景](https://heropatterns.com)[### Blob Maker
Blob 形状生成
blobsvg形状](https://www.blobmaker.app)[### Get Waves
波浪背景生成
波浪svg背景](https://getwaves.io)[### Shape Divider
分隔线生成
分隔svg背景](https://www.shapedivider.app)[### unDraw
开源插画库
插画svg免费](https://undraw.co)[### Storyset
动画插画库
插画动画免费](https://storyset.com)[### Unsplash
免费图片库
图片免费摄影](https://unsplash.com)[### Pexels
免费图片视频
图片视频免费](https://www.pexels.com)[### SVG Repo
50万+ 免费 SVG 图标
图标iconsvg](https://www.svgrepo.com)[### Tabler Icons
5000+ 免费描边图标
图标iconsvg](https://tabler.io/icons)[### Boxicons
1500+ 免费图标
图标iconsvg](https://boxicons.com)[### StackBlitz
在线 IDE (WebContainers)
ide在线开发](https://stackblitz.com)[### CodeSandbox
在线代码沙盒
沙盒在线开发](https://codesandbox.io)[### PlayCode
快速 JS/TS 预览
playgroundjavascripttypescript](https://playcode.io)[### AST Explorer
AST 在线解析
ast解析编译](https://astexplorer.net)[### JWT.io
JWT 解码/验证
jwt认证安全](https://jwt.io)[### LottieFiles
Lottie 动画库
动画lottie免费](https://lottiefiles.com)[### Shots.so
精美 Mockup 生成
mockup截图美化](https://shots.so)[### Perplexity
AI 搜索引擎
ai搜索问答](https://www.perplexity.ai)[### Phind
开发者 AI 搜索
ai搜索编程](https://www.phind.com)[### Cursor
AI 代码编辑器
aiide编辑器](https://cursor.sh)[### tldraw
无限画布白板
白板绘图协作](https://www.tldraw.com)[### Anime.js
JS 动画引擎
动画javascript库](https://animejs.com)[### DiceBear
头像生成器
头像avatar生成](https://www.dicebear.com/playground)[### Lordicon
动画图标库
图标动画lottie](https://lordicon.com)[### Animated Icons
动画图标集合
图标动画svg](https://animatedicons.co)[### Lucide Animated
Lucide 动画图标
图标iconlucide](https://lucide-animated.com)[### Central Icons
中心化图标库
图标svg免费](https://centralicons.com)[### Remix Icon
开源图标系统
图标开源svg](https://remixicon.com)[### Nucleo
专业图标库
图标icon专业](https://nucleoapp.com)[### Icônes
图标浏览器
图标icon搜索](https://icones.js.org)[### Heroicons Animated
Heroicons 动画图标
图标heroicons动画](https://www.heroicons-animated.com)## 应用与 URL Scheme
[### 微信扫一扫
App扫描二维码
微信扫码二维码](weixin://scanqrcode)[### 微信付款码
App出示付款码
微信付款支付](weixin://widget/pay)[### 微信朋友圈
App查看朋友圈
微信朋友圈社交](weixin://dl/moments)[### QQ
App打开 QQ
QQ聊天社交](mqq://)[### Telegram
App打开 Telegram
Telegram聊天消息](tg://)[### 钉钉扫一扫
App扫描二维码
钉钉扫码办公](dingtalk://dingtalkclient/page/scan)[### 飞书扫一扫
App扫描二维码
飞书扫码办公](feishu://applink.feishu.cn/client/qrcode/main)[### 飞书日历
App查看日历
飞书日历日程](feishu://applink.feishu.cn/client/calendar/open)[### 飞书任务
App查看任务
飞书任务待办](feishu://applink.feishu.cn/client/todo/open)[### 支付宝扫一扫
App扫描二维码
支付宝扫码支付](alipay://platformapi/startapp?appId=10000007)[### 支付宝付款码
App出示付款码
支付宝付款支付](alipay://platformapi/startapp?appId=20000056)[### 支付宝乘车码
App公交地铁乘车
支付宝乘车公交](alipay://platformapi/startapp?appId=200011235)[### 支付宝话费充值
App手机充值
支付宝充值话费](alipay://platformapi/startapp?saId=10000003)[### 云闪付扫一扫
App扫描二维码
云闪付扫码支付](upwallet://native/scanCode)[### 云闪付付款
App出示付款码
云闪付付款支付](upwallet://pay)[### 云闪付乘车码
App公交地铁乘车
云闪付乘车公交](upwallet://rn/rnshcarcode)[### 美团扫码
App扫描二维码
美团扫码](imeituan://www.meituan.com/scanQRCode)[### 美团付款码
App出示付款码
美团付款支付](imeituan://www.meituan.com/search?q=付款码)[### 美团打车
App叫车出行
美团打车出行](imeituan://www.meituan.com/cab/home)[### 菜鸟取件码
App显示取件身份码
菜鸟快递取件](cainiao://desktop/station_code)[### 哈啰扫码
App扫码骑车
哈啰单车骑行](hellobike://hellobike.com/scan_qr)[### 抖音搜索
App搜索视频内容
抖音视频搜索](snssdk1128://search/tabs?keyword=)[### 小红书搜索
App搜索笔记内容
小红书笔记搜索](xhsdiscover://search/recommend)[### 小红书扫一扫
App扫描二维码
小红书扫码](xhsdiscover://scan)[### 微博扫一扫
App扫描二维码
微博扫码](sinaweibo://qrcode)[### 知乎扫一扫
App扫描二维码
知乎扫码](zhihu://codereader)[### 哔哩哔哩
App打开 B 站首页
B站视频弹幕](bilibili://home)[### B站扫一扫
App扫描二维码
B站扫码](bilibili://qrcode)[### B站历史记录
App查看观看历史
B站历史记录](bilibili://user_center/history)[### 豆瓣扫一扫
App扫描二维码
豆瓣扫码](douban:///scan)[### 高德地图
App打开高德地图
高德地图导航](iosamap://)[### 百度地图
App打开百度地图
百度地图导航](baidumap://)[### 苹果地图
App打开 Apple Maps
苹果地图导航](maps://)[### 快捷指令
App打开快捷指令
快捷指令自动化效率](shortcuts://)[### Safari 搜索
App网页搜索
Safari浏览器搜索](x-web-search://)[### Spotify
App打开 Spotify
Spotify音乐流媒体](spotify://)[### 网易云音乐
App打开网易云
网易云音乐歌曲](orpheuswidget://)[### QQ音乐
App打开 QQ 音乐
QQ音乐音乐歌曲](qqmusic://)## 系统设置
[### Wi-Fi 设置
App无线网络配置
设置WiFi网络](App-prefs:WIFI)[### 蓝牙设置
App蓝牙设备管理
设置蓝牙设备](App-prefs:Bluetooth)[### 蜂窝网络
App移动数据设置
设置蜂窝流量](App-prefs:MOBILE_DATA_SETTINGS_ID)[### 显示与亮度
App屏幕显示设置
设置显示亮度](App-prefs:DISPLAY)[### 声音与触感
App铃声与振动
设置声音铃声](App-prefs:Sounds)[### 电池
App电池用量与健康
设置电池电量](App-prefs:BATTERY_USAGE)[### 通用设置
App系统通用设置
设置通用系统](App-prefs:General)[### 键盘设置
App键盘与输入法
设置键盘输入法](App-prefs:General&path=Keyboard)[### VPN 设置
AppVPN 配置
设置VPN网络](App-prefs:General&path=VPN)[### 储存空间
AppiPhone 储存空间
设置储存空间](App-prefs:General&path=STORAGE_MGMT)[### 关于本机
App设备信息
设置关于信息](App-prefs:General&path=About)[### 隐私与安全
App隐私设置
设置隐私安全](App-prefs:Privacy)[### 通知设置
App通知与提醒
设置通知提醒](App-prefs:NOTIFICATIONS_ID)[### 专注模式
App勿扰与专注
设置专注勿扰](App-prefs:DO_NOT_DISTURB)[### 屏幕使用时间
App使用时间统计
设置屏幕时间](App-prefs:SCREEN_TIME)[### 墙纸设置
App更换壁纸
设置墙纸壁纸](App-prefs:Wallpaper)## 购物与电商
[### 淘宝扫一扫
App扫码购物
淘宝扫码购物](taobao://tb.cn/n/scancode)[### 淘宝
App打开淘宝
淘宝购物电商](taobao://)[### 京东扫一扫
App扫码购物
京东扫码购物](openjd://virtual?params={"category":"jump","des":"saoasao"})[### 京东付款码
App出示付款码
京东付款支付](openjd://virtual?params={"category":"jump","des":"jdpaymentcode"})[### 京东订单
App查看我的订单
京东订单购物](openjd://virtual?params={"category":"jump","des":"orderlist"})[### 拼多多
App打开拼多多
拼多多购物拼团](pinduoduo://)按 / 聚焦搜索 • Esc 关闭
---
url: /template/basic-list.md
---
# 通用列表页
标准的数据列表页面模板,适用于各类管理后台的数据展示场景。
## 预览
```tsx file="/demos/template/basic-list.tsx" preview
import React from 'react';
import { Cascader, Form, message, Select, Table } from 'antd';
import { useAntdTable } from 'ahooks';
import { EasyButton, EasyText, PageView } from '@alife/alsc-ele-components';
import type { ColumnType } from 'antd/es/table';
import MultiButtonAction from '@/components/MultiButtonAction';
import SearchForm from '@/components/SearchForm';
import {
ActionButtonEnum,
ActionButtonMapping,
ContractStatusBadge,
ContractStatusEnum,
ContractStatusMapping,
} from '@/constants/contract';
import { buildPagination } from '@/utils/table';
interface DataItem {
id: number;
code: string;
name: string;
type: string;
city: string;
status: ContractStatusEnum;
validityPeriod: string;
btnList?: ActionButtonEnum[];
}
// Mock 类型选项
const mockTypeOptions = [
{ label: '类型A', value: 'TYPE_A' },
{ label: '类型B', value: 'TYPE_B' },
{ label: '类型C', value: 'TYPE_C' },
];
// Mock 城市列表(级联选择器示例)
const mockCityList = [
{
label: '浙江省',
value: '330000',
children: [
{ label: '杭州市', value: '330100' },
{ label: '宁波市', value: '330200' },
{ label: '温州市', value: '330300' },
],
},
{
label: '江苏省',
value: '320000',
children: [
{ label: '南京市', value: '320100' },
{ label: '苏州市', value: '320500' },
],
},
];
// Mock 区域选项
const mockAreaOptions = [
{ label: '区域A', value: 'AREA_A' },
{ label: '区域B', value: 'AREA_B' },
{ label: '区域C', value: 'AREA_C' },
];
/**
* 生成 Mock 列表数据
* @param pageNum 页码
* @param pageSize 每页条数
*/
const generateMockData = (pageNum: number, pageSize: number): DataItem[] => {
const startIndex = (pageNum - 1) * pageSize;
return Array.from({ length: pageSize }, (_, index) => {
const id = startIndex + index + 1;
const statusList = Object.values(ContractStatusEnum);
const status = statusList[id % statusList.length];
return {
id,
code: `CODE${String(id).padStart(6, '0')}`,
name: `数据项${String.fromCharCode(65 + (id % 26))}`,
type: mockTypeOptions[id % mockTypeOptions.length].label,
city: ['杭州市', '宁波市', '温州市', '南京市', '苏州市'][id % 5],
status,
validityPeriod: '2024-01-01 至 2025-12-31',
btnList: [ActionButtonEnum.VIEW, ActionButtonEnum.EDIT],
};
});
};
/**
* 合同管理页面
*/
const ContractManagement: React.FC = () => {
const [form] = Form.useForm();
/**
* 获取表格数据(Mock 实现)
* 实际使用时替换为真实 API 调用
*/
const fetchData = async (tableParams: { current: number; pageSize: number }, formValues: Record) => {
const { current, pageSize } = tableParams;
const { cityIds, ...rest } = formValues;
// 提取级联选择器的最后一级值
const extractedCityIds = cityIds?.map((arr: any[]) => arr[arr.length - 1]) || [];
console.log('搜索参数:', { cityIds: extractedCityIds, pageNum: current, pageSize, ...rest });
// 模拟网络请求延迟
await new Promise((resolve) => setTimeout(resolve, 300));
// 返回 Mock 数据
const mockData = generateMockData(current, pageSize);
return {
list: mockData,
total: 100,
};
};
const { tableProps, search } = useAntdTable(fetchData, {
form,
defaultPageSize: 10,
});
/**
* 搜索处理
*/
const handleSearch = () => {
search.submit();
};
/**
* 重置处理
*/
const handleReset = () => {
search.reset();
};
/**
* 新建操作
*/
const handleCreate = () => {
message.info('新建功能(待实现)');
};
/**
* 处理操作按钮点击
*/
const handleAction = (code: ActionButtonEnum, record: DataItem) => {
const actionMessages: Record = {
[ActionButtonEnum.VIEW]: `查看详情:${record.code}`,
[ActionButtonEnum.EDIT]: `编辑:${record.code}`,
};
message.info(actionMessages[code] || '操作功能(待实现)');
};
/**
* 表格列配置
*/
const columns: Array> = [
{
title: '编号',
dataIndex: 'code',
width: 120,
fixed: 'left',
},
{
title: '名称',
dataIndex: 'name',
width: 200,
render: (value: string) => {value} ,
},
{
title: '类型',
dataIndex: 'type',
width: 120,
},
{
title: '城市',
dataIndex: 'city',
width: 120,
},
{
title: '状态',
dataIndex: 'status',
width: 120,
render: (value: ContractStatusEnum) => ContractStatusBadge[value],
},
{
title: '有效期',
dataIndex: 'validityPeriod',
width: 220,
},
{
title: '操作',
key: 'actions',
fixed: 'right',
width: 120,
render: (_, record) => (
({
key: code,
label: ActionButtonMapping[code],
}))}
onAction={(code) => handleAction(code as ActionButtonEnum, record)}
/>
),
},
];
return (
新建
}
>
({
label,
value,
}))}
/>
);
};
export default ContractManagement;
```
### 枚举定义
:::details 展开查看
```tsx title="src/constants/contract.tsx"
import React from 'react';
import { Badge } from 'antd';
/** 状态枚举 */
export enum ContractStatusEnum {
/** 待处理 */
PENDING = 'PENDING',
/** 进行中 */
PROCESSING = 'PROCESSING',
/** 已完成 */
COMPLETED = 'COMPLETED',
}
/** 状态映射 */
export const ContractStatusMapping: Record = {
[ContractStatusEnum.PENDING]: '待处理',
[ContractStatusEnum.PROCESSING]: '进行中',
[ContractStatusEnum.COMPLETED]: '已完成',
};
/** 状态Badge映射 */
export const ContractStatusBadge: Record = {
[ContractStatusEnum.PENDING]: ,
[ContractStatusEnum.PROCESSING]: ,
[ContractStatusEnum.COMPLETED]: ,
};
/** 操作按钮枚举 */
export enum ActionButtonEnum {
/** 查看详情 */
VIEW = 'VIEW',
/** 编辑 */
EDIT = 'EDIT',
}
/** 操作按钮映射 */
export const ActionButtonMapping: Record = {
[ActionButtonEnum.VIEW]: '查看',
[ActionButtonEnum.EDIT]: '编辑',
};
```
:::
## 依赖组件
| 组件 | 用途 |
| ----------------- | ------------ |
| PageView | 页面布局容器 |
| SearchForm | 搜索表单组件 |
| EasyButton | 按钮组件 |
| EasyText | 文本组件(用于省略显示) |
| MultiButtonAction | 操作按钮组 |
| useAntdTable | 分页表格 Hook |
| buildPagination | 分页配置构建 |
## 功能特性
### 搜索表单
支持多种筛选控件:
- **Select** - 单选/多选下拉框(状态、类型、区域)
- **Cascader** - 级联选择器(城市)
- 支持搜索、清空、最大标签显示等常用功能
### 数据表格
- 固定列(编号、操作列固定左侧)
- 宽度自适应(scroll: x: 'max-content')
- 自定义渲染(状态 Badge、文字省略)
### 分页
- 使用 `useAntdTable` 实现
- 默认每页 10 条
- 与搜索表单联动
### 操作列
- 动态操作按钮(查看、编辑)
- 使用 `MultiButtonAction` 组件
## 使用说明
1. **修改字段** - 根据实际业务调整 `DataItem` 接口和列配置
2. **替换 Mock** - 将 `generateMockData` 替换为真实 API 调用
3. **完善操作** - 在 `handleAction` 中实现具体业务逻辑
4. **抽取枚举** - 将业务枚举抽取到 `src/constants/` 目录下
---
url: /template/common-detail/code.md
---
#
返回删 除编辑基本信息ID1名称项目 A状态进行中描述这是一个测试项目的详细描述信息创建时间2026-01-10 10:00:00更新时间2026-01-10 15:30:00
---
url: /template/common-detail/demo.md
---
#
返回删 除编辑基本信息ID1名称项目 A状态进行中描述这是一个测试项目的详细描述信息创建时间2026-01-10 10:00:00更新时间2026-01-10 15:30:00
---
url: /template/common-detail/index.md
---
# 通用详情页
标准的详情展示页面,包含头部操作区和详情内容区。
## 特性
- 返回按钮
- 操作按钮组
- 描述列表展示
- 分组信息卡片
## 依赖组件
- [BoundaryBlock](/components/BoundaryBlock.md) - 边界区块组件
- [Descriptions](/components/Descriptions.md) - 描述列表组件
## 在线预览
返回删 除编辑基本信息ID1名称项目 A状态进行中描述这是一个测试项目的详细描述信息创建时间2026-01-10 10:00:00更新时间2026-01-10 15:30:00
## 源码
返回删 除编辑基本信息ID1名称项目 A状态进行中描述这是一个测试项目的详细描述信息创建时间2026-01-10 10:00:00更新时间2026-01-10 15:30:00
## 使用说明
### 1. 复制代码
点击代码块右上角的复制按钮,将完整代码复制到你的项目中。
### 2. 自定义配置
根据你的实际需求修改:
- 描述字段配置
- 操作按钮
- 信息分组
- 返回逻辑
### 3. API 说明
#### CommonDetailProps
| 属性 | 说明 | 类型 | 默认值 |
| ---------------- | ------ | ------------------- | --- |
| detail | 详情数据 | `DetailItem` | - |
| descriptionItems | 描述字段配置 | `DescriptionItem[]` | - |
| onBack | 返回回调 | `() => void` | - |
| onEdit | 编辑回调 | `() => void` | - |
---
url: /template/common-list/index.md
---
# 通用列表页
标准的数据列表页面模板,适用于各类管理后台的数据展示场景。
## 依赖组件
| 组件 | 用途 |
| ----------------- | ------------ |
| PageView | 页面布局容器 |
| SearchForm | 搜索表单组件 |
| EasyButton | 按钮组件 |
| EasyText | 文本组件(用于省略显示) |
| MultiButtonAction | 操作按钮组 |
| useAntdTable | 分页表格 Hook |
| buildPagination | 分页配置构建 |
## 功能特性
### 搜索表单
支持多种筛选控件:
- **Select** - 单选/多选下拉框(状态、类型、区域)
- **Cascader** - 级联选择器(城市)
- 支持搜索、清空、最大标签显示等常用功能
### 数据表格
- 固定列(编号、操作列固定左侧)
- 宽度自适应(scroll: x: 'max-content')
- 自定义渲染(状态 Badge、文字省略)
### 分页
- 使用 `useAntdTable` 实现
- 默认每页 10 条
- 与搜索表单联动
### 操作列
- 动态操作按钮(查看、编辑)
- 使用 `MultiButtonAction` 组件
## 代码结构
## 使用说明
1. **修改字段** - 根据实际业务调整 `DataItem` 接口和列配置
2. **替换 Mock** - 将 `generateMockData` 替换为真实 API 调用
3. **完善操作** - 在 `handleAction` 中实现具体业务逻辑
4. **抽取枚举** - 将业务枚举抽取到 `src/constants/` 目录下
---
url: /template/drawer-detail/code.md
---
#
| ID | 名称 | 状态 | 创建时间 | 操作 |
| --- | --- | --- | --- | --- |
| 暂无数据暂无数据 |
---
url: /template/drawer-detail/demo.md
---
#
| ID | 名称 | 状态 | 创建时间 | 操作 |
| --- | --- | --- | --- | --- |
| 1 | 项目 A | 进行中 | 2026-01-10 | 查看详情 |
| 2 | 项目 B | 已完成 | 2026-01-09 | 查看详情 |
-
- [1](#)
-
---
url: /template/drawer-detail/index.md
---
# 抽屉详情区块组件
点击列表项的查看详情按钮,在侧边抽屉中展示完整的描述信息。
## 特性
- 侧边抽屉展示
- 描述列表组件
- 保持列表上下文
- 操作按钮组
## 依赖组件
- [BoundaryBlock](/components/BoundaryBlock.md) - 边界区块组件
- [Descriptions](/components/Descriptions.md) - 描述列表组件
## 在线预览
| ID | 名称 | 状态 | 创建时间 | 操作 |
| --- | --- | --- | --- | --- |
| 1 | 项目 A | 进行中 | 2026-01-10 | 查看详情 |
| 2 | 项目 B | 已完成 | 2026-01-09 | 查看详情 |
-
- [1](#)
-
## 源码
| ID | 名称 | 状态 | 创建时间 | 操作 |
| --- | --- | --- | --- | --- |
| 暂无数据暂无数据 |
## 使用说明
### 1. 复制代码
点击代码块右上角的复制按钮,将完整代码复制到你的项目中。
### 2. 自定义配置
根据你的实际需求修改:
- 描述字段配置
- 抽屉宽度
- 操作按钮
### 3. API 说明
#### DrawerDetailProps
| 属性 | 说明 | 类型 | 默认值 |
| ---------------- | ------ | ------------------- | ----- |
| columns | 表格列配置 | `Column[]` | - |
| dataSource | 数据源 | `DataItem[]` | - |
| descriptionItems | 描述字段配置 | `DescriptionItem[]` | - |
| drawerWidth | 抽屉宽度 | `number` | `600` |
---
url: /template/drawer-form/code.md
---
#
新增| ID | 名称 | 状态 | 操作 |
| --- | --- | --- | --- |
| 暂无数据暂无数据 |
---
url: /template/drawer-form/demo.md
---
#
新增| ID | 名称 | 状态 | 操作 |
| --- | --- | --- | --- |
| 1 | 项目 A | 进行中 | 编辑 |
| 2 | 项目 B | 已完成 | 编辑 |
-
- [1](#)
-
---
url: /template/drawer-form/index.md
---
# 抽屉表单组件
在侧边抽屉中进行表单编辑,保持列表上下文的同时提供编辑功能。
## 特性
- 侧边抽屉表单
- 支持新增和编辑
- 表单验证
- 保存取消操作
## 依赖组件
- [BoundaryBlock](/components/BoundaryBlock.md) - 边界区块组件
## 在线预览
新增| ID | 名称 | 状态 | 操作 |
| --- | --- | --- | --- |
| 1 | 项目 A | 进行中 | 编辑 |
| 2 | 项目 B | 已完成 | 编辑 |
-
- [1](#)
-
## 源码
新增| ID | 名称 | 状态 | 操作 |
| --- | --- | --- | --- |
| 暂无数据暂无数据 |
## 使用说明
### 1. 复制代码
点击代码块右上角的复制按钮,将完整代码复制到你的项目中。
### 2. 自定义配置
根据你的实际需求修改:
- 表单字段配置
- 表单验证规则
- 抽屉宽度
- API 接口
### 3. API 说明
#### DrawerFormProps
| 属性 | 说明 | 类型 | 默认值 |
| ---------- | ------ | ------------------ | --- |
| columns | 表格列配置 | `Column[]` | - |
| dataSource | 数据源 | `DataItem[]` | - |
| formItems | 表单字段配置 | `FormItem[]` | - |
| onSubmit | 提交回调 | `(values) => void` | - |
---
url: /template/drawer-list/code.md
---
#
| ID | 名称 | 状态 | 创建时间 | 操作 |
| --- | --- | --- | --- | --- |
| 暂无数据暂无数据 |
---
url: /template/drawer-list/demo.md
---
#
| ID | 名称 | 状态 | 创建时间 | 操作 |
| --- | --- | --- | --- | --- |
| 1 | 项目 A | 进行中 | 2026-01-10 | 查看 |
| 2 | 项目 B | 已完成 | 2026-01-09 | 查看 |
-
- [1](#)
-
---
url: /template/drawer-list/index.md
---
# 抽屉列表组件
点击列表项的查看按钮,从右侧弹出抽屉展示详细信息。
## 特性
- 侧边抽屉展示详情
- 保持列表上下文
- 支持抽屉内操作
- 响应式宽度
## 依赖组件
- [BoundaryBlock](/components/BoundaryBlock.md) - 边界区块组件
- [Descriptions](/components/Descriptions.md) - 描述列表组件
## 在线预览
| ID | 名称 | 状态 | 创建时间 | 操作 |
| --- | --- | --- | --- | --- |
| 1 | 项目 A | 进行中 | 2026-01-10 | 查看 |
| 2 | 项目 B | 已完成 | 2026-01-09 | 查看 |
-
- [1](#)
-
## 源码
| ID | 名称 | 状态 | 创建时间 | 操作 |
| --- | --- | --- | --- | --- |
| 暂无数据暂无数据 |
## 使用说明
### 1. 复制代码
点击代码块右上角的复制按钮,将完整代码复制到你的项目中。
### 2. 自定义配置
根据你的实际需求修改:
- 表格列定义
- 描述字段配置
- 抽屉宽度
- 操作按钮
### 3. API 说明
#### DrawerListProps
| 属性 | 说明 | 类型 | 默认值 |
| ---------------- | ------ | ------------------- | ----- |
| columns | 表格列配置 | `Column[]` | - |
| dataSource | 数据源 | `DataItem[]` | - |
| descriptionItems | 描述字段配置 | `DescriptionItem[]` | - |
| drawerWidth | 抽屉宽度 | `number` | `600` |
---
url: /template/drawer-step-form/code.md
---
#
新增| ID | 名称 | 状态 |
| --- | --- | --- |
| 暂无数据暂无数据 |
---
url: /template/drawer-step-form/demo.md
---
#
新增| ID | 名称 | 状态 |
| --- | --- | --- |
| 暂无数据暂无数据 |
---
url: /template/drawer-step-form/index.md
---
# 抽屉步骤表单组件
将复杂表单拆分为多个步骤,在抽屉中逐步填写,提升用户体验。
## 特性
- 分步表单设计
- 步骤指示器
- 上一步/下一步导航
- 每步独立验证
- 最后确认提交
## 依赖组件
- [BoundaryBlock](/components/BoundaryBlock.md) - 边界区块组件
## 在线预览
新增| ID | 名称 | 状态 |
| --- | --- | --- |
| 暂无数据暂无数据 |
## 源码
新增| ID | 名称 | 状态 |
| --- | --- | --- |
| 暂无数据暂无数据 |
## 使用说明
### 1. 复制代码
点击代码块右上角的复制按钮,将完整代码复制到你的项目中。
### 2. 自定义配置
根据你的实际需求修改:
- 步骤数量和内容
- 每步的表单字段
- 验证规则
- 步骤标题
### 3. API 说明
#### DrawerStepFormProps
| 属性 | 说明 | 类型 | 默认值 |
| ---------- | ---- | ------------------ | --- |
| steps | 步骤配置 | `StepConfig[]` | - |
| dataSource | 数据源 | `DataItem[]` | - |
| onSubmit | 提交回调 | `(values) => void` | - |
---
url: /template/index.md
---
# 模板库
这里提供了经过实战验证的业务模板,帮助你快速构建常见页面和功能。所有模板都遵循项目的设计规范,可直接复制使用。
## 模板列表
搜索分类全部标签暂无数据暂无匹配的模板
---
url: /template/tabs-list/code.md
---
#
名称状态请选择状态重 置查 询## 数据列表
新增全部进行中已完成| ID | 名称 | 状态 | 创建时间 | 操作 |
| --- | --- | --- | --- | --- |
| 暂无数据暂无数据 |
---
url: /template/tabs-list/demo.md
---
#
名称状态请选择状态重 置查 询## 数据列表
新增全部进行中已完成| ID | 名称 | 状态 | 创建时间 | 操作 |
| --- | --- | --- | --- | --- |
| 1 | 项目 A | 进行中 | 2026-01-10 | [查看](#) |
| 2 | 项目 B | 已完成 | 2026-01-09 | [查看](#) |
| 3 | 项目 C | 进行中 | 2026-01-08 | [查看](#) |
-
- [1](#)
-
- 10 条/页
---
url: /template/tabs-list/index.md
---
# 带 Tabs 的列表页
一个功能完整的列表页模板,集成了搜索表单、标签页切换和数据表格展示。
## 特性
- 响应式搜索表单,支持展开/收起
- 多标签页切换展示不同数据
- 数据表格支持分页、排序
- 完善的错误处理和加载状态
## 依赖组件
- [SearchForm](/components/SearchForm.md) - 搜索表单组件
- [BoundaryBlock](/components/BoundaryBlock.md) - 边界区块组件
## 在线预览
名称状态请选择状态重 置查 询## 数据列表
新增全部进行中已完成| ID | 名称 | 状态 | 创建时间 | 操作 |
| --- | --- | --- | --- | --- |
| 1 | 项目 A | 进行中 | 2026-01-10 | [查看](#) |
| 2 | 项目 B | 已完成 | 2026-01-09 | [查看](#) |
| 3 | 项目 C | 进行中 | 2026-01-08 | [查看](#) |
-
- [1](#)
-
- 10 条/页
## 源码
名称状态请选择状态重 置查 询## 数据列表
新增全部进行中已完成| ID | 名称 | 状态 | 创建时间 | 操作 |
| --- | --- | --- | --- | --- |
| 暂无数据暂无数据 |
## 使用说明
### 1. 复制代码
点击代码块右上角的复制按钮,将完整代码复制到你的项目中。
### 2. 自定义配置
根据你的实际需求修改:
- 表单字段配置
- 表格列定义
- API 接口地址
- 数据处理逻辑
- 标签页配置
### 3. API 说明
#### TabsListProps
| 属性 | 说明 | 类型 | 默认值 |
| ---------- | ----- | ------------------ | ------- |
| tabItems | 标签页配置 | `TabConfig[]` | - |
| columns | 表格列配置 | `Column[]` | - |
| dataSource | 数据源 | `DataItem[]` | - |
| onSearch | 搜索回调 | `(values) => void` | - |
| loading | 加载状态 | `boolean` | `false` |
---
url: /theme/color-palette.md
---
# Color Tokens
品牌色和语义化颜色 Token 系统,提供完整的色彩规范,包含品牌色、中性色以及多种语义色。
## 基础用法
:::tip
点击色块可复制 token 名称,每组颜色包含 10 个色阶(从浅到深)
:::
颜色转换工具BrandToken12345678910GrayToken123456789BlueToken12345678910CyanToken12345678910GeekblueToken12345678910GoldToken12345678910GreenToken12345678910LimeToken12345678910MagentaToken12345678910OrangeToken12345678910PurpleToken12345678910RedToken12345678910VolcanoToken12345678910YellowToken12345678910
## 设计规范
### 色阶系统
所有颜色均采用 10 级色阶系统,从浅色背景到深色文本,确保在不同场景下都有良好的视觉对比度:
- **Level 1-3**:浅色系,用于背景、强调区域
- **Level 4-6**:中等色,用于主要内容、交互元素
- **Level 7-10**:深色系,用于文本、标题、重要信息
### Brand(品牌色)
项目的主品牌色,用于表达品牌个性的橙色系。
| Token | 使用场景 |
| --------------------------- | --------- |
| **brand-1** \~ **brand-3** | 浅色背景、强调区域 |
| **brand-4** \~ **brand-6** | 品牌按钮、主要内容 |
| **brand-7** \~ **brand-10** | 深色文本、标题 |
### Gray(中性色)
用于表达中性状态的灰色系,包含 9 个色阶(使用 rgba 透明度)。
| Token | 使用场景 |
| ------------------------ | --------- |
| **gray-1** \~ **gray-3** | 背景色、分割线 |
| **gray-4** \~ **gray-6** | 次要文本、禁用状态 |
| **gray-7** \~ **gray-9** | 主要文本、标题 |
### 语义色系
系统提供多种语义化颜色,用于不同的功能和场景:
| 颜色 | 用途 |
| ------------ | ---------- |
| **Blue** | 信息、链接、主要操作 |
| **Cyan** | 科技、清新风格 |
| **Geekblue** | 技术感、深蓝色调 |
| **Gold** | 警告、VIP 标识 |
| **Green** | 成功、安全状态 |
| **Lime** | 清新、活力风格 |
| **Magenta** | 时尚、女性向 |
| **Orange** | 警告、注意状态 |
| **Purple** | 高端、神秘感 |
| **Red** | 错误、危险状态 |
| **Volcano** | 强调、火山橙 |
| **Yellow** | 警示、提示状态 |
## 使用建议
### 选择合适的色阶
```tsx pure
// 背景色使用浅色阶
信息卡片
// 按钮使用中等色阶
主要按钮
// 文本使用深色阶
次要文本
主要文本
```
### 颜色搭配
- **单一色调**:使用同一颜色的不同色阶,保持视觉统一
- **对比色**:使用互补色(如 Blue + Orange)突出重点
- **品牌色 + 中性色**:品牌色用于强调,中性色用于主体内容
### 注意事项
1. **可读性优先**:确保文本与背景有足够的对比度
2. **保持克制**:避免使用过多颜色,保持视觉简洁
3. **语义一致**:相同功能使用相同颜色,保持用户体验一致
4. **深色模式**:在深色模式下需要调整颜色使用方案
---
url: /theme/font-tokens.md
---
# Font Tokens
字号 Token 系统,定义了不同层级的文字大小、行高和字重,提供清晰的信息层级和一致的视觉体验。
## 基础用法
:::tip
点击卡片可复制 token 名称
:::
text-3xlMedium600示例文本 The quick brown foxFont Size30pxLine Height38px点击复制text-2xlMedium600示例文本 The quick brown foxFont Size24pxLine Height32px点击复制text-xlMedium600示例文本 The quick brown foxFont Size20pxLine Height28px点击复制text-lgMedium600示例文本 The quick brown foxFont Size18pxLine Height26px点击复制text-base-mMedium600示例文本 The quick brown foxFont Size16pxLine Height24px点击复制text-baseRegular400示例文本 The quick brown foxFont Size16pxLine Height24px点击复制text-sm-mMedium600示例文本 The quick brown foxFont Size14pxLine Height22px点击复制text-smRegular400示例文本 The quick brown foxFont Size14pxLine Height22px点击复制text-xsRegular400示例文本 The quick brown foxFont Size12pxLine Height20px点击复制
## 设计规范
### 字号层级
系统提供 9 个字号层级,从 `text-xs` (12px) 到 `text-3xl` (30px),满足各种使用场景:
| Token | Font Size | Line Height | Font Weight | 使用场景 |
| --------------- | --------- | ----------- | ----------- | ---------- |
| **text-3xl** | 30px | 38px | 600 | 特大标题、页面主标题 |
| **text-2xl** | 24px | 32px | 600 | 大标题、区块标题 |
| **text-xl** | 20px | 28px | 600 | 中标题、卡片标题 |
| **text-lg** | 18px | 26px | 600 | 小标题、副标题 |
| **text-base-m** | 16px | 24px | 600 | 中等正文、强调文本 |
| **text-base** | 16px | 24px | 400 | 常规正文、默认文本 |
| **text-sm-m** | 14px | 22px | 600 | 中等小字、辅助说明 |
| **text-sm** | 14px | 22px | 400 | 小字、次要信息 |
| **text-xs** | 12px | 20px | 400 | 特小字、标签文本 |
### 字重系统
- **Medium (600)**:用于标题和需要强调的文本
- **Regular (400)**:用于正文和常规文本
## 使用建议
1. **标题层级**:根据内容重要性选择合适的标题层级
2. **字重搭配**:同尺寸下使用不同字重来区分强调程度
3. **行高设置**:确保良好的阅读体验,避免行高过小导致文字拥挤
4. **响应式考虑**:在小屏幕设备上适当减小字号
---
url: /theme/functional-colors.md
---
# Functional Colors
功能色 Token 系统,用于表达不同状态的语义化颜色,包括错误、警告和成功三种状态,每个状态包含 5 个色阶。
## 基础用法
:::tip
点击色块可复制 token 名称,每个状态包含 5 个色阶(从浅到深)
:::
ErrorToken12345WarningToken12345SuccessToken12345
## 色阶系统
功能色采用 5 级色阶系统,从浅色背景到深色文本,确保在不同场景下都有良好的视觉对比度:
- **Level 1**:最浅色,用于背景色和强调区域
- **Level 2**:浅色,用于边框、分隔线等
- **Level 3**:中等色,用于主要内容
- **Level 4**:深色,用于文本和图标
- **Level 5**:最深色,用于标题和重要信息
:::info 简化形式
Level 3(默认色级)可使用简化形式的 token:
- **error-3** 可简写为 **error**
- **warning-3** 可简写为 **warning**
- **success-3** 可简写为 **success**
例如:`bg-error-3` 等同于 `bg-error`
:::
## 颜色规范
### Error(错误色)
用于表达错误、失败、危险等负面状态的红色系。
| Token | Value | 使用场景 |
| ----------------------- | ------- | ----------- |
| **error-1** | #fff3f0 | 错误提示背景、浅色区域 |
| **error-2** | #ffb0a1 | 错误图标、浅色边框 |
| **error-3** / **error** | #ff3325 | 错误按钮、主要错误信息 |
| **error-4** | #d91c16 | 错误文本、深色内容 |
| **error-5** | #b30909 | 错误标题、重要错误提示 |
### Warning(警告色)
用于表达警告、注意等中性状态的橙色系。
| Token | Value | 使用场景 |
| --------------------------- | ------- | ----------- |
| **warning-1** | #fff8e6 | 警告提示背景、浅色区域 |
| **warning-2** | #ffd37a | 警告图标、浅色边框 |
| **warning-3** / **warning** | #ff9100 | 警告按钮、主要警告信息 |
| **warning-4** | #d97400 | 警告文本、深色内容 |
| **warning-5** | #b35900 | 警告标题、重要警告提示 |
### Success(成功色)
用于表达成功、完成等正面状态的绿色系。
| Token | Value | 使用场景 |
| --------------------------- | ------- | ----------- |
| **success-1** | #dff7eb | 成功提示背景、浅色区域 |
| **success-2** | #6adeac | 成功图标、浅色边框 |
| **success-3** / **success** | #00b87a | 成功按钮、主要成功信息 |
| **success-4** | #009166 | 成功文本、深色内容 |
| **success-5** | #006b4f | 成功标题、重要成功提示 |
## 使用建议
### 选择合适的色阶
```tsx pure
// 背景色使用 Level 1
错误提示框
// 边框使用 Level 2
警告信息
// 按钮使用 Level 3(可使用简化形式)
确认
确认 // 等同于上面的写法
// 文本使用 Level 4 或 Level 5
错误文本
重要错误
```
### 状态图标
```tsx pure
// 成功图标
// 警告图标
// 错误图标
```
---
url: /theme/index.md
---
# Overview
## Color Tokens
### [Color Tokens](/theme/color-palette.md)
- [基础用法](/theme/color-palette.md#基础用法)
- [设计规范](/theme/color-palette.md#设计规范)
- [使用建议](/theme/color-palette.md#使用建议)
## Font Tokens
### [Font Tokens](/theme/font-tokens.md)
- [基础用法](/theme/font-tokens.md#基础用法)
- [设计规范](/theme/font-tokens.md#设计规范)
- [使用建议](/theme/font-tokens.md#使用建议)
## Radius Tokens
### [Radius Tokens](/theme/radius-tokens.md)
- [基础用法](/theme/radius-tokens.md#基础用法)
- [设计规范](/theme/radius-tokens.md#设计规范)
- [设计建议](/theme/radius-tokens.md#设计建议)
- [嵌套圆角最佳实践](/theme/radius-tokens.md#嵌套圆角最佳实践)
## Shadow Tokens
### [Shadow Tokens](/theme/shadows-tokens.md)
- [基础用法](/theme/shadows-tokens.md#基础用法)
- [设计规范](/theme/shadows-tokens.md#设计规范)
- [使用建议](/theme/shadows-tokens.md#使用建议)
- [注意事项](/theme/shadows-tokens.md#注意事项)
## Functional Colors
### [Functional Colors](/theme/functional-colors.md)
- [基础用法](/theme/functional-colors.md#基础用法)
- [色阶系统](/theme/functional-colors.md#色阶系统)
- [颜色规范](/theme/functional-colors.md#颜色规范)
- [使用建议](/theme/functional-colors.md#使用建议)
## Shortcuts
### [Shortcuts](/theme/shortcuts-tokens.md)
- [注意事项](/theme/shortcuts-tokens.md#注意事项)
---
url: /theme/radius-tokens.md
---
# Radius Tokens
圆角 Token 系统,定义了不同层级的圆角大小,为界面元素提供统一且柔和的视觉效果。
## 基础用法
:::tip
点击卡片可复制 token 名称
:::
rounded-xs2pxPreviewBorder Radius2pxrounded-sm4pxPreviewBorder Radius4pxrounded8pxPreviewBorder Radius8pxrounded-md8pxPreviewBorder Radius8pxrounded-lg12pxPreviewBorder Radius12pxrounded-xl16pxPreviewBorder Radius16pxrounded-full9999pxPreviewBorder Radius9999px
## 设计规范
### 圆角层级
系统提供 7 个圆角层级,从极小圆角 (2px) 到完全圆角 (9999px),适用于各种 UI 元素:
| Token | Value | 使用场景 |
| ---------------- | ------ | ----------------- |
| **rounded-xs** | 2px | 极小圆角,用于细微的边角处理 |
| **rounded-sm** | 4px | 小圆角,用于标签、徽章等小元素 |
| **rounded** | 8px | 默认圆角,用于卡片、按钮等常规元素 |
| **rounded-md** | 8px | 中等圆角,与 rounded 相同 |
| **rounded-lg** | 12px | 大圆角,用于较大的卡片和容器 |
| **rounded-xl** | 16px | 超大圆角,用于弹窗、模态框等 |
| **rounded-full** | 9999px | 完全圆角,用于头像、圆形按钮 |
### 使用指南
1. **保持一致性**:同一类型的元素应使用相同的圆角值
2. **层级关系**:圆角大小应与元素尺寸成正比
3. **视觉平衡**:过大的圆角在矩形元素上可能显得突兀
## 设计建议
### 选择合适的圆角
- **小元素** (按钮、标签):使用 `rounded-sm` 或 `rounded`
- **中等元素** (卡片、面板):使用 `rounded` 或 `rounded-lg`
- **大元素** (弹窗、容器):使用 `rounded-lg` 或 `rounded-xl`
- **圆形元素** (头像、图标):使用 `rounded-full`
### 组合使用
```tsx pure
// 按钮使用默认圆角
按钮
// 卡片使用大圆角
卡片内容
// 头像使用完全圆角
```
## 嵌套圆角最佳实践
当使用嵌套元素时,正确计算外层和内层的圆角值非常重要:
:::tip
当两个元素嵌套且都有圆角时,外层圆角应等于内层圆角加上 padding 值。这样可以确保两个圆角的圆心重合,视觉效果更协调。或者使用乘数计算来测试:将内层元素缩放到外层元素的大小,检查圆角是否匹配。
:::
### 计算公式
```
外层圆角 = 内层圆角 + padding
```
### 图示说明

---
url: /theme/shadows-tokens.md
---
# Shadow Tokens
阴影 Token 系统,定义了不同层级的阴影效果,用于创建界面的深度感和层次感。
## 基础用法
:::tip
点击卡片可复制 token 名称
:::
shadow-xsPreviewBox Shadow0 2px 8px 0 rgba(0, 0, 0, 0.08)shadow-smPreviewBox Shadow0 2px 8px 0 rgba(0, 0, 0, 0.12)shadowPreviewBox Shadow0 2px 12px 0 rgba(0, 0, 0, 0.12)shadow-lgPreviewBox Shadow0 2px 16px 0 rgba(0, 0, 0, 0.12)
## 设计规范
### 阴影层级
系统提供 4 个阴影层级,从轻微阴影到明显阴影,满足不同场景的使用需求:
| Token | CSS 变量 | 阴影值 | 使用场景 |
| ------------- | -------------------------- | ---------------------------------- | ------------------ |
| **shadow-xs** | `--cook-boxShadow-xs` | `0 2px 8px 0 rgba(0, 0, 0, 0.08)` | 极轻微阴影,用于卡片、面板的默认状态 |
| **shadow-sm** | `--cook-boxShadow-sm` | `0 2px 8px 0 rgba(0, 0, 0, 0.12)` | 小阴影,用于悬浮状态的元素 |
| **shadow** | `--cook-boxShadow-DEFAULT` | `0 2px 12px 0 rgba(0, 0, 0, 0.12)` | 默认阴影,用于弹窗、下拉菜单 |
| **shadow-lg** | `--cook-boxShadow-lg` | `0 2px 16px 0 rgba(0, 0, 0, 0.12)` | 大阴影,用于模态框、重要提示 |
### 阴影参数说明
阴影值采用 `box-shadow` 标准格式:
- **X 偏移**:水平偏移量(当前都为 0)
- **Y 偏移**:垂直偏移量(当前都为 2px)
- **模糊半径**:控制阴影的模糊程度(8px - 16px)
- **扩展半径**:控制阴影的扩展范围(当前都为 0)
- **颜色**:阴影颜色,使用 rgba 控制透明度
## 使用建议
### 选择合适的阴影
```tsx pure
// 默认卡片 - 使用极轻微阴影
卡片内容
// 悬浮按钮 - 使用小阴影
按钮
// 弹窗 - 使用默认阴影
弹窗内容
// 模态框 - 使用大阴影
模态框内容
```
### 阴影与层级关系
阴影大小应该与元素的层级关系成正比:
- **浅层元素**(默认状态的卡片、面板):`shadow-xs`
- **中层元素**(悬浮状态、下拉菜单):`shadow-sm` 或 `shadow`
- **深层元素**(弹窗、模态框):`shadow` 或 `shadow-lg`
### 动态阴影
```tsx pure
// 静态状态使用小阴影,悬浮时使用大阴影
卡片内容
```
## 注意事项
1. **性能考虑**:阴影会影响渲染性能,避免在大量列表中使用
2. **组合使用**:阴影可以与其他效果(如圆角、边框)组合使用
3. **深色模式**:在深色模式下可能需要调整阴影的透明度
4. **响应式**:移动设备上可以适当减小阴影以提升性能
---
url: /theme/shortcuts-tokens.md
---
# Shortcuts
UnoCSS Shortcuts 系统,提供常用样式组合的快捷类名,简化开发并保持样式一致性。
快捷列表使用示例完整配置:::tip
点击卡片可复制 shortcut 名称
:::
empty空值占位符(显示 --)展开后的类名`empty:before:content-["--"]`flex-between水平布局,两端对齐展开后的类名`flex items-center justify-between`flex-col-between垂直布局,两端对齐展开后的类名`flex flex-col justify-between`form-card表单卡片容器样式展开后的类名`rounded bg-white px-6 pt-5 pb-1px`card-default默认卡片容器样式展开后的类名`rounded bg-white px-6 py-5`card-default-border带边框的默认卡片样式展开后的类名`rounded bg-white px-6 py-5 border border-solid border-gray-3`card-default-sm小尺寸卡片容器样式展开后的类名`rounded bg-white px-6 pt-4 pb-5`card-header卡片头部容器样式展开后的类名`flex items-center justify-between pb-4`card-header-title卡片标题样式展开后的类名`text-base-m truncate`card-header-extra卡片头部额外操作区样式展开后的类名`ml-4 flex-shrink-0 text-gray-6 cursor-pointer flex items-center gap-4`descriptions-title描述列表标题样式展开后的类名`font-600 text-gray-8 mb-4`descriptions描述列表网格布局展开后的类名`grid gap-x-6 gap-y-3 w-full grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4`descriptions-item描述列表项样式展开后的类名`flex gap-3 [&>:first-child]:text-gray-6 [&>:first-child]:text-nowrap [&>:last-child]:flex-1 [&>:last-child]:min-w-0 [&>:last-child]:break-all`form-item-compact紧凑型表单项样式展开后的类名`[&_.ant-form-item-control-input]:min-h-22px [&_.ant-form-item-no-colon]:h-22px`tag-base标签基础样式展开后的类名`inline-block box-border rounded-xs border border-solid border-transparent`tag-default默认标签样式展开后的类名`inline-block box-border rounded-xs border border-solid border-transparent px-1 bg-gray-2 text-gray-7 text-xs`tag-default-lg大尺寸默认标签样式展开后的类名`inline-block box-border rounded-xs py-1px px-2 bg-gray-2 text-gray-7 text-sm`bg-body页面背景色展开后的类名`bg-#f5f5f5`tag-success成功状态标签展开后的类名`inline-block box-border rounded-xs px-1 bg-gray-2 text-gray-7 text-xs border-success-1 bg-success-1 text-success`tag-error错误状态标签展开后的类名`inline-block box-border rounded-xs px-1 bg-gray-2 text-gray-7 text-xs border-error-1 bg-error-1 text-error`tag-warning警告状态标签展开后的类名`inline-block box-border rounded-xs px-1 bg-gray-2 text-gray-7 text-xs border-warning-1 bg-warning-1 text-warning`tag-success-lg大尺寸成功状态标签展开后的类名`inline-block box-border rounded-xs py-1px px-2 bg-gray-2 text-gray-7 text-sm border-success-1 bg-success-1 text-success`tag-error-lg大尺寸错误状态标签展开后的类名`inline-block box-border rounded-xs py-1px px-2 bg-gray-2 text-gray-7 text-sm border-error-1 bg-error-1 text-error`tag-warning-lg大尺寸警告状态标签展开后的类名`inline-block box-border rounded-xs py-1px px-2 bg-gray-2 text-gray-7 text-sm border-warning-1 bg-warning-1 text-warning`tabs-no-border无边框的 Tabs 样式展开后的类名`[&_.ant-tabs-nav::before]:!border-none`pagination-bottom-0底部无边距的分页样式展开后的类名`[&_.ant-pagination]:mb-0`### 占位符类
#### empty
空值占位符,用于数据为空时显示横线
**效果**
姓名:张三编号:0备注:昵称:描述:
**代码**
```ts pure lineNumbers
姓名:
{values.name}
编号:
{values.code}
备注:
{values.remark} // [!code focus]
昵称:
{values.nickname} // [!code focus]
描述:
{values.empty} // [!code focus]
```
### 布局类
用于快速实现常见布局结构的快捷类:
#### flex-between
水平布局,两端对齐(flex + items-center + justify-between)
**效果**
左侧内容右侧内容
**代码**
```ts pure lineNumbers
// [!code focus]
左侧内容
右侧内容
```
#### flex-col-between
垂直布局,两端对齐(flex + flex-col + justify-between)
**效果**
顶部内容底部内容
**代码**
```ts pure lineNumbers
// [!code focus]
顶部内容
底部内容
```
### 卡片类
统一的卡片容器样式,提供一致的视觉效果:
#### card-default
默认卡片样式(圆角 + 白色背景 + 标准内边距)
**效果**
这是默认卡片内容
**代码**
```ts pure lineNumbers
// [!code focus]
这是默认卡片内容
```
#### card-default-border
带边框的默认卡片样式
**效果**
这是带边框的卡片内容
**代码**
```ts pure lineNumbers
// [!code focus]
这是带边框的卡片内容
```
#### card-default-sm
小尺寸卡片样式(顶部内边距更小)
**效果**
这是小尺寸卡片内容
**代码**
```ts pure lineNumbers
// [!code focus]
这是小尺寸卡片内容
```
#### form-card
表单卡片样式(底部边距为 1px)From.Item 默认会有 margin-bottom: 24px;
**效果**
用户名邮箱角色请选择角色提 交
**代码**
```ts pure lineNumbers
import { Button, Form, Input, Select } from 'antd';
// [!code focus]
{/* ... more form items */}
```
### 卡片头部类
卡片区域的细分样式:
#### 完整的卡片头部示例
**效果**
卡片标题操作 1操作 2卡片内容区域
**代码**
```ts pure lineNumbers
// [!code focus]
卡片标题
// [!code focus]
// [!code focus]
操作 1
操作 2
卡片内容区域
```
### 描述列表类
用于展示键值对信息的网格布局:
#### 完整的描述列表示例
**效果**
基本信息姓名张三年龄25城市北京职业工程师邮箱zhangsan@example.com手机13800138000
**代码**
```ts pure lineNumbers
基本信息
// [!code focus]
// [!code focus]
姓名
张三
// [!code focus]
年龄
25
{/* ... more items */}
```
### 标签类
统一的标签样式系统:
#### 基础标签
**效果**
默认标签大尺寸标签
**代码**
```ts pure lineNumbers
默认标签 // [!code focus]
大尺寸标签 // [!code focus]
```
#### 状态标签
**效果**
默认成功错误警告默认成功状态错误状态警告状态
**代码**
```ts pure lineNumbers
默认 // [!code focus]
成功 // [!code focus]
错误 // [!code focus]
警告 // [!code focus]
默认 // [!code focus]
成功状态 // [!code focus]
错误状态 // [!code focus]
警告状态 // [!code focus]
```
### 其他工具类
#### bg-body
页面背景色(#f5f5f5)
**效果**
这是使用 bg-body 背色的区域
**代码**
```ts pure lineNumbers
// [!code focus]
这是使用 bg-body 背色的区域
```
#### tabs-no-border
去除 Ant Design Tabs 组件导航栏底部的默认边框
**效果**
默认样式(有边框)
用户管理角色管理权限管理使用 tabs-no-border(无边框)
用户管理角色管理权限管理
**代码**
```ts pure lineNumbers
import { Tabs } from 'antd';
// 默认样式(有边框)
// 使用 tabs-no-border(无边框)
// [!code focus]
```
#### pagination-bottom-0
去除 Ant Design Table 组件分页器的默认底部边距
**效果**
默认样式(分页器有底部间距)| 姓名 | 年龄 | 地址 |
| --- | --- | --- |
| 张三 | 32 | 北京市朝阳区 |
| 李四 | 28 | 上海市浦东新区 |
-
- [1](#)
- [2](#)
- [3](#)
- [4](#)
- [5](#)
-
使用 pagination-bottom-0(无底部间距)| 姓名 | 年龄 | 地址 |
| --- | --- | --- |
| 张三 | 32 | 北京市朝阳区 |
| 李四 | 28 | 上海市浦东新区 |
-
- [1](#)
- [2](#)
- [3](#)
- [4](#)
- [5](#)
-
**代码**
```ts pure lineNumbers
{/* 默认样式 */}
{/* 使用 pagination-bottom-0 */}
使用 pagination-bottom-0(无底部间距)
```
:::tip
完整的 UnoCSS 配置文件,可直接复制到项目中使用
:::
```ts title="uno.config.ts"
import { defineConfig, presetWind3 } from 'unocss';
export default defineConfig({
presets: [presetWind3()],
cli: {
entry: {
patterns: ['**/*.{tsx,mdx}'],
outFile: 'theme/uno.css',
},
},
rules: [
],
shortcuts: [
['empty', 'empty:before:content-["--"]'],
['flex-between', 'flex items-center justify-between'],
['flex-col-between', 'flex flex-col justify-between'],
['form-card', 'rounded bg-white px-6 pt-5 pb-1px'],
['card-default', 'rounded bg-white dark:bg-gray-6 px-6 py-5'],
['card-default-border', 'card-default border border-solid border-gray-3 dark:border-white-4'],
['card-default-sm', 'rounded bg-white dark:bg-gray-6 px-6 pt-4 pb-5'],
['card-header', 'flex-between pb-4'],
['card-header-title', 'text-base-m truncate'],
['card-header-extra', 'ml-4 flex-shrink-0 text-gray-6 cursor-pointer flex items-center gap-4'],
['descriptions-title', 'font-600 text-gray-8 mb-4'],
['descriptions', 'grid gap-x-6 gap-y-3 w-full grid-cols-1 @sm:grid-cols-2 @lg:grid-cols-3 @xl:grid-cols-4'],
[
'descriptions-item',
'flex gap-3 [&>:first-child]:text-gray-6 [&>:first-child]: [&>:first-child]:text-nowrap ' +
'[&>:last-child]:flex-1 [&>:last-child]:min-w-0 [&>:last-child]:break-all',
],
['search-form-actions', 'col-start-auto flex-1 flex justify-end'],
['form-item-compact', '[&_.ant-form-item-control-input]:min-h-22px [&_.ant-form-item-no-colon]:h-22px'],
['tag-base', 'inline-block box-border rounded-xs border border-solid border-transparent'],
['tag-default', 'tag-base px-1 bg-gray-2 text-gray-7 dark:bg-white-4 dark:text-white text-xs'],
['tag-default-lg', 'tag-default py-1px px-2 text-sm'],
['bg-body', 'bg-[#f5f5f5] dark:bg-[#1a1a1a]'],
[
/^tag-(success|error|warning)(-lg)?$/,
([, status, size]) => {
const baseClass = size ? 'tag-default-lg' : 'tag-default';
const colorMap: Record = {
success: 'border-success-1 dark:border-success bg-success-1 dark:bg-success text-success dark:text-success-1',
error: 'border-error-1 dark:border-error bg-error-1 dark:bg-error text-error dark:text-error-1',
warning: 'border-warning-1 dark:border-warning bg-warning-1 dark:bg-warning text-warning dark:text-warning-1',
};
return `${baseClass} ${colorMap[status]}`;
},
],
['tabs-no-border', '[&_.ant-tabs-nav::before]:!border-none'],
['pagination-bottom-0', '[&_.ant-pagination]:mb-0!'],
],
});
```
## 使用建议
### 组件样式组合
```tsx pure
// 完整的卡片结构
// 描述列表
```
### 标签状态
```tsx pure
// 根据状态使用不同的标签样式
成功
失败
警告
// 大尺寸标签
成功状态
```
## 注意事项
1. **语义化命名**:shortcut 名称应清晰表达其用途
2. **组合使用**:多个 shortcuts 可以组合使用实现复杂效果
3. **避免覆盖**:使用 shortcuts 后如需调整,添加额外的类名而非修改 shortcut
4. **保持一致**:相同功能的组件应使用相同的 shortcuts
---
url: /theme/shortcuts/bg-body.demo.md
---
#
这是使用 bg-body 背色的区域
---
url: /theme/shortcuts/card-default-border.demo.md
---
#
这是带边框的卡片内容
---
url: /theme/shortcuts/card-default-sm.demo.md
---
#
这是小尺寸卡片内容
---
url: /theme/shortcuts/card-default.demo.md
---
#
这是默认卡片内容
---
url: /theme/shortcuts/card-header.demo.md
---
#
卡片标题操作 1操作 2卡片内容区域
---
url: /theme/shortcuts/descriptions.demo.md
---
#
基本信息姓名张三年龄25城市北京职业工程师邮箱zhangsan@example.com手机13800138000
---
url: /theme/shortcuts/empty.demo.md
---
#
姓名:张三编号:0备注:昵称:描述:
---
url: /theme/shortcuts/form-card.demo.md
---
#
用户名邮箱角色请选择角色提 交
---
url: /theme/shortcuts/layout-flex-between.demo.md
---
#
左侧内容右侧内容
---
url: /theme/shortcuts/layout-flex-col-between.demo.md
---
#
顶部内容底部内容
---
url: /theme/shortcuts/pagination-bottom-0.demo.md
---
#
默认样式(分页器有底部间距)| 姓名 | 年龄 | 地址 |
| --- | --- | --- |
| 张三 | 32 | 北京市朝阳区 |
| 李四 | 28 | 上海市浦东新区 |
-
- [1](#)
- [2](#)
- [3](#)
- [4](#)
- [5](#)
-
使用 pagination-bottom-0(无底部间距)| 姓名 | 年龄 | 地址 |
| --- | --- | --- |
| 张三 | 32 | 北京市朝阳区 |
| 李四 | 28 | 上海市浦东新区 |
-
- [1](#)
- [2](#)
- [3](#)
- [4](#)
- [5](#)
-
---
url: /theme/shortcuts/tabs-no-border.demo.md
---
#
默认样式(有边框)
用户管理角色管理权限管理使用 tabs-no-border(无边框)
用户管理角色管理权限管理
---
url: /theme/shortcuts/tag-default.demo.md
---
#
默认标签大尺寸标签
---
url: /theme/shortcuts/tag-status.demo.md
---
#
默认成功错误警告默认成功状态错误状态警告状态
---
url: /utils/common.md
---
# Common 常用工具
通用工具函数集合。
## 安装
```sh [npx]
npx shadcn@latest add https://codebase.anyask.dev/r/utils-common.json
```
```sh [yarn]
yarn dlx shadcn@latest add https://codebase.anyask.dev/r/utils-common.json
```
```sh [pnpm]
pnpm dlx shadcn@latest add https://codebase.anyask.dev/r/utils-common.json
```
```sh [bunx]
bunx shadcn@latest add https://codebase.anyask.dev/r/utils-common.json
```
```sh [deno]
deno run npm:shadcn@latest npm:add https://codebase.anyask.dev/r/utils-common.json
```
## 快速开始
```tsx
import { sleep, isEmpty, clamp, getLastOfEachSubarray } from '@/utils';
// 使用工具函数
await sleep(1000);
isEmpty(null);
clamp(value, 0, 100);
getLastOfEachSubarray([[1, 2], [3, 4]]);
```
## sleep
异步等待指定时间。
### 使用示例
```tsx file="/demos/utils/common/sleep.demo.tsx" preview
import React, { useState } from 'react';
import { Button, message } from 'antd';
import { sleep } from '@/utils';
const Demo: React.FC = () => {
const [loading, setLoading] = useState(false);
const handleSleep = async () => {
setLoading(true);
await sleep(2000);
setLoading(false);
message.success('已等待 2 秒');
};
return (
等待 2 秒
);
};
export default Demo;
```
### API
**签名**: `sleep(ms: number): Promise`
| 参数 | 说明 | 类型 | 默认值 |
| -- | ------ | -------- | --- |
| ms | 等待的毫秒数 | `number` | - |
***
## isEmpty
检查值是否为空。
### 使用示例
```tsx file="/demos/utils/common/isEmpty.demo.tsx" preview
import React from 'react';
import { Table } from 'antd';
import { isEmpty } from '@/utils';
const Demo: React.FC = () => {
const isEmptyData = [
{ code: 'isEmpty(null)', result: isEmpty(null) },
{ code: 'isEmpty(undefined)', result: isEmpty(undefined) },
{ code: "isEmpty('')", result: isEmpty('') },
{ code: "isEmpty('test')", result: isEmpty('test') },
{ code: 'isEmpty(0)', result: isEmpty(0) },
];
return (
{text},
},
{
title: '返回值',
dataIndex: 'result',
key: 'result',
render: (value) => {String(value)} ,
},
]}
pagination={false}
size="middle"
/>
);
};
export default Demo;
```
### API
**签名**: `isEmpty(value: FormatNumberInput): boolean`
| 参数 | 说明 | 类型 | 默认值 |
| ----- | ----- | ------------------- | --- |
| value | 要检查的值 | `FormatNumberInput` | - |
**返回值**: `boolean` - true 表示值为空
**支持的空值**:
- `null`
- `undefined`
- `''` (空字符串)
**不视为空值**:
- `0`
- `false`
- `' '` (空格字符串)
***
## clamp
将一个数值约束在指定的区间内。
### 使用示例
```tsx file="/demos/utils/common/clamp.demo.tsx" preview
import React, { useState } from 'react';
import { InputNumber } from 'antd';
import { clamp } from '@/utils';
const Demo: React.FC = () => {
const [clampValue, setClampValue] = useState(5);
const [clampMin, setClampMin] = useState(0);
const [clampMax, setClampMax] = useState(10);
const clampResult = clamp(clampValue, clampMin, clampMax);
return (
value:
setClampValue(val ?? 0)} className="w-50" step={1} />
min:
setClampMin(val ?? 0)} className="w-50" step={1} />
max:
setClampMax(val ?? 0)} className="w-50" step={1} />
clamp({clampValue} , {clampMin} ,{' '}
{clampMax} )
{clampResult}
结果约束在 [{clampMin}, {clampMax}] 范围内
);
};
export default Demo;
```
### API
**签名**: `clamp(value: number, min: number, max: number): number`
| 参数 | 说明 | 类型 | 默认值 |
| ----- | ----------- | -------- | --- |
| value | 需要被裁剪的数值 | `number` | - |
| min | 区间的最小边界(包含) | `number` | - |
| max | 区间的最大边界(包含) | `number` | - |
**返回值**: 被裁剪后的数值,确保 `min <= 返回值 <= max`
***
## getLastOfEachSubarray
获取每个子数组的最后一个元素。
### 使用示例
```tsx file="/demos/utils/common/getLastOfEachSubarray.demo.tsx" preview
import React from 'react';
import { Table } from 'antd';
import { getLastOfEachSubarray } from '@/utils';
const Demo: React.FC = () => {
const getLastOfEachSubarrayData = [
{
input: '[[1, 2, 3], [4, 5], null, [6]]',
result: JSON.stringify(getLastOfEachSubarray([[1, 2, 3], [4, 5], null, [6]])),
},
{
input: '[[1], [2, 3, 4], [5, 6]]',
result: JSON.stringify(getLastOfEachSubarray([[1], [2, 3, 4], [5, 6]])),
},
{
input: '[null, []]',
result: JSON.stringify(getLastOfEachSubarray([null, []])),
},
{
input: '[]',
result: JSON.stringify(getLastOfEachSubarray([])),
},
];
return (
{text},
},
{
title: '返回值',
dataIndex: 'result',
key: 'result',
render: (text) => {text},
},
]}
pagination={false}
size="middle"
/>
);
};
export default Demo;
```
### API
**签名**: `getLastOfEachSubarray<T>(arrays?: Array<T[] | null> | null): T[]`
| 参数 | 说明 | 类型 | 默认值 | |
| ------ | -------------- | ------------- | --------------- | - |
| arrays | 可能包含若干子数组的二维数组 | \`Array\ \| null\` | - |
**返回值**: 包含所有非空子数组最后一个元素的数组
---
url: /utils/index.md
---
# Utils 工具函数
## Common 常用工具
### [Common 常用工具](/utils/common.md)
- [安装](/utils/common.md#安装)
- [快速开始](/utils/common.md#快速开始)
- [sleep](/utils/common.md#sleep)
- [isEmpty](/utils/common.md#isempty)
- [clamp](/utils/common.md#clamp)
- [getLastOfEachSubarray](/utils/common.md#getlastofeachsubarray)
## Number 数字格式化
### [Number 数字格式化](/utils/number.md)
- [安装](/utils/number.md#安装)
- [formatWithPrecision](/utils/number.md#formatwithprecision)
- [formatNumber](/utils/number.md#formatnumber)
- [formatNumberWithUnit](/utils/number.md#formatnumberwithunit)
- [formatWithSeparator](/utils/number.md#formatwithseparator)
- [formatAndSplitValueUnit](/utils/number.md#formatandsplitvalueunit)
- [formatAndSplitValueIntegerDecimalUnit](/utils/number.md#formatandsplitvalueintegerdecimalunit)
- [API 参考](/utils/number.md#api-参考)
## Percent 百分比
### [Percent 百分比](/utils/percent.md)
- [安装](/utils/percent.md#安装)
- [formatPercent](/utils/percent.md#formatpercent)
- [calculatePercentage](/utils/percent.md#calculatepercentage)
- [API 参考](/utils/percent.md#api-参考)
## React 工具
### [React 工具](/utils/react.md)
- [安装](/utils/react.md#安装)
- [renderEllipsisList](/utils/react.md#renderellipsislist)
- [renderWithParentheses](/utils/react.md#renderwithparentheses)
- [API](/utils/react.md#api-2)
---
url: /utils/number.md
---
# Number 数字格式化
提供一系列数字格式化工具函数,支持保留精度、千分位分隔、自动单位转换等功能。
## 安装
```sh [npx]
npx shadcn@latest add https://codebase.anyask.dev/r/utils-number.json
```
```sh [yarn]
yarn dlx shadcn@latest add https://codebase.anyask.dev/r/utils-number.json
```
```sh [pnpm]
pnpm dlx shadcn@latest add https://codebase.anyask.dev/r/utils-number.json
```
```sh [bunx]
bunx shadcn@latest add https://codebase.anyask.dev/r/utils-number.json
```
```sh [deno]
deno run npm:shadcn@latest npm:add https://codebase.anyask.dev/r/utils-number.json
```
## formatWithPrecision
保留指定小数位数的数字格式化函数。超出精度的部分会被四舍五入,不足则保持原样。
### 功能特点
- 支持任意数值类型的输入
- 自动处理空值和 NaN
- 精度超出截断,不足保持原样
### 使用示例
```tsx file="/demos/utils/number/formatWithPrecision.demo.tsx" preview
import React, { useState } from 'react';
import { InputNumber, Radio } from 'antd';
import { formatWithPrecision } from '@/utils';
const Demo: React.FC = () => {
const [value, setValue] = useState(123.456);
const [precision, setPrecision] = useState(2);
const result = formatWithPrecision(value, precision);
return (
输入值
setValue(val)} className="w-50" step={0.1} />
精度
setPrecision(e.target.value)} buttonStyle="solid">
0
1
2
3
formatWithPrecision(
{value}
, {precision})
{result}
);
};
export default Demo;
```
## formatNumber
数字格式化函数,支持自动添加单位(万、百万、千万、亿)和千分位分隔。
### 功能特点
- 自动识别数值范围添加适当单位
- 支持自定义小数位数
- 支持自定义千分位分隔符
- 可选择是否启用单位格式化
### 单位换算规则
| 数值范围 | 单位 |
| ----- | ---- |
| ≥ 1亿 | 亿 |
| ≥ 1千万 | 千万 |
| ≥ 1百万 | 百万 |
| ≥ 1万 | 万 |
| \< 1万 | 原值显示 |
### 使用示例
```tsx file="/demos/utils/number/formatNumber.demo.tsx" preview
import React, { useState } from 'react';
import { InputNumber, Radio, Switch } from 'antd';
import { formatNumber } from '@/utils';
const Demo: React.FC = () => {
const [value, setValue] = useState(123456789.456);
const [precision, setPrecision] = useState(2);
const [shouldFormat, setShouldFormat] = useState(true);
const result = formatNumber(value, { precision, shouldFormat });
return (
输入值
setValue(val)} className="w-60" />
精度
setPrecision(e.target.value)} buttonStyle="solid">
0
1
2
自动格式化
formatNumber(
{value}
, {'{'}precision: {precision}, shouldFormat: {shouldFormat.toString()}
{'}'})
{result}
);
};
export default Demo;
```
## formatNumberWithUnit
带单位的数字格式化,在格式化后的数字后追加指定单位。
### 功能特点
- 自动格式化数字并追加单位
- 自动处理空值情况
- 0 会被正常格式化
### 使用示例
```tsx file="/demos/utils/number/formatNumberWithUnit.demo.tsx" preview
import React, { useState } from 'react';
import { Input, InputNumber, Radio, Switch } from 'antd';
import { formatNumberWithUnit } from '@/utils';
const Demo: React.FC = () => {
const [value, setValue] = useState(123456);
const [unit, setUnit] = useState('元');
const [precision, setPrecision] = useState(2);
const [shouldFormat, setShouldFormat] = useState(false);
const result = formatNumberWithUnit(value, unit, { precision, shouldFormat });
return (
数值
setValue(val)} className="w-50" />
单位
setUnit(e.target.value)} className="w-50" />
精度
setPrecision(e.target.value)} buttonStyle="solid">
0
1
2
自动格式化
formatNumberWithUnit({value ?? 'null'} , '{unit}' )
{result ?? 'null'}
);
};
export default Demo;
```
## formatWithSeparator
为数字添加千分位分隔符。
### 功能特点
- 支持自定义分隔符
- 自动处理整数和小数部分
- 空值返回空字符串
### 使用示例
```tsx file="/demos/utils/number/formatWithSeparator.demo.tsx" preview
import React, { useState } from 'react';
import { Input, InputNumber } from 'antd';
import { formatWithSeparator } from '@/utils';
const Demo: React.FC = () => {
const [value, setValue] = useState(123456789);
const [separator, setSeparator] = useState(',');
const result = formatWithSeparator(value, separator);
return (
输入值
setValue(val)} className="w-50" />
分隔符
setSeparator(e.target.value)} className="w-50" placeholder="自定义分隔符" />
formatWithSeparator({value ?? 'null'} ,{' '}
'{separator}' )
{result ?? 'null'}
);
};
export default Demo;
```
## formatAndSplitValueUnit
将带单位的数值字符串分离为值和单位两部分。
### 功能特点
- 智能识别数值和单位
- 支持格式化选项
- 空值返回 `{ value: null, unit: null }`
### 使用示例
```tsx file="/demos/utils/number/formatAndSplitValueUnit.demo.tsx" preview
import React, { useState } from 'react';
import { Input, Radio, Switch } from 'antd';
import { formatAndSplitValueUnit } from '@/utils';
const Demo: React.FC = () => {
const [input, setInput] = useState('123456.78元');
const [precision, setPrecision] = useState(2);
const [shouldFormat, setShouldFormat] = useState(true);
const result = formatAndSplitValueUnit(input, { precision, shouldFormat });
return (
输入值
setInput(e.target.value)} className="w-60" placeholder="如: 123456.78元" />
精度
setPrecision(e.target.value)} buttonStyle="solid">
0
1
2
自动格式化
formatAndSplitValueUnit('{input}' )
{JSON.stringify(result)}
);
};
export default Demo;
```
## formatAndSplitValueIntegerDecimalUnit
将带单位的数值字符串分离为整数部分、小数部分和单位三部分。
### 功能特点
- 分别返回整数部分、小数部分和单位
- 小数部分带 `.` 分隔符标识
- 适合需要分别渲染整数和小数的场景
### 返回值结构
```typescript
{
integerPart: string | null; // 整数部分
decimalPart: string | null; // 小数部分(带 . 标识)
unit: string | null; // 单位
}
```
### 使用示例
```tsx file="/demos/utils/number/formatAndSplitValueIntegerDecimalUnit.demo.tsx" preview
import React, { useState } from 'react';
import { Input, Radio, Switch } from 'antd';
import { formatAndSplitValueIntegerDecimalUnit } from '@/utils';
const Demo: React.FC = () => {
const [input, setInput] = useState('123456.78元');
const [precision, setPrecision] = useState(2);
const [shouldFormat, setShouldFormat] = useState(true);
const result = formatAndSplitValueIntegerDecimalUnit(input, { precision, shouldFormat });
return (
输入值
setInput(e.target.value)} className="w-60" placeholder="如: 123456.78元" />
精度
setPrecision(e.target.value)} buttonStyle="solid">
0
1
2
自动格式化
formatAndSplitValueIntegerDecimalUnit('{input}' )
{JSON.stringify(result)}
);
};
export default Demo;
```
## API 参考
### 通用类型
```typescript
type FormatNumberInput = string | number | null | undefined;
interface FormatNumberOptions {
/** 保留的小数位数 */
precision?: number;
/** 千分位分隔符 */
separator?: string;
/** 是否格式化数值(添加单位:万、百万、千万、亿) */
shouldFormat?: boolean;
}
```
### 函数签名
| 函数 | 签名 |
| --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `formatWithPrecision` | `(value: FormatNumberInput, precision?: number) => string \| null` |
| `formatNumber` | `(value: FormatNumberInput, options?: FormatNumberOptions) => string \| null` |
| `formatNumberWithUnit` | `(value: FormatNumberInput, unit: string, options?: FormatNumberOptions) => string \| null` |
| `formatWithSeparator` | `(value: FormatNumberInput, separator?: string) => string` |
| `formatAndSplitValueUnit` | `(input: FormatNumberInput, options?: FormatNumberOptions) => { value: string \| null, unit: string \| null }` |
| `formatAndSplitValueIntegerDecimalUnit` | `(input: FormatNumberInput, options?: FormatNumberOptions) => { integerPart: string \| null, decimalPart: string \| null, unit: string \| null }` |
---
url: /utils/percent.md
---
# Percent 百分比
提供百分比格式化和计算的工具函数。
## 安装
```sh [npx]
npx shadcn@latest add https://codebase.anyask.dev/r/utils-percent.json
```
```sh [yarn]
yarn dlx shadcn@latest add https://codebase.anyask.dev/r/utils-percent.json
```
```sh [pnpm]
pnpm dlx shadcn@latest add https://codebase.anyask.dev/r/utils-percent.json
```
```sh [bunx]
bunx shadcn@latest add https://codebase.anyask.dev/r/utils-percent.json
```
```sh [deno]
deno run npm:shadcn@latest npm:add https://codebase.anyask.dev/r/utils-percent.json
```
## formatPercent
将数值转换为百分比形式,可指定小数位数。
### 功能特点
- 自动将数值乘以 100
- 支持指定小数位数
- 自动处理空值和 NaN
### 使用示例
```tsx file="/demos/utils/percent/formatPercent.demo.tsx" preview
import React, { useState } from 'react';
import { InputNumber, Radio } from 'antd';
import { formatPercent } from '@/utils';
const Demo: React.FC = () => {
const [value, setValue] = useState(0.1234);
const [precision, setPrecision] = useState(2);
const result = formatPercent(value, precision);
return (
输入值
setValue(val)} className="w-50" step={0.01} />
精度
setPrecision(e.target.value)} buttonStyle="solid">
0
1
2
3
formatPercent({value ?? 'null'} , {precision})
{result ?? 'null'}
);
};
export default Demo;
```
## calculatePercentage
计算两个数值的百分比(numerator / denominator \* 100),可指定小数位数。
### 功能特点
- 支持任意数值类型的输入
- 自动处理空值情况
- 分母为 0 时:分子为 0 返回 0,否则返回 null
### 使用示例
```tsx file="/demos/utils/percent/calculatePercentage.demo.tsx" preview
import React, { useState } from 'react';
import { InputNumber, Radio } from 'antd';
import { calculatePercentage } from '@/utils';
const Demo: React.FC = () => {
const [numerator, setNumerator] = useState(1);
const [denominator, setDenominator] = useState(2);
const [precision, setPrecision] = useState(2);
const result = calculatePercentage(numerator, denominator, precision);
return (
分子
setNumerator(val)} className="w-50" />
分母
setDenominator(val)} className="w-50" />
精度
setPrecision(e.target.value)} buttonStyle="solid">
0
1
2
calculatePercentage({numerator ?? 'null'} ,{' '}
{denominator ?? 'null'} , {precision})
{result ?? 'null'}
);
};
export default Demo;
```
## API 参考
### 通用类型
```typescript
type FormatNumberInput = string | number | null | undefined;
```
### 函数签名
| 函数 | 签名 |
| --------------------- | ---------------------------------------------------------------------------------------------------------------- |
| `formatPercent` | `(value: FormatNumberInput, percent?: number) => string \| null` |
| `calculatePercentage` | `(numerator?: FormatNumberInput, denominator?: FormatNumberInput, percent?: number) => string \| number \| null` |
---
url: /utils/react.md
---
# React 工具
React 组件相关的工具函数。
## 安装
```sh [npx]
npx shadcn@latest add https://codebase.anyask.dev/r/utils-react.json
```
```sh [yarn]
yarn dlx shadcn@latest add https://codebase.anyask.dev/r/utils-react.json
```
```sh [pnpm]
pnpm dlx shadcn@latest add https://codebase.anyask.dev/r/utils-react.json
```
```sh [bunx]
bunx shadcn@latest add https://codebase.anyask.dev/r/utils-react.json
```
```sh [deno]
deno run npm:shadcn@latest npm:add https://codebase.anyask.dev/r/utils-react.json
```
## renderEllipsisList
通用的列表渲染函数,用于处理 Ellipsis 和 join 逻辑。
### 功能特点
- 自动将数组元素用分隔符连接
- 支持自定义文本转换函数
- 文本超出时显示省略号并支持 tooltip
### 使用示例
```tsx file="/demos/utils/react/renderEllipsisList.demo.tsx" preview
import React, { useState } from 'react';
import { Button, Input, Tag } from 'antd';
import { renderEllipsisList } from '@/utils';
const Demo: React.FC = () => {
const [list, setList] = useState(['苹果', '香蕉', '橙子', '葡萄', '西瓜']);
const [separator, setSeparator] = useState('、');
const [newItem, setNewItem] = useState('');
const addItem = () => {
if (newItem.trim()) {
setList([...list, newItem.trim()]);
setNewItem('');
}
};
const removeItem = (item: string) => {
setList(list.filter((i) => i !== item));
};
const result = renderEllipsisList(list, (item) => item, separator);
return (
{list.map((item) => (
removeItem(item)}>
{item}
))}
renderEllipsisList(list, item => item, '{separator}')
{result}
鼠标悬停查看完整文本(超出省略)
);
};
export default Demo;
```
### API
**签名**:
```ts
renderEllipsisList(
list: T[] | undefined,
getDisplayText?: (item: T) => string | null | undefined,
separator?: string
): React.ReactElement | null
```
## renderWithParentheses
渲染两个字段,第一个字段在前,第二个字段用括号包围。
### 功能特点
- 自动处理空值情况
- 自动去除首尾空格
- 智能返回最简洁的格式
### 使用示例
```tsx file="/demos/utils/react/renderWithParentheses.demo.tsx" preview
import React, { useState } from 'react';
import { Input } from 'antd';
import { renderWithParentheses } from '@/utils';
const Demo: React.FC = () => {
const [primary, setPrimary] = useState('张三');
const [secondary, setSecondary] = useState('zhangsan@example.com');
const result = renderWithParentheses(primary, secondary);
return (
);
};
export default Demo;
```
### API
**签名**:
```ts
renderWithParentheses(
primary?: string | null,
secondary?: string | null
): string | null | undefined
```
## API
### renderEllipsisList
通用的列表渲染函数,用于处理 Ellipsis 和 join 逻辑。
**签名**:
```ts
renderEllipsisList<T>(
list: T[] | undefined,
getDisplayText?: (item: T) => string | null | undefined,
separator?: string
): React.ReactElement | null
```
| 参数 | 说明 | 类型 | 默认值 |
| -------------- | --------- | ------------------------------------------ | ---------------------------- |
| list | 要渲染的数组 | `T[] \| undefined` | - |
| getDisplayText | 获取显示文本的函数 | `(item: T) => string \| null \| undefined` | `(item) => item?.toString()` |
| separator | 分隔符 | `string` | `、` |
**返回值**: JSX 元素或 null
**示例**:
```tsx
// 基础用法
renderEllipsisList(['张三', '李四', '王五']);
// 张三、李四、王五
// 自定义分隔符
renderEllipsisList(['a', 'b', 'c'], (item) => item, ', ');
// a, b, c
// 自定义显示文本
renderEllipsisList(
[{ name: '张三', email: 'zhangsan@example.com' }],
(item) => item.name
);
// 张三
```
### renderWithParentheses
渲染两个字段,第一个字段在前,第二个字段用括号包围。
**签名**:
```ts
renderWithParentheses(
primary?: string | null,
secondary?: string | null
): string | null | undefined
```
| 参数 | 说明 | 类型 | 默认值 |
| --------- | ------------ | ---------------- | --- |
| primary | 主要字段(显示在括号外) | `string \| null` | - |
| secondary | 次要字段(显示在括号内) | `string \| null` | - |
**返回值**: 格式化后的字符串,或 null/undefined
**示例**:
```ts
renderWithParentheses('张三', 'zhangsan@example.com');
// "张三
renderWithParentheses('张三', '');
// "张三"
renderWithParentheses('', 'zhangsan@example.com');
// "zhangsan@example.com"
renderWithParentheses('', '');
// null
```