@cueplusplus/ui

中文文档
0.34.2发布于 2026/11/09MITTypeScriptES Module近 30 天下载 3897

CUE++ design system components: Tailwind v4 styled wrappers over Base UI, driven by @cueplusplus/tokens.

原始使用文档
文档目录9 节
  1. Install
  2. Quick start
  3. What it ships
  4. Showing a component: Preview , Inspector , CodeBlock
  5. Preview — one component on a stage
  6. Inspector — the layout of a settings panel
  7. CodeBlock — code with a caption and a copy button
  8. The machine-readable half
  9. Where the rest is

@cueplusplus/ui

Components for console software: dense, keyboard-first interfaces where a screen is mostly data. Base UI underneath for behaviour and accessibility, Tailwind v4 on top for the paint.

Install

The @cueplusplus scope is public on npm and resolves there by default, so there is nothing to configure and no credential to supply — it installs like any other package.

pnpm add @cueplusplus/ui @cueplusplus/tokens @cueplusplus/theme-cue @base-ui/react

Three peers are required and declared: react ^19, react-dom ^19 and @base-ui/react ^1.7. tailwindcss ^4 is a declared peer too, but an optional one — needed for the default styling lane, and without it you own the CSS. Every other peer is optional and scoped to a subpath. @cueplusplus/tokens arrives as a dependency; installing it by name just makes the token constants importable in your own code. The theme package is not a peer at all — see below.

CI, Vercel and the token's expiry are in docs/CONSUMING.md §1.

Quick start

/* app/globals.css */
@import "tailwindcss";
@import "@cueplusplus/ui/styles.css";
@import "@cueplusplus/theme-cue/theme.css";
import cue from "@cueplusplus/theme-cue";
import { Button } from "@cueplusplus/ui";
import { ThemeProvider } from "@cueplusplus/ui/system";

export default function App() {
  return (
    <ThemeProvider themes={[cue]} theme="cue" density="compact" mode="system">
      <Button variant="primary">Run cue</Button>
    </ThemeProvider>
  );
}

The order of those three @imports is load-bearing, and the themes prop is not optional in practice: this library contains no palette. Install and register a @cueplusplus/theme-* package, or every surface paints @cueplusplus/theme-base's blank base — greys, one desaturated accent, the platform monospace — with nothing erroring to tell you.

To stop the defaults flashing on first paint, add prepaintScript() beside the provider and hand both the same array — §4 of CONSUMING.md is the whole layout.

Beside theme and mode, the provider takes four axes, and each one changes a single thing: density the geometry, font the typeface pairing, styleSet the page composition, and paint the finish — rims, strokes, elevation, glow, glass, texture and edge fades. paint is off unless you ask for it: the provider stamps no data-paint, so a page looks exactly as it did until you pass one of none, halo, hatch, lift, frost, bevel or grain. Any subtree can take its own with <Density paint="frost"> — the same island that re-scopes density and styleSet. The font pairing is the one axis a subtree cannot change: it lives on <html>, so it is the root's.

import cue from "@cueplusplus/theme-cue";
import { ThemeProvider } from "@cueplusplus/ui/system";

export function App({ children }: { children: React.ReactNode }) {
  return (
    <ThemeProvider themes={[cue]} theme="cue" density="compact" mode="system" paint="halo">
      {children}
    </ThemeProvider>
  );
}

The ten packs, where each was measured from and what each refuses: https://ui.cueplusplus.com/docs/paint. Serving a nonce-based Content-Security-Policy? Read §4.5 of CONSUMING.md before you ship it — paint="grain" alone needs img-src data:.

What it ships

Common components come from the root entry. Groups that need an optional peer have a subpath of their own, so importing a button never pulls a charting library into your bundle.

Import specifierWhat is in it
@cueplusplus/uithe root barrel: every component that costs no optional peer, the brand marks and the container icons included
@cueplusplus/ui/primitivesthe leaves: buttons, chips, avatars, dots and the two loading shapes
@cueplusplus/ui/formseverything a user types into, toggles, picks from or drags
@cueplusplus/ui/overlayseverything that floats: dialogs, sheets, menus, tooltips, the command palette
@cueplusplus/ui/chromeconsole furniture: panels, rows, bars, tabs, the tree outline and the Inspector layout
@cueplusplus/ui/layoutpage structure: cards, stacks, grids, Bento, the Preview frame, disclosure and the navigation shapes
@cueplusplus/ui/layout/carouselneeds embla-carousel-react
@cueplusplus/ui/layout/resizableneeds react-resizable-panels
@cueplusplus/ui/instrumentsthe readouts: meters, sparklines, tables, logs, CodeBlock and the two device frames
@cueplusplus/ui/instruments/data-tableneeds @tanstack/react-table
@cueplusplus/ui/instruments/log-viewerneeds @tanstack/react-virtual, anser
@cueplusplus/ui/chartsRecharts in this system's tokens, plus the categorical palette and the ramps; needs recharts
@cueplusplus/ui/datecalendars, pickers and segmented date/time fields; needs react-day-picker, date-fns, react-aria-components, @internationalized/date
@cueplusplus/ui/colorthe picker suite the configurator edits with, hex and oklch; needs react-aria-components
@cueplusplus/ui/configuratorthe floating panel that edits the token layer live and exports what it edited; needs react-aria-components
@cueplusplus/ui/flowReact Flow wearing the tokens: node cards, handles, signal-carrying wires; needs @xyflow/react (+ ./flow.css)
@cueplusplus/ui/chatthe multi-agent transcript: messages, composer, HITL questions, agent colour
@cueplusplus/ui/agent-runtimethe streaming layer under Chat; needs @assistant-ui/react
@cueplusplus/ui/elementsthe agent's own surface, vendored from assistant-ui and repainted onto the tokens; needs lucide-react and heat-graph (+ ./elements.css)
@cueplusplus/ui/elements/markdownMarkdownText; needs react-markdown, rehype-sanitize, micromark-extension-gfm-table, mdast-util-gfm-table
@cueplusplus/ui/elements/generativethe generative-UI renderer and its spec (+ ./elements/generative.css)
@cueplusplus/ui/elements/replaythe scripted session-replay frame
@cueplusplus/ui/dmx512 bytes at wire rate: the bar, the strip, the patch bar, the channel grid
@cueplusplus/ui/midisequencer instruments: keyboard, musical clock, ruler, analyser, threshold rail
@cueplusplus/ui/systemThemeProvider, prepaintScript, the Density island, the portal frame, isSafeTokenValue
@cueplusplus/ui/themingcreateTheme(), contrastReport() and the --cue-* vocabulary as constants

Four stylesheet exports. @cueplusplus/ui/styles.css is always imported; the other three are imported only if you use what they paint — @cueplusplus/ui/elements.css, @cueplusplus/ui/flow.css and @cueplusplus/ui/elements/generative.css.

Showing a component: Preview, Inspector, CodeBlock

Three pieces for a page that shows components rather than only using them — a docs page, a design review, a settings screen with a live sample. Each is exported from the root barrel as well as from its group's subpath, and none needs an optional peer.

Preview — one component on a stage

From @cueplusplus/ui/layout. A frame with a stage for the specimen, a tools slot at the top right and a footer. label is required, because the frame is a role="group" named by it. The stage can carry its own theme, mode, density and font; with none of them set it carries no attribute and inherits the page.

A stage theme needs that theme's stylesheet on the page. Naming a theme does not load it: the stage is scoped with [data-theme="<name>"], so @cueplusplus/theme-<name>/theme.css has to be imported like any other palette, or the stage paints the blank base with nothing erroring. The example below shows terminal on a cue page, so both are imported and both are registered:

/* app/globals.css */
@import "tailwindcss";
@import "@cueplusplus/ui/styles.css";
@import "@cueplusplus/theme-cue/theme.css";
@import "@cueplusplus/theme-terminal/theme.css";
import cue from "@cueplusplus/theme-cue";
import terminal from "@cueplusplus/theme-terminal";
import { Chip } from "@cueplusplus/ui";
import { Preview } from "@cueplusplus/ui/layout";
import { ThemeProvider } from "@cueplusplus/ui/system";

export default function ChipPage() {
  return (
    <ThemeProvider themes={[cue, terminal]} theme="cue" density="compact" mode="system">
      <Preview label="Chip preview" theme="terminal" resizable footer="terminal · compact">
        <Chip tone="accent">Standby</Chip>
      </Preview>
    </ThemeProvider>
  );
}
  • Only the stage changes theme. tools, footer, the resize grips and anything they open stay in the page's theme, so the controls that drive a specimen always look like the page around them.
  • resizable adds a grip per axis, 160–1280 × 96–960 px by default, that works by pointer and by keyboard (arrows step 8 px, Shift+arrow 64 px). Pass { axis, minWidth, maxWidth, minHeight, maxHeight } to narrow it. A resizable Preview fills its container's width.
  • It is a client component ("use client").

Inspector — the layout of a settings panel

From @cueplusplus/ui/chrome. Titled sections of label-and-control rows, then a footer — the shape of a properties sidebar or a wrench menu. The controls are the library's own.

import { Button, Input, SegmentedControl } from "@cueplusplus/ui";
import { Inspector } from "@cueplusplus/ui/chrome";

const sizes = [
  { value: "sm", label: "Small" },
  { value: "md", label: "Medium" },
  { value: "lg", label: "Large" },
];

export function ButtonInspector() {
  return (
    <Inspector.Root>
      <Inspector.Section label="Variants">
        <Inspector.Row label="Size">
          <SegmentedControl items={sizes} defaultValue="md" />
        </Inspector.Row>
        <Inspector.Row label="Label" htmlFor="button-label">
          <Input id="button-label" defaultValue="Run cue" />
        </Inspector.Row>
      </Inspector.Section>
      <Inspector.Footer note="preset · primary" action={<Button size="sm">Reset</Button>} />
    </Inspector.Root>
  );
}
  • A row names its control. With htmlFor the label is a <label> for that id; without it the row lays label on the control as aria-label, unless the control already names itself.
  • A row is one column until the Inspector is 18rem wide, then label beside control. It is a container query, so it follows the popover or sidebar the Inspector sits in, not the viewport.
  • Inspector itself has no hooks and no "use client", so a server component can render it.

CodeBlock — code with a caption and a copy button

From @cueplusplus/ui/instruments.

import { CodeBlock } from "@cueplusplus/ui/instruments";

export function ButtonSource() {
  return <CodeBlock label="button.tsx" language="jsx" code={'<Button variant="primary">Run cue</Button>'} />;
}
  • code is printed verbatim, and the copy button copies exactly that. label is the caption and defaults to the language; language defaults to "tsx".
  • There is no syntax-highlighter palette. language="jsx" picks out tag names, attribute names and punctuation in three inks the theme already has; every other language prints plain.

The machine-readable half

This package ships its own manifest: @cueplusplus/ui/manifest.json is an index of every component with a SHA-256 for each companion document, and @cueplusplus/ui/manifest/components/<name>.json is one component in full — props, variants, the tokens it paints with, and the hand-written notes on when it is the wrong choice. Beside them, @cueplusplus/ui/manifest/tokens.json is the token vocabulary and @cueplusplus/ui/manifest/fixtures.json the playground fixture catalogue. An agent or a code generator should read those rather than guess a prop name.

The same surfaces are published at https://ui.cueplusplus.com, with the docs site, the live kitchen sink and the CUE++ agent skills beside them.

Where the rest is

版本与发布记录

@cueplusplus/ui 共发布 46 个版本,首次发布于 2026/09/16;过去 12 个月发布了 46 个版本。

版本发布日期距今
0.34.2latest2026/11/092 天前
0.34.12026/10/2715 天前
0.34.1-dev.1793042906377dev2026/10/2715 天前
0.34.02026/10/2615 天前
0.34.0-dev.17930064848772026/10/2615 天前
0.33.02026/10/2615 天前

其他发布通道:historical → 0.12.0,dev → 0.34.1-dev.1793042906377。

关于 @cueplusplus/ui 的常见问题

@cueplusplus/ui 是什么?

CUE++ design system components: Tailwind v4 styled wrappers over Base UI, driven by @cueplusplus/tokens.

如何安装 @cueplusplus/ui?

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

@cueplusplus/ui 支持 TypeScript 吗?

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

@cueplusplus/ui 支持 ESM 还是 CommonJS?

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

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

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

@cueplusplus/ui 可以商用吗?

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

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

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

@cueplusplus/ui 还在维护吗?

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