Customization

Lint 规则

由 Lint 强制的治理规则——表单控件、焦点环、图标三层等级。

仓库通过 pnpm lint(Biome v2 + 自定义脚本)强制执行三类治理规则。违规的新代码会让 CI 失败;现有例外见下文。

表单控件规则

apps/**禁止使用原生 <input> / <textarea> / <select>。请改用 @nebutra/ui/primitives 中的原语:

import {
  Input,
  Textarea,
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
  Field,
  Checkbox,
  RadioGroup,
} from "@nebutra/ui/primitives";

<Field label="Email *" htmlFor="email">
  <Input id="email" type="email" name="email" required />
</Field>

<Field label="Plan *" htmlFor="plan">
  <Select name="plan" defaultValue="pro">
    <SelectTrigger id="plan">
      <SelectValue />
    </SelectTrigger>
    <SelectContent>
      <SelectItem value="pro">Pro</SelectItem>
      <SelectItem value="enterprise">Enterprise</SelectItem>
    </SelectContent>
  </Select>
</Field>

原生豁免

对合法场景(隐藏字段、配合自定义按钮触发的 type="file"、需要空字符串「全部」语义的过滤 select 等)添加 data-allow-native 属性即可豁免:

<input data-allow-native type="hidden" name="orgId" value={orgId} />

<input data-allow-native type="file" ref={inputRef} className="sr-only" />

<select
  data-allow-native
  value={filters.outcome ?? ""}
  onChange={(e) => setOutcome(e.target.value || null)}
>
  <option value="">全部</option>
  <option value="success">成功</option>
  <option value="failure">失败</option>
</select>

强制方式

  • 脚本scripts/lint-no-raw-inputs.mjs(在 pnpm lint 中调用)
  • 白名单:Storybook Story、design-docs / sailor-docs 预览、测试文件、所有 packages/**/primitives/**

焦点环规则

不要在组件层加 focus:ring* packages/design/design-tokens/static/base.css 中的全局 :focus-visible 规则会为每个可聚焦元素自动添加 2px 半透明描边(hsl(var(--ring) / 0.5))与 2px 偏移。键盘用户获得焦点环;鼠标用户不会触发。

// ✅ 正确 —— 无需任何 focus 类
<button type="button" aria-label="关闭对话框" className="rounded-md p-1">
  <X className="h-4 w-4" />
</button>

// ✅ 正确 —— input 通过 border 颜色变化提供鼠标聚焦反馈
<input className="rounded-md border border-neutral-7 focus:border-[hsl(var(--ring))] focus:outline-none" />

// ❌ 错误 —— 重新引入 100% 饱和度的品牌蓝环,与全局规则双环叠加
<button className="focus:ring-[var(--blue-9)] focus:ring-offset-1">…</button>

仅当某个组件确实需要不同的环时才覆写(极少见),并提前与设计体系维护者沟通。

图标治理(三层)

只允许三个图标库,每个有明确的唯一位置:

层级适用场景
1 —— 默认@nebutra/icons(Geist 541)全部产品 / 应用 / 控制台界面。视觉与 Vercel、v0 一致。
2 —— 营销@phosphor-icons/react/light仅限 packages/design/ui/src/marketing/**,提供 AI 品牌的细描 / 双色调表现。
3 —— 弃用lucide-react禁止新增任何引用。 已于 2026-05-14 清扫所有历史用例;后续新增直接 lint 失败。
// ✅ 默认(产品界面)
import {
  MagnifyingGlass,
  SettingsGear,
  ChevronRight,
  Sparkles,
} from "@nebutra/icons";

// ✅ 营销(AI 品牌强调使用的细描 / 双色调) —— 仅允许在受限目录
import { Brain } from "@phosphor-icons/react/dist/ssr";
// 仅允许在 packages/design/ui/src/marketing/** 内

// ❌ 新代码中禁止
import { Search } from "lucide-react";

同时禁止: 在产品代码内手写 <svg> 图标路径,请从层 1 / 2 中选择。数据可视化原语(如 Gauge)使用 SVG 数学绘制仍然允许。

Console 规则

生产代码禁止 console.log,改用 @nebutra/logger

import { logger } from "@nebutra/logger";

logger.info({ tenantId }, "subscription.activated");

Biome 允许 console.warnconsole.errorconsole.assert 用于显式告警 / 错误路径。

相关内容

How is this guide?

目录