校对:soup
在 Base UI 和 Tailwind v4 令牌上所建的可访问回放设计系统:按钮,菜单,模式,桌子,土司等. 需要信号的组件,例如 Grid,当它改变时重新放弃,不需要国家管理.
安装
pnpm add @azmr/ui @azmr/core react react-dom
# or
npm install @azmr/ui @azmr/core react react-dom
@azmr/core 是一个 同伴依赖自己安装,这样你的应用程序和 @azmr/ui 共享一份( 两份不兼容) Signal 类型).
样式和设计符号
@azmr/ui 将设计符号和Tailwind v4主题映射成两个样式表。 在您的全球CSS中,选择一个:
@import "tailwindcss";
@import "@azmr/ui/styles.css"; /* tokens + global base rules (new app) */
@import "@azmr/ui/classes.css"; /* or one list per component you use */
@import "tailwindcss";
@import "@azmr/ui/tokens.css"; /* tokens only (app that already has global styles) */
@import "@azmr/ui/classes/button.css";
-
styles.css实值tokens.css加上两个全局基本规则:页面背景和文本颜色body,而我们的边框和外观颜色是每个元素的默认值。 用在一个新的应用程序. -
tokens.css具有同样的同义词、主题、密度、运动和公用事业,以及 改变不了我们自己班外的任何东西。当应用程序已经具有全局风格时使用它:另一个UI库中移,或者一个文档站点. 部件看起来是右侧的. -
按 shadcn/ ui 键名 (单位:千美元)
--background, (中文(简体) ),--primary, (中文(简体) ),--ring, (中文(简体) ),--radius, (中文(简体) ),--sidebar-*因此,从任何注册的阴影组件 看着我们旁边。 阿兹马拉又说--success, (中文(简体) ),--warning, (中文(简体) ),--info, (中文(简体) ),--chart-1改为--chart-8, (中文(简体) ),--motion-*, (中文(简体) ),--elevation-*, (中文(简体) ),--z-*财务报告和审定财务报表--density-*。 。 。 . -
公用事业 例如
bg-background, (中文(简体) ),text-muted-foreground, (中文(简体) ),rounded-lg, (中文(简体) ),shadow-elevation-2财务报告和审定财务报表ease-standard工作从盒子。 导入您使用的每个条目的类列表( E)@azmr/ui/classes/button.css),或@azmr/ui/classes.css对所有人来说,Tailwind生成 包的类。 每个列表都保留着条目使用的类别,所以一个应用程序只支付其进口的组件. -
光和暗 使用 OKLCH 颜色
light-dark()。页面默认跟随系统;强制模式class="dark"编号 :class="light"或者说data-theme="dark|light"任何祖先都一样 没有JavaScript,没有闪光. -
密度 : 设定
data-density="compact"或者说"spacious"以改变控制高度、粘接和行高. -
减少运动: 与
prefers-reduced-motion: reduce,每个--motion-duration-*符号倒塌到0.01ms安全网可以缩短其他动画 将真正必要的动议标出data-motion="essential"。 。 。 . -
测试无障碍性: 每对前地/后地令牌一对在两种模式中都与WCAG AA文本对比(4.5:1)相会,焦点环和图表颜色相会于3:1相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相会相.
主题、密度和地点
服务器布局(Next.js App Router). 从服务器上的 cookie 读取存储首选项, 并将其转换为 <html>,因此第一种颜料已经正确,没有内含脚本(严格CSP下的工作):
// app/layout.tsx
import { cookies } from "next/headers";
import { htmlAttributes, parseDensity, parseThemePreference, THEME_COOKIE, DENSITY_COOKIE } from "@azmr/ui/theme";
import { LocaleProvider, ThemeProvider } from "@azmr/ui/react";
export default async function RootLayout({ children }: { children: React.ReactNode }) {
const jar = await cookies();
const theme = parseThemePreference(jar.get(THEME_COOKIE)?.value);
const density = parseDensity(jar.get(DENSITY_COOKIE)?.value);
return (
<html lang="en-NZ" {...htmlAttributes({ theme, density })}>
<body>
<ThemeProvider defaultTheme={theme} defaultDensity={density}>
<LocaleProvider locale="en-NZ" currency="NZD">{children}</LocaleProvider>
</ThemeProvider>
</body>
</html>
);
}
system(默认)不需要属性和 JavaScript: 符号使用light-dark(),因此页面遵循操作系统.useTheme()返回时{ theme, resolvedTheme, setTheme, density, setDensity }更新更改<html>立即被记起persist={false}关掉它.- 无法在服务器上读取 cookie 的静态站点可以内入
themeInitScript()相反(将您的 CSP 非ce 添加到标签中) . createTheme({ primary, secondary, success, warning, info, destructive, radius, font, density })转换出品牌颜色( e)#rrggbb, (中文(简体) ),oklch(L C H)或者说{ l, c, h })成为符号覆盖. 每个颜色选项都是可选的,省略时保留默认值(destructive是"危险"的颜色。 它保证WCAG AA两种模式,必要时调整光度并保持色调:- 每个
-foreground颜色至少是4.5:1, 包括在坚固的按钮的悬浮表面 (按键与悬浮上页相混合,可以拉出只从4.5:1下经过的颜色;取出时检查该相混合;); success, (中文(简体) ),info财务报告和审定财务报表destructive也可读取为 文本 页面和卡片Text tone,格式错误),以及warning获得单独的可读性--warning-text· ;- 焦距环至少为3:1. 输入被严格验证,因为输出是 CSS,一个错误命名了错误的选项.
- 每个
import { createTheme } from "@azmr/ui/theme";
const theme = createTheme({
primary: "#1E88E5",
success: "#2E7D32",
destructive: "#D32F2F",
radius: "0.5rem",
});
// <style>{theme.css}</style> or <html style={theme.cssVariables}>
当地人. LocaleProvider 默认为 en-NZ, (中文(简体) ), NZD 周一开始. useLocale() 给定缓存 Intl 格式化器( e)formatNumber, (中文(简体) ), formatCurrency, (中文(简体) ), formatDate, (中文(简体) ), formatDateTime)和字符串组件显示(messages,压倒一切。 只约会字符串, 如 2026-10-15 在每个时区打印日历日; 缺少或无效的值格式为空字符串, 而不是扔出.
构成部分
组件只读取设计符号( 没有原始颜色), 接受 className (最后合并,因此可以覆盖默认),向前 ref 到真正的 DOM 元素,并跟随密度符来表示高度和粘贴。 从根或从子道导入;子道和根都具有树能活性.
按钮
import { Button } from "@azmr/ui/button";
<Button>Save</Button>
<Button variant="destructive" loading loadingText="Deleting">Delete</Button>
<Button variant="outline" startIcon={<PlusIcon />}>New customer</Button>
<Button size="icon" aria-label="Close"><XIcon /></Button> {/* icon-only needs a name */}
<Button nativeButton={false} render={<a href="/docs" />}>Docs</Button> {/* renders a link */}
- 备选案文:
default, (中文(简体) ),secondary, (中文(简体) ),outline, (中文(简体) ),ghost, (中文(简体) ),destructive, (中文(简体) ),success, (中文(简体) ),warning, (中文(简体) ),info, (中文(简体) ),link。 。 。 . 大小 :sm, (中文(简体) ),md(按照密度符号),lg, (中文(简体) ),icon。 。 。 . loading数字 : 显示旋转器, 套aria-busy,忽略了点击和键盘激活, 保持可聚焦 (键盘用户保留位置).loadingText装入时替换标签;startIcon由旋转器取代,endIcon留下来.type实值"button"默认,所以表格中的按钮绝不是偶然提交的;通过type="submit"当然.- 只检查图标按钮类型 :
size="icon"需求aria-label或者说aria-labelledby。 。 。 .
投入
import { Input } from "@azmr/ui/input";
import { useForm } from "react-hook-form";
const { register } = useForm();
<label htmlFor="email">Email</label>
<Input id="email" type="email" {...register("email")} /> {/* no Controller needed */}
ref 是真实的 <input>这样 register() {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}直接工作 土著 onChange 键入 onValueChange(value) 两个火. aria-invalid="true" 样式无效状态;焦点使用全强环(WCAG 2.2焦点外观).
旋转器
<Spinner /> 装饰; <Spinner label="Loading customers" /> 宣布为状态。 它不停地旋转 prefers-reduced-motion 因为冷冻的旋转器读作挂起的一页. size (单位:千美元)xs 改为 xl,或 inherit, (中文(简体) ), tone 财务报告和审定财务报表 delay (ms在它消失之前,纯CSS)是可选的.
正在装入
import { Loading } from "@azmr/ui/loading"; // Server Component: fine in loading.tsx
import { LoadingBar, LoadingOverlay } from "@azmr/ui/loading/client";
<Loading label="Loading invoices…" variant="page" /> // a Next loading.tsx
<Loading label="Loading data" logo={<img src="/logo.svg" alt="" />} />
<LoadingOverlay active={isRefetching}>{table}</LoadingOverlay> // dims, aria-busy, spinner on top
<LoadingBar loading={isNavigating} /> // thin bar at the top of the page
图标
Icon 使任何图标组件的大小、中风、运动和无障碍性一致。 这是一个 服务器组件 (没有钩子,没有) "use client"),所以它的工作在 loading.tsx,布局和悬浮倒计时.
import { Icon } from "@azmr/ui/icons";
import { Search } from "lucide-react";
import { IconBell } from "@tabler/icons-react"; // optional: any set, or your own SVG component
<Icon icon={Search} /> {/* decorative: aria-hidden */}
<Icon icon={Search} aria-label="Search" size="lg" /> {/* meaningful: role="img" + name */}
<Icon icon={IconBell} strokeWidth={1.5} />
<Icon icon={Loader} spin /> {/* keeps spinning under reduced motion */}
- 大小 :
xs, (中文(简体) ),sm, (中文(简体) ),md(违约),lg, (中文(简体) ),xl遵循大小符号;数字是像素大小.className最后合并,所以className="size-8"赢了. - 默认可访问 : 装饰性(
aria-hidden除非你通过aria-label或者说aria-labelledby。仅由图标的按钮由标签图标命名. - 带任何一套. Lucide( ISC) 是默认值; Taller( MIT) 和您自己的 SVG 组件通过同一程序工作
icon无适配器的道具.react-icons故意不捆绑:它通过精确的子路径进口来混合许可证和树摇. - 树摇被测试: 图标核心完全不捆绑图标, 和一个只导入图标的图标捆绑的应用程序.
以名为相. 从大多数到最不孤立的三种方式:
// 1. The curated Lucide set, with typed names (about 60 everyday icons; Lucide's own kebab-case names)
import { Icon } from "@azmr/ui/icons/lucide";
<Icon name="circle-alert" />
// 2. Your own typed set: nothing global, only the icons you list are bundled
import { createIconSet } from "@azmr/ui/icons";
export const { Icon } = createIconSet({ check: Check, "my-logo": MyLogo });
// 3. A global registry for custom SVGs (names are untyped strings)
import { registerIcons } from "@azmr/ui/icons";
registerIcons({ "my-logo": MyLogo }); // then <Icon name="my-logo" />
一个未知的名称会让一个开发警告无所事事并日志; 它永远不会崩溃页面 .
从 @mui/icons-material。 。 。 . @azmr/ui/icons/mui-map 是纯数据 : resolveMuiIcon("SearchOutlined") 返回时 { name: "Search", variant: "outlined", lucide: "search", tabler: "IconSearch" }它覆盖300多块通用材料图标 Outlined 编号 : Rounded 编号 : Sharp 编号 : TwoTone 变体(和遗产) Outline 拼写旧的 MUI 版本导出),仅将品牌图标映射到 Tabler (Lucide 没有), 并列出它故意不映射的常见名称 unmappedMuiIcons。里面的每个名字都通过测试来检查真实的 @mui/icons-material, (中文(简体) ), lucide-react 财务报告和审定财务报表 @tabler/icons-react。 迁移代码模块使用它, 并报告任何未刷新而非猜测 .
入境点
| 导入 | 目录 | 指令 |
|---|---|---|
@azmr/ui | 所有东西( a)Grid, (中文(简体) ), useSignal, (中文(简体) ), cn(中文(简体) ) | "use client" |
@azmr/ui/hooks | 反应钩子( R)useSignal, (中文(简体) ), useDebouncedCallback, (中文(简体) ), useDebouncedValue, (中文(简体) ), useReducedMotion, (中文(简体) ), useUrlTab(中文(简体) ) | "use client" |
@azmr/ui/theme | 服务器安全主题助手 : createTheme饼干, htmlAttributes, (中文(简体) ), createLocale | 无, 从服务器组件和中间软件可导入 |
@azmr/ui/react | ThemeProvider, (中文(简体) ), useTheme, (中文(简体) ), LocaleProvider, (中文(简体) ), useLocale | "use client" |
@azmr/ui/button | Button, (中文(简体) ), buttonVariants | "use client" |
@azmr/ui/input | Input, (中文(简体) ), Textarea | "use client" |
@azmr/ui/input-group | InputGroup, (中文(简体) ), InputGroupInput, (中文(简体) ), InputGroupAddon, (中文(简体) ), InputGroupButton | "use client" |
@azmr/ui/password-input | PasswordInput, (中文(简体) ), passwordRequirements, (中文(简体) ), defaultPasswordScorer | "use client" |
@azmr/ui/number-field | NumberField, (中文(简体) ), MoneyField, (中文(简体) ), numberOrNull | "use client" |
@azmr/ui/field-array | FieldArray (重复行:添加,去除,拖放或键盘重排,总计) | "use client" |
@azmr/ui/rhf | Form, (中文(简体) ), FormField, (中文(简体) ), FormErrorSummary, (中文(简体) ), FormFieldArray (反应钩形式7,可选对等) | "use client" |
@azmr/ui/zod | zodResolver, (中文(简体) ), fieldsFromSchema, (中文(简体) ), fieldFromSchema, (中文(简体) ), toFieldErrors (Zod 4,可选对等点) | 无, 服务器安全 |
@azmr/ui/field | Field, (中文(简体) ), FieldRoot, (中文(简体) ), FieldLabel, (中文(简体) ), FieldDescription, (中文(简体) ), FieldError | "use client" |
@azmr/ui/form | Fieldset, (中文(简体) ), FieldsetRoot, (中文(简体) ), FieldsetLegend, (中文(简体) ), FormSection, (中文(简体) ), ErrorSummary, (中文(简体) ), toErrorSummaryItems | "use client" |
@azmr/ui/spinner | Spinner (单位:千美元)size, (中文(简体) ), tone, (中文(简体) ), delay(中文(简体) ) | 无,可以从服务器组件导入 |
@azmr/ui/loading | Loading (内置、部分或页;可见标签;带有旋转环的标志), Spinner | 无,可以从服务器组件导入 |
@azmr/ui/state-view | StateView (一个区域装入状态、 空状态和出错状态的布局) | 无,可以从服务器组件导入 |
@azmr/ui/error-boundary | ErrorBoundary (单位:千美元)onError 报告钩, reset, (中文(简体) ), resetKeys, (中文(简体) ), rethrow 框架错误) | "use client" |
@azmr/ui/loading/client | LoadingOverlay, (中文(简体) ), LoadingBar (上页栏), useLoadingState (单位:千美元)delay 财务报告和审定财务报表 minDuration(中文(简体) ) | "use client" |
@azmr/ui/icons | Icon, (中文(简体) ), createIconSet, (中文(简体) ), registerIcons | 无,可以从服务器组件导入 |
@azmr/ui/icons/lucide | Icon 被捆绑在Lucide的套房里, lucideIcons | 无,可以从服务器组件导入 |
@azmr/ui/icons/mui-map | resolveMuiIcon, (中文(简体) ), muiIconMap, (中文(简体) ), unmappedMuiIcons (移徙数据) | 无, 纯数据 |
@azmr/ui/lib | cn() 和其他服务器安全助手 | 无,可以从服务器组件导入 |
cn(...classes) 合并类名并解决矛盾的 Tailwind 公用事业, 最后一位获胜: cn("p-2", "p-4") → "p-4"。 。 。 .
网格
import { Signal } from "@azmr/core";
import { Grid } from "@azmr/ui";
const customers = new Signal([
{ name: "Aroha", balance: 150 },
{ name: "Mere", balance: 320 },
]);
function App() {
return (
<Grid
signal={customers}
labels={{ name: "Customer", balance: "Balance ($)" }}
/>
);
}
// Grid updates automatically
customers.set([...customers.peek(), { name: "Tane", balance: 0 }]);
使用符号
Hook 将任何反应组件订阅到信号上 .
import { useSignal } from "@azmr/ui";
function Counter({ count }: { count: Signal<number> }) {
const value = useSignal(count); // push-based, no polling
return <span>{value}</span>;
}
网格道具
| Prop | 类型 | 说明 |
|---|---|---|
signal | Signal<T[]> | 反应数据源 |
columns | (keyof T)[] | 可选列顺序 |
labels | Partial<Record<keyof T, string>> | 可选列标签覆盖 |
emptyMessage | string | 信号为空时显示的消息 |
所有细胞值都是通过 React 的 JSX 逃出—— dangerouslySetInnerHTML 从未使用.
所需资源
- 节点.js 18
- 反应 18 或 19
- TypeScript 第 5 (包括类型)
文档
完整文件时间 互联网档案馆的存檔,存档日期2013-12-02
许可证
麻省理工学院 阿兹马拉实验室