@danxbot/ui

中文文档
35.1.0发布于 2026/11/06MITTypeScriptES Module近 30 天下载 3.9万

50 Arms — a domain-agnostic React design system with motion as a first-class primitive.

原始使用文档
文档目录12 节
  1. What is in it
  2. The parts worth knowing about
  3. Motion is a layer, not a decoration
  4. Both themes come from one contract
  5. Accessibility is a floor you can opt into
  6. Size is a multiplier, not a breakpoint
  7. Chat messages are typed parts
  8. The library names its own richer alternatives
  9. Setup
  10. Browser support
  11. Running the tests
  12. Licence

@danxbot/ui

A React design system with motion as a foundation, not a finish pass.

npm install @danxbot/ui
import { Button, Chat, ThemeMenu } from "@danxbot/ui";
/* your app's Tailwind entry — see Setup, all three lines are required */
@import "tailwindcss";
@import "@danxbot/ui/theme.css";
@import "@danxbot/ui/styles.css";

Requires React 19 and Tailwind CSS 4 in the consuming build — the package ships no compiled utilities, on purpose. MIT licensed.

What is in it

102 components across forms, overlays, structure, data, layout and chat.

Forms — Field, FieldSet, Input, Textarea, Checkbox, Switch, Radio, RadioCard, Select, Combobox, MultiCombobox, Slider, NumberInput, OTPInput, FileUpload, DatePicker, Toggle, ToggleGroup, Toolbar

Overlays — Dialog, AlertDialog, Popover, Tooltip, Toast, Menu, CommandPalette

Structure — Card, Tabs, Accordion, Breadcrumb, Pagination, AppShell, Separator, ScrollArea, Collapsible, PanelGroup

Display — Avatar, Progress, Meter, ProgressRing, Stat, Sparkline, Timeline, Tree, EmptyState, Badge, Icon, Spinner, Skeleton, LoadingOverlay

Data — DataTable

Chat — Chat, Message, MessageScroller, Composer, Markdown, CodeBlock, ToolCall, Attachment, ModelSelector, EffortControl, ContextMeter

The parts worth knowing about

Motion is a layer, not a decoration

Four spring curves are baked as CSS linear() easings. A spring curve encodes its damping ratio — its shape — and nothing else, so duration stays a free parameter and one curve is correct at any speed. There is no JavaScript animation runtime; the equivalent costs 35–40 KB to do what these do for free.

Reduced motion reduces. The usual animation-duration: 0.01ms !important sweep is wrong twice over: the spec asks for motion removed, reduced or replaced, and !important makes the decision unoverridable. Instead --motion-scale halves durations and --motion-travel zeroes distances, so components inherit the preference without knowing it exists.

Both themes come from one contract

Colour is a three-tier OKLCH system — primitives, semantic tokens, component tokens — and both themes are written against the same semantic names. Dark accents are hand-tuned at roughly 20% reduced chroma, because a large saturated fill on a dark surface reads as glare rather than emphasis.

Accessibility is a floor you can opt into

Contrast compliance is a switch (data-contrast="aa"), not a permanent state. Forcing AA everywhere flattens hierarchy: de-emphasised text stops being de-emphasised. The default is the palette as drawn; the AA overlay is one attribute away and honours prefers-contrast: more on first load.

Size is a multiplier, not a breakpoint

data-ui-scale sets a unitless multiplier over rem, which composes with the reader's own browser font size instead of overriding it. It moves type, spacing, control heights and icon sizes together, with hard floors so a tap target never drops below 24px.

Chat messages are typed parts

A message is a list of parts — text, code, reasoning, tool call, file, or a named application component — never a blob of markdown. An assistant turn routinely interleaves prose, a tool call and a confirmation button, and each is a different rendering problem. Applications register their own components by name, so a message can carry working UI:

<Chat
  messages={messages}
  components={{
    approval: (props, ctx) => (
      <ApprovalCard {...props} onApprove={ctx.app.approve} />
    ),
  }}
  appContext={{ approve }}
/>

Props are plain data and components are addressed by name, so a transcript stays serialisable — a component reference in the message would make it impossible to persist or replay.

The library names its own richer alternatives

COMPONENT_GUIDANCE (exported from the package root) is a data table, not a doc page: for each basic primitive — and each native-HTML/ARIA shape this library replaces outright — it names the richer component that usually fits better and why (Textarea → InlineMarkdownEdit/MarkdownEditor for prose, a <pre> → Markdown, a ghost text Button → IconButton, and so on). A consuming repo's own source scan reads this table instead of hard-coding the same list, so a new richer component added here extends every consumer's enforcement with no edit on their side. The rule of thumb it encodes: for each piece of data, use the most capable component that fits it, with inline editing in place as the default interaction — a plainer primitive is sometimes still correct, and that is what a consumer's own escape-hatch comment is for, not a reason to leave the table incomplete.

Setup

Two stylesheets, and you want both. In your application's Tailwind entry:

@import "tailwindcss";
@import "@danxbot/ui/theme.css";   /* @source + the @theme bridge */
@import "@danxbot/ui/styles.css";  /* the token values, base layer and component CSS */

That is the whole contract. There is no layer-order statement to remember and no path to configure.

Your Tailwind build compiles this library's utilities, not ours. theme.css carries @source "./**/*.js", which points your compiler at the shipped modules; the package itself ships zero generated utilities. That is deliberate and it is the fix for a real defect: a compiled stylesheet emits into @layer utilities, which is the same layer name your build uses, at equal specificity, imported last — so the library used to win every tie. Measured in a consuming app at 1440px, grid grid-cols-1 xl:grid-cols-[1.6fr_1fr] rendered one column and md:grid-cols-2 xl:grid-cols-3 rendered two. Nothing was misused; xl: is supposed to beat md: because Tailwind sorts breakpoints, and that guarantee only holds inside one compiler's output. So there is one compiler.

theme.css also carries the @theme bridge, extracted from source at build time, mapping every semantic token onto Tailwind's namespaces — without it your own bg-accent-subtle compiles to nothing, silently. Order matters: styles.css comes after, because it supplies the values the bridge points at.

Not using Tailwind 4? Then this package will not style anything: you get the tokens, the base layer and the hand-written component CSS, and no utilities at all. Components render structurally correct and visually unstyled — loudly, on the first screen, rather than as one breakpoint quietly misbehaving. Tailwind 4 in the consuming build is a requirement, not a recommendation.

Fonts are self-hosted woff2 subsets rather than CDN-loaded, because a blocked CDN renders every design in a system font with no error anywhere. They are pulled in by styles.css; @danxbot/ui/fonts.css exposes the @font-face rules on their own if you need them separately.

Preferences are read from <html> attributes so plain CSS and portalled content both see them:

import { useTheme, useUiScale, useContrast, useMotionPreference } from "@danxbot/ui";

ThemeMenu bundles all four into one popover.

Browser support

Modern evergreen browsers — Chrome, Safari, Firefox and modern mobile. That choice is what makes @property, @starting-style, container queries, field-sizing and OKLCH available without fallbacks.

Running the tests

The vitest suite runs in one place: a Linux Docker container built from Dockerfile.test. npm test builds the image (cached until package-lock.json changes), streams this checkout's git-visible files into a container, runs vitest there and removes the container. Nothing from this machine is mounted and no node_modules is shared.

npm test                                # the whole suite
npm test -- src/__tests__/board.test.tsx   # named files
npm run test:dist                       # the whole suite with the built dist/ copied in (what `verify` and `release` run)
npm run probe:slider                    # the slider browser probe against the built demo (needs `npm run build:demo`), same container
node scripts/test-in-container.mjs --script probe-scale audit-hover a11y-scan   # any browser probe, audit or screenshot script, in order, in one container
npm run probe                           # every browser probe (needs `npm run build:lib` and `npm run build:demo`)
npm run audit                           # every audit
npm run visual                          # the Playwright visual suite, in the Playwright container (`visual:update` re-records baselines)

A vitest run anywhere else (a Windows checkout, a bare WSL shell) refuses before any test runs and names this command. So does every browser probe, audit and screenshot script (scripts/probe-*.mjs, scripts/audit-*.mjs, a11y-scan, shoot*), and a bare playwright test refuses outside the Playwright container. Nothing runs in CI: there is no workflow.

Licence

MIT

版本与发布记录

@danxbot/ui 共发布 473 个版本,首次发布于 2026/08/26;过去 12 个月发布了 473 个版本。

版本发布日期距今
35.1.0latest2026/11/065 天前
35.0.12026/11/056 天前
35.0.02026/11/047 天前
34.3.02026/11/047 天前
34.2.02026/11/028 天前
34.1.02026/11/029 天前

关于 @danxbot/ui 的常见问题

@danxbot/ui 是什么?

50 Arms — a domain-agnostic React design system with motion as a first-class primitive.

如何安装 @danxbot/ui?

在项目目录运行 npm install @danxbot/ui,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react(^19)、react-dom(^19)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@danxbot/ui 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@danxbot/ui 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@danxbot/ui 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=20。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@danxbot/ui 可以商用吗?

@danxbot/ui 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@danxbot/ui 的下载量有多少?

根据 npm 官方下载统计,@danxbot/ui 在 2026/10/12 – 2026/11/10 这 30 天内被下载 38,988 次,日均约 1,300 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@danxbot/ui 还在维护吗?

最新版本 35.1.0 发布于 2026/11/06(5 天前);至今共发布 473 个版本,其中过去 12 个月发布了 473 个;首次发布于 2026/08/26。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。