@ api7/ ui 组件
API7 创建于 基础UI 和尾风 CSS v4. 组件以Tailwind公用事业类为样式,应用程序自有的Tailwind CSS编译,因此库和应用程序共享了一套公用事业和一款主题.
安装
库需要React 19和一个已经用 Tailwind CSS 4.1 或更新的构建的应用程序. 如果应用程序尚未使用 Tailwind , 请遵循 尾风 CSS 安装指南 先用你的建造工具 然后回来.
npm install @api7/ui-components tailwindcss react-day-picker lucide-react
# or
pnpm add @api7/ui-components tailwindcss react-day-picker lucide-react
# or
yarn add @api7/ui-components tailwindcss react-day-picker lucide-react
tailwindcss 如果应用程序使用Tailwind,则该应用程序已经存在。 为您的构建工具安装 Tailwind 集成(@tailwindcss/vite, (中文(简体) ), @tailwindcss/postcss 或者说 @tailwindcss/cli) (中文(简体) ). 主题的导入与Vite插件,PostCSS插件和CLI一起工作,CLI是测试的. 其他的构建工具,如webpack,没有经过测试. 软件包期望应用程序中的这些对等依赖性 :
| 软件包 | 版本 | 需要时间 |
|---|---|---|
react, (中文(简体) ), react-dom | ^19 | 所有东西 |
tailwindcss | ^4.1.0 | 汇编组件的类别并登记主题。 见 快开始 |
lucide-react | ^1 | 组件内部使用的图标 |
react-day-picker | ^10.0.1 | 要求. Calendar, (中文(简体) ), DatePicker 财务报告和审定财务报表 DateRangePicker 导入, 软件包将它声明为需要的对等端, 所以即使不使用也安装它 |
@tanstack/react-form | ^1.33.0 | @api7/ui-components/form (可选) |
@tanstack/react-table | ^9.0.0 | @api7/ui-components/data-table (可选) |
只有在导入这些切入点时,才会添加可选切入点.
快开始
-
在应用程序的主 CSS 文件中( 例如 )
src/index.css),导入 Tailwind CSS,然后导入库主题,并确保导入 CSS 文件的应用程序的条目文件:@import 'tailwindcss'; @import '@api7/ui-components';令为事. 主题延伸了"尾风"主题,所以它必须追随
tailwindcss。 。 。 .CSS 软件包名称通过
style导出条件, 在 JavaScript 中, 它会解析到组件 。 Tailwind CSS 4 以及解决 CSS 的工具导入方式( Tailwind CLI,@tailwindcss/postcss财务报告和审定财务报表@tailwindcss/vite应用条件。 忽略它的工具查找 JavaScript 条目而失败@import。 。 。 .这就是所有的配置。 主题文件在组件使用的类别中指向 Tailwind, 所以你不添加
@source语义颜色(bg-primary, (中文(简体) ),text-muted-foreground, (中文(简体) ),border-border,其他的),将弧度和字体作为Tailwind主题值. 应用程序保留了自己的"Tailwind"调色板,同样的课程在自己的标记中工作. 见 用你的尾风CSS 用于主题在应用程序中的变化. -
装入字体
--font-sans默认为 Inter。 例如,安装@fontsource-variable/inter(单位:千美元)npm install @fontsource-variable/inter)并导入到同一 CSS 文件,或应用程序的条目文件中:import '@fontsource-variable/inter';要使用另一个字体, 设置
--font-sans在一个@theme输入后块 :@theme { --font-sans: 'Your Font', sans-serif; }库中不设置页面样式 。 部件从页面中继承文本颜色、字体和字体大小,因此设置它们
body在应用程序的基层中。 构件的布置和测试都采用此规则,不同的线高会改变不自设的构件的高度:@layer base { body { background-color: var(--color-background); color: var(--color-foreground); font-family: var(--font-sans); font-size: var(--text-sm); line-height: var(--text-sm--line-height); } } -
打开
isolate应用的根元件(<div id="root" class="isolate">) (中文(简体) ). 弹出器、对话框和抽屉<body>在你的根外,他们有z-index: 50(祝酒词已经1010) (中文(简体) ). 申请中包含一个更高的元素z-index,或带有z-index被涂在弹出上 与它重叠.isolate制作z-index应用程序的值是本地到根的,所以无论应用程序使用什么值,每个弹出都停留在它的上方. -
使用组件。 不需要任何提供者。 渲染器
Toaster使用时一次toast,然后将应用程序围入ConfigProvider如果您需要除此以外的地方en-US数字 :import { Button, ConfigProvider, Toaster, toast } from '@api7/ui-components'; export function App() { return ( <ConfigProvider locale="zh-CN"> <Button onClick={() => toast.success('Saved', { description: 'Your changes were stored.' })}>Save</Button> <Toaster /> </ConfigProvider> ); }
ConfigProvider 接受 locale (单位:千美元)en-US 或者说 zh-CN和 messages,可以覆盖内置文本的对象,例如按钮或自旋器的加载标签、关闭按钮、数据表的空状态和页形标签。 定义 messages 在模块范围或记忆中.
入境点
| 导入 | 目录 |
|---|---|
@api7/ui-components | 组件, toast 财务报告和审定财务报表 Toaster, (中文(简体) ), ConfigProvider, (中文(简体) ), useLocale 财务报告和审定财务报表 useMessages,在 CSS 中,应用程序 Tailwind CSS 的主题 |
@api7/ui-components/form | 在 TanStack Form 上构建的窗体字段 。 他们的形而上学, LabeledField,在主条目中并与任何形式的库合作 |
@api7/ui-components/data-table | 数据表基于 TanStack 表格 |
@api7/ui-components/tokens | 设计代号数据(palette, (中文(简体) ), themes, (中文(简体) ), FAMILIES, (中文(简体) ), STEPS 文档页面的对比帮助) |
一揽子措施仅是无害环境管理。 组件模块保留 "use client" 指令,因此组件在像 Next.js app 路由器这样的 React 服务器组件设置中工作.
按钮
Button 使用一个 variant数字 : primary (默认), secondary, (中文(简体) ), outline, (中文(简体) ), ghost, (中文(简体) ), destructive 或者说 link需要一个 size数字 : sm, (中文(简体) ), md (默认), lg 或者说 icon。 。 。 . loading 禁用按钮并显示旋转器,以及 loadingLabel 设置屏幕阅读器宣布的文本.
import { Button } from '@api7/ui-components';
export function Actions() {
return (
<>
<Button>Save</Button>
<Button variant="outline" size="sm">
Cancel
</Button>
<Button variant="destructive" loading loadingLabel="Deleting">
Delete
</Button>
</>
);
}
看起来像按钮的链接是一个普通锚或路由器链接,其样式为 buttonVariants它的班级与A级相同 Button数字 :
import { buttonVariants } from '@api7/ui-components';
export function DocsLink() {
return (
<a href="/docs" className={buttonVariants({ variant: 'outline' })}>
Docs
</a>
);
}
旋转器
Spinner 是一个旋转的SVG, 它是一个状态, 所以屏幕阅读器宣布它。 它需要一个 size数字 : xs, (中文(简体) ), sm, (中文(简体) ), md (默认)或 lg。它的颜色是文本颜色,所以设置为 text-* 类,以及任何其他 className 合并到 SVG 上.
import { Spinner } from '@api7/ui-components';
<div className="flex justify-center py-12">
<Spinner />
</div>;
事情值得你先知道 在此基础上:
- 所公布的名字是
spinner.label联合国ConfigProvider,则aria-label在旋转器上取而代之,例如说在装什么. - 旋转器会与加载状态一起挂起,屏幕读取器是否宣布插入页面的状态,则由屏幕读取器决定. 要可靠地宣布装入状态, 设置
aria-busy或者说aria-live="polite"放在一个已经放在页面上的容器上,然后把旋转器放进去. - 它不包罗其他要素。 要旋转自己的图标,请添加
animate-spin对它. - 它在用户喜欢减少运动时会停止旋转,然后显示静态图标.
- 它没有定位。 在一个表格或卡片上加载上加载,在使用该表或卡片的地方会建起一个加载上加载上加载上加载的卡片,并带有该地需要的布局.
Button拥有自己的loading道具,用那个按下按钮.
进度栏
Progress 显示任务已实现多远 。 它需要一个 value 介于 min (0)和 max (100个)和a null 值使栏不确定,因为任务长度未知。 它需要一个 size数字 : xs, (中文(简体) ), sm (默认)或 md,是4,6和8px高。 它需要一个 variant数字 : default, (中文(简体) ), success, (中文(简体) ), warning 或者说 destructive,填充的颜色。 栏子填充其容器的宽度,因此将宽度设置在容器上或用 className。 。 。 .
import { Progress } from '@api7/ui-components';
<div className="flex flex-col gap-1">
<div className="flex justify-between text-xs">
<span id="cores-label">Cores</span>
<span>45 / 100</span>
</div>
<Progress value={45} aria-labelledby="cores-label" />
</div>;
事情值得你先知道 在此基础上:
- 没有默认的可访问名称, 因为只有您知道正在发生什么 。 给酒吧一个
aria-label,或一个aria-labelledby指向旁边的文本,如上. - 标签和酒吧周围的号码 都放在你使用的地方 没有标签或价值部分 .
- 变相为固定颜色. 改变所填颜色的条,如将红色变为接近其极限的配额,是一个
variant用它来计算值. - 一个不确定的栏沿轨道滑出一段。 当用户更喜欢减少运动时,它会以半不透明而不是静态段来显示整个音轨,所以它不会被读作部分值. 确定栏的宽度也是动画化的,这也停止了.
- 填充使用每个音调的文字颜色(
primary-text, (中文(简体) ),success-foreground, (中文(简体) ),warning-foreground财务报告和审定财务报表destructive-text因为在两个主题中,这些都停留在3:1对赛道上,而平淡的音调颜色则没有.
表单
@api7/ui-components/form 包装 TanStack 格式. useAppForm 返回其窗体 AppField 手握你准备的田地: TextField, (中文(简体) ), TextareaField, (中文(简体) ), NumberField, (中文(简体) ), SelectField, (中文(简体) ), ComboboxField, (中文(简体) ), DatePickerField, (中文(简体) ), DateRangePickerField, (中文(简体) ), CheckboxField, (中文(简体) ), SwitchField 财务报告和审定财务报表 RadioGroupField数字 :
import { Button } from '@api7/ui-components';
import { useAppForm } from '@api7/ui-components/form';
export function NameForm({ onSave }: { onSave: (name: string) => void }) {
const form = useAppForm({
defaultValues: { name: '' },
onSubmit: ({ value }) => onSave(value.name),
});
return (
<form
noValidate
onSubmit={(event) => {
event.preventDefault();
void form.handleSubmit();
}}
>
<form.AppField name="name" validators={{ onChange: ({ value }) => (value ? undefined : 'Name is required') }}>
{(field) => <field.TextField label="Name" />}
</form.AppField>
<Button type="submit">Save</Button>
</form>
);
}
校验器是TanStack Form中的一种,所以一个函数或一个标准Schema,如zod schema两者都工作. 校验器返回的字符串将在字段下显示.
用另一个表单库
这些字段绘制的窗体行是 LabeledField 从主条目,它不依赖于 TanStack Form。 它的标签, labelTooltip, (中文(简体) ), optional, (中文(简体) ), description 财务报告和审定财务报表 layout 就像上面的田地, 田地状态作为道具: name, (中文(简体) ), invalid, (中文(简体) ), touched, (中文(简体) ), dirty 财务报告和审定财务报表 errors,在 invalid 这是真的。 里面的控制器得到它的ID, aria-invalid 财务报告和审定财务报表 aria-describedby 从球场,所以它被线 与以TanStack的形式. group 为一组控件,如收音机按钮,使带有标签的字段集成为它的传说.
使用反应- hook-form 读取状态 useController 并传入:
import { Input, LabeledField } from '@api7/ui-components';
import { useController } from 'react-hook-form';
export function NameField() {
const { field, fieldState } = useController({ name: 'name', rules: { required: 'Name is required' } });
return (
<LabeledField
label="Name"
name={field.name}
invalid={fieldState.invalid}
touched={fieldState.isTouched}
dirty={fieldState.isDirty}
errors={fieldState.error?.message ? [fieldState.error.message] : []}
>
<Input ref={field.ref} value={field.value} onValueChange={field.onChange} onBlur={field.onBlur} />
</LabeledField>
);
}
invalid 决定错误显示的时间。 领域 /form 一旦球场被触动,就显示它,并反应-hook-forms集 fieldState.invalid 在它自己的验证模式运行后,在默认情况下提交.
加入字段和按钮
InputGroup 加入一个 Input 带有 Button 或一个 InputGroupAddon 进入一个控制。 该团体没有自己的边界、环或状态。 每个部分都保留自己的边框,徘徊,聚焦,无效和被禁用的样式,它们用它们之间的一个分出器来相接,所以字段和按钮读作一个. 只有组外角为圆. 一个 Input (单位:千美元) Button 独立是不会改变的.
import { Button, Input, InputGroup, InputGroupAddon } from '@api7/ui-components';
export function TokenField({ token, onCopy }: { token: string; onCopy: () => void }) {
return (
<InputGroup>
<Input aria-label="Token" readOnly value={token} />
<Button variant="outline" onClick={onCopy}>
Copy
</Button>
</InputGroup>
);
}
export function HostField() {
return (
<InputGroup>
<InputGroupAddon>https://</InputGroupAddon>
<Input aria-label="Host" />
<InputGroupAddon>.example.com</InputGroupAddon>
</InputGroup>
);
}
这些部分是该团体的直系子女,按顺序排列。 一个 InputGroupAddon 是一个块,其遗留主控台的背景为文字、图标或按钮,以及 Button 里面会失去自己的地表 状态属于有它的部分:一个有焦点的字段单独被设定,一个按钮保留它单独站立时的焦点(键盘一个环,一个点击都没有),和一个无效的字段(aria-invalid,或一个 Field 无效)的字段只有无效的边框,因为已禁用字段只有禁用字段的背景。 大纲按钮具有输入的边框颜色。 带有填充的按钮( N)primary, (中文(简体) ), secondary 或者说 destructive保持自己的边缘:休息时,球场的边界朝向它是透明的,所以没有一行横过填充线. 组像一个32px高 Input,部分伸到那个高地, 所以它们不取自己的高地。 将组合放入一个 Field (单位:千美元) FieldLabel 标记其中的字段, 如它所做的任何 Input。 。 。 .
说明清单
DescriptionList 显示只读标签和值对,例如细节页面的字段。 委员会由下列人员组成: DescriptionListItem, (中文(简体) ), DescriptionListLabel 财务报告和审定财务报表 DescriptionListValue,没有数据阵列道具。 为了制作一个记录列表, 绘制您使用它的地方的地图, 并过滤出您不想显示的那些记录 .
import {
DescriptionList,
DescriptionListItem,
DescriptionListLabel,
DescriptionListValue,
Tooltip,
TooltipContent,
TooltipTrigger,
} from '@api7/ui-components';
import { Info } from 'lucide-react';
export function GatewayDetails({ gateway }: { gateway: { id: string; name: string; verifyTls: boolean } }) {
return (
<DescriptionList variant="outline" columns={2}>
<DescriptionListItem colSpan={2}>
<DescriptionListLabel>ID</DescriptionListLabel>
<DescriptionListValue>{gateway.id}</DescriptionListValue>
</DescriptionListItem>
<DescriptionListItem>
<DescriptionListLabel>Name</DescriptionListLabel>
<DescriptionListValue>{gateway.name}</DescriptionListValue>
</DescriptionListItem>
<DescriptionListItem>
<DescriptionListLabel>
Verify TLS
<Tooltip>
<TooltipTrigger aria-label="About Verify TLS">
<Info />
</TooltipTrigger>
<TooltipContent>Verify the certificate of the upstream server.</TooltipContent>
</Tooltip>
</DescriptionListLabel>
<DescriptionListValue>{gateway.verifyTls ? 'Enabled' : 'Disabled'}</DescriptionListValue>
</DescriptionListItem>
</DescriptionList>
);
}
variant 实值 default,无边界的清单,或 outline,它复制了遗留控制台细节页面的相接网格并带有有色标签栏. columns 是数个标签和值对坐一行,默认为 1 。 一个项目需要 colSpan 横跨其中的几个。 分数 columns 或者说 colSpan 将四舍五入,1以下或1以外的数字计为1,a colSpan 大于 columns 减为 columns。 。 。 .
事情值得你先知道 在此基础上:
- 标记是
dl,每个项目都是div拥有一个dt和一个dd,标签和值是相邻的兄弟姐妹,因此测试可以取出标签与下个兄弟姐妹的值. 没有行元素,因为浏览器会用 CSS 网格铺出项目,所以选择项目,而不是行. - 未填入的行, 例如第三个项
columns={2},让其余的行空出. 最后一件东西没有伸展. - 标签栏是160px宽的,如遗留控制台. 设定
--description-list-label-width内style或者说className在列表中更改它. - 一个值可以持有任何内容. 它随内容和长的文字包装而增长,因此不给值一个固定的高度.
- 标签中的工具提示是
Tooltip它的触发器需要一个无障碍的名称, 就像它在其他地方一样.
他们
库主题为应用程序的默认主题. 颜色、光度和字体是 Tailwind 主题变量,例如 --color-primary 财务报告和审定财务报表 --font-sans,该应用程序在导入后在自己的CSS中覆盖它们,因为 用你的尾风CSS 解释一下 光值是页面的值, [data-theme=light] 重复到一个区域 [data-theme=dark] 持有黑暗的价值观。 价值观本身在 src/tokens/semantic.ts。 。 。 .
黑暗模式
设定 data-theme="dark" 打开 <html> 每一个部件都会变暗,包括弹出、对话、抽屉和土司,因为它们会变成 <body> 并继承自 <html>。没有属性,或有其他任何价值 dark,轻主题适用. 删除属性或更改其值会同时重塑页面样式,没有库状态可以保持步入.
库只读取属性. 绝对不会 prefers-color-scheme永远不要存储任何东西 也不要写信 document,因此没有暗黑设计的应用程序不会变暗,因为访客浏览器更喜欢. 选择主题,记住它并遵循系统,如果应用程序想要,就是应用程序的工作. 与 下一个主题 这是 <ThemeProvider attribute="data-theme" defaultTheme="light" enableSystem={false}>,同样的代码也可以设置属性.
color-scheme 也遵循主题,因此滚动条和本地窗体控件匹配.
库定义了 Tailwind dark 变体为: data-theme=dark 元素,所以 dark:bg-muted 在自己的标记中遵循相同的属性。 如果申请自己宣布 @custom-variant dark 导入后,用于 .dark 类或媒体查询,该声明将取代库中的一个,并且 dark: 分类也随之而来。 颜色变量仍然只切换到 data-theme,因此,这样的应用程序会得到灯光符号连同 dark: 调整组件,外观不一。 设定 data-theme 或者不重新定义变体.
具有另一个主题的区域
data-theme="light" 或者说 data-theme="dark" 设置颜色变量和 color-scheme 黑暗的一页可以保持一个光区,反之亦然。 这对颜色变量和 dark: 风格相似。 一个案例的平原 CSS 无法表达是一个暗元素内部的暗元素: 内最暗元素被读作"光" dark: 样式,尽管其变量是正确的.
属性不描绘背景或文字颜色, 因此区域应该看起来像自己的需要的一页 bg-background text-foreground (或你自己的规则) 弹出为 <body>,所以它跟着 <html>而不是打开它的区域。 要以弹出为主题,请将属性放入弹出元素本身(<PopoverContent data-theme="light">,它适用于波波弗、菜单、选择、Combobox、工具提示、对话框和绘图器的内容,因为每个都将其道具传递到弹出元素),或者在弹出内容内部的一个元素上,然后适用于所包装的内容.
在组件中写入暗色样式
一个组件的样式本身带有语义符号,每个符号都有光和暗值,所以大多数组件对于暗模式不需要什么. 当一个黑暗主题需要不同的处理方式而不是一个符号交换时,一个组件可能会添加一个 dark: 类和语义符号(dark:bg-input/30) (中文(简体) ). 原始调色板步骤( E)bg-blue-100由于应用程序的调色板是应用程序自己的,因此完全没有在一个组件中使用. 徽章是每个调色板家族一个有颜色的组件,它读取了私有变量 --badge-<color>-bg 财务报告和审定财务报表 --badge-<color>-fg,该主题为来自 BADGE_STEPS 内 src/tokens/contrast.ts一个品牌的颜色有两个符号,因为一个填充和文本的颜色在黑暗中需要不同的光度: primary 财务报告和审定财务报表 destructive 已填充( 以 primary-foreground 在顶上),同时 primary-text 财务报告和审定财务报表 destructive-text 用于表面的文本和图标,例如按钮链接变体、选定的标签、错误文本或破坏性菜单项。 它们等同光线的填充,所以一个以文字为颜色的页面 text-primary 透过光线,在黑暗中失败对比。 给一个标志 dark: 随处能取出异相. src/theme-classes.test.ts 执行这些规则。 暗号的值在 src/tokens/semantic.ts,并且两个主题的每个文本和表面对都测试WCAG AA in src/tokens/contrast.test.ts。 。 。 .
用你的尾风CSS
其组件为普通的Tailwind公用事业,因此有一款样式表和一款级联. 组件的类别生成到 utilities 应用的层,在自己的公用事业旁边,a className 中,通过一个组件替换设置同一属性的默认类。 通过 p-6 的组件 px-3 仅离开 p-6。 。 。 .
应用程序中的主题有什么变化 :
- 它为 Tailwind 主题添加了语义色彩:
background, (中文(简体) ),foreground, (中文(简体) ),card, (中文(简体) ),popover, (中文(简体) ),primary, (中文(简体) ),primary-text, (中文(简体) ),muted, (中文(简体) ),accent, (中文(简体) ),destructive, (中文(简体) ),success, (中文(简体) ),warning, (中文(简体) ),info, (中文(简体) ),border, (中文(简体) ),input, (中文(简体) ),ring所列其他src/tokens/semantic.ts。名称是常见的,所以一个已经定义了--color-primary或者说--color-muted获得任何最后一个声明的值. - 它设置
rounded-sm至 2px, 缩写为,rounded-md改为 4px 和rounded-lg至 8px,用于应用程序本身的标记。 8px尺寸用于外容器,而现有的控制尺寸保持不变. 其他的radi和整个彩色调色板会随着Tailwind定义而保留. - 它设置
--font-sans。 Tailwind 的主题点--default-font-family,所以 Inter 成为整个应用程序的默认字体,而不仅仅是font-sans函数. - 它定义
dark变量,如 黑暗模式。 。 。 .
要更改颜色, 导入后重新声明变量, 在库所用的相同选择器上, 以使主题和嵌入区域都继续工作 :
@import 'tailwindcss';
@import '@api7/ui-components';
:root,
[data-theme='light'] {
--color-primary: #0b5cff;
}
[data-theme='dark'] {
--color-primary: #6ea0ff;
}
一个 @theme 区块,同一个变量只更改没有的页面根的值 data-theme 属性。 A 类 data-theme 区域,包括 <html data-theme="…">,保留库值,因为库规则不是在一层中,而Tailwind 发音 @theme 值。 使用 @theme 仅针对主题不变的值,例如 --font-sans。 。 。 .
弹出箭头
PopoverContent 默认没有箭头。 添加 PopoverArrow 在它内部,指向在取景口相撞处理起落或翻起弹出时跟随扳机的指针. 箭头使用弹出式背景符并接受 Base UI 箭头道具,包括 className 财务报告和审定财务报表 style 对外观的覆盖.
import { Popover, PopoverArrow, PopoverContent, PopoverTrigger } from '@api7/ui-components';
<Popover>
<PopoverTrigger>View ID</PopoverTrigger>
<PopoverContent align="center" sideOffset={12}>
<PopoverArrow />
ID: service-production
</PopoverContent>
</Popover>;