Communitygithub.com

多应用共享组件库整合

将多个应用或原型整合到一份共享组件库中,同时保留各自外观。涵盖查找重复本地组件、将共享组件设计为令牌驱动、映射变体名称、决定哪些内容保留在应用层面,以及 tailwind-merge 中会静默破坏自定义令牌的陷阱。

多应用共享组件库整合 是什么?

本技能针对多个独立发展的应用(如 app A、app B 等)中出现大量重复组件(如 Btn、Select、Modal)的问题,提供一套系统化的解决方案。核心思路是将共享组件设计为“令牌驱动”:组件只负责行为、标记和状态,所有尺寸、圆角、间距等度量值都通过 CSS 主题令牌(如 `--spacing-btn-md`)由各应用或主题独立设定。技能详细指导用户如何清点各应用的本地组件副本,并逐步用令牌化共享组件替换,同时明确映射本地变体名到共享变体名(如 primary → accent)。它还强调了几个关键陷阱:tailwind-merge 的 `cn()` 函数无法自动识别自定义尺寸令牌,会导致样式覆盖失败;验证和焦点环的 CSS 特异性问题;以及 `button` 元素在表单中的默认提交行为。该技能适用于多个应用共享组件库、设计系统难以适配第二款产品、或需要对系列应用进行重新主题化的场景,支持 React/TypeScript 技术栈及 Tailwind CSS。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Adamparishspok/skills/tree/HEAD/skills/multi-app-design-system

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

多应用,同一组件库

常见的失败模式:为应用 A 构建了一套组件库,应用 B 的按钮高 4 像素、圆角大 2 像素,于是 B “就这一次”复制了按钮。五个应用之后,出现了六个按钮、八个下拉框和三个模态框,做的却是同一件事。

让共享组件变成令牌驱动:它只承载行为、标记和状态,每个主题提供自己的度量值。然后逐个应用进行整合。

令牌驱动组件

将所有应用间有差异的度量值读取自主题令牌:

@theme {
  --spacing-btn-sm: 1.75rem;  --spacing-btn-px-sm: 0.625rem;
  --spacing-btn-md: 2.25rem;  --spacing-btn-px-md: 0.875rem;
  --spacing-field: 2.125rem;  /* 输入框 / 下拉框高度 */
  --text-label: 0.8125rem;
}
md: "h-btn-md px-btn-px-md text-sm",
icon: "size-btn-md",

如此:

  • 一个套件在其主题中一次性覆盖令牌,其中的每个应用都能获得自己尺寸的控件。
  • 圆角、填充和阴影已经是令牌(rounded-field, bg-accent, --shadow-card)。
  • 用颜色加装饰性类来表现填充,例如 bg-accent accent-fill。只定义装饰(如光泽)的主题则永远不会渲染透明按钮。

参见 references/button.tsx。

逐个应用的整合步骤

  1. 盘点本地副本。 在每个应用中搜索 export function (Btn|Button|IconBtn|Select|Field|Input|Modal|Dialog|Sheet|Badge|Empty|Pager|Toast|Stat|Status|Spinner)。统计调用次数。

  2. 替换并删除 当共享组件经过主题化后匹配时。显式映射变体名称,并记录映射关系:

    本地名称共享变体
    primary, navyaccent
    secondaryoutline
    quiet, softsubtle
    danger (实心)danger-solid
  3. 将应用特有的部分保留在应用层:

    • 领域组件、图表和应用框架;
    • 其形状本身就是品牌的控件(iOS 圆片形、Carbon 扁平控件、48px 药丸形 CTA);
    • 拥有共享组件缺乏的行为的控件(三态复选框、可移除标签、“任意”重置项、多选过滤器)。

    当只增加一个功能时,使用薄封装层是可以的。通过注释说明原因。

  4. 弃用原生 <select> 和基于菜单的下拉框,统一使用一个 Select 组件。

    • Radix Select 将 "" 保留为“无值”:请使用像 "all" 这样的哨兵值,并映射回来。
    • 转发 aria-labelledby 和 aria-describedby。
    • 调用 selectOption() 的脚本需要先点击组合框,再点击选项。
  5. 对照每个应用自己的截图进行验证(参见 visual-regression-pass)。实际差异通常是预期的:尺寸、光泽、按压缩放。

tailwind-merge 陷阱(cn())

tailwind-merge 只识别 Tailwind 内置的度量体系。自定义令牌会在三个地方静默破坏它:

  • 未知的间距令牌。 cn("h-btn-md", "h-10") 会保留两者,因为它不知道 h-btn-md 是一个高度属性,样式表顺序决定最终效果。调用方的 h-10 被令牌覆盖,导致 40px 的按钮渲染成 36px。注册这些令牌: extendTailwindMerge({ extend: { theme: { spacing: ["btn-sm","btn-md","field", …] } } })。
  • 未知的文本尺寸。 cn("text-meta", "text-ink") 会将 text-meta 视为颜色并丢弃它。注册尺寸: theme: { text: ["meta","micro","label"] }。
  • 自定义阴影和颜色。 text-14 和 text-t3 并存,或者任意 shadow-[var(--x)] 和命名阴影并存:同样的问题。当代码库到处使用封闭的自定义度量体系时,在这些地方使用普通的 clsx。

参见 references/cn.ts。

焦点与验证

  • aria-invalid:ring-* 样式会覆盖 focus-visible:ring-*,从而在焦点位于无效字段时隐藏焦点环。请使用 aria-invalid:not-focus-visible:ring-…。
  • 表单内的裸 <button> 元素会提交表单。如果共享的 Button 不默认 type="button",则每个转换后的非提交调用点都必须显式设置它。

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

Adamparishspok/skills

Make a website, web app or online store ready for AI agents. Scan it with Cloudflare's Agent Readiness checks, decide which checks apply to this kind of site, ship the discovery files and headers in priority order, and add the AI-first basics the scanner does not score (server-rendered content, JSON-LD, llms.txt). Covers robots.txt AI rules, Content Signals, sitemap, Markdown for Agents (Accept text/markdown), Link headers, API catalog, OAuth discovery, auth.md, MCP server card, A2A agent card, agent skills index, WebMCP, and commerce protocols (ACP, UCP, AP2, MPP, x402). Use when making a site AI-ready, agent-ready or AI-first, or fixing an isitagentready.com or Cloudflare Agent Readiness report. Triggers on: AI ready, agent ready, AI-first, agent readiness, isitagentready, AI Crawl Control, Markdown for Agents, text/markdown, llms.txt, GPTBot, ClaudeBot, AI crawlers, Content-Signal, ai-train, api-catalog, .well-known, oauth-protected-resource, auth.md, MCP server card, agent card, agent skills, WebMCP, a...

Adamparishspok/skills

Install a complete, lean favicon set on any website or web app — the five files modern browsers, iOS and Android actually use, one block of head markup added once in the root layout, and a check that every file resolves. Covers finding the public folder per framework, generating the set from one SVG (or from a RealFaviconGenerator package), dark-mode SVG icons, maskable manifest icons, cache busting and verification. Use when adding, replacing or auditing a favicon, app icon, apple-touch-icon or web manifest. Triggers on: favicon, favicon.ico, favicon.svg, apple-touch-icon, site.webmanifest, manifest.json, app icon, PWA icon, maskable icon, tab icon, RealFaviconGenerator.

Adamparishspok/skills

Give an interface one shared tempo and a small vocabulary of hover and state micro-interactions: duration tiers (tap/pop/hover/card/layout) for CSS and Motion, swap hand-offs, rows whose highlight grows in, trailing arrows, chevron nudges, card lifts without translate, scroll-edge fades, and icon/label swaps for copy and toggle buttons. Use when animations feel inconsistent, durations are scattered magic numbers, hovers only change colour, or a product feels flat or unfinished. Triggers on: animation duration, transition timing, hover state, micro-interaction, polish, copy button feedback, menu icon to close, back arrow, card hover, scroll fade, motion tokens, Framer Motion durations.

Adamparishspok/skills

Build or migrate a UI's neutral palette (grounds, surfaces, lines, ink/text) as an OKLCH formula driven by a few inputs instead of dozens of hand-picked hex values, with light and dark themes, per-step ladder overrides, a fit script that reproduces existing colours, and a browser contrast audit. Use when creating a theme, adding dark mode, retinting a product, auditing text contrast, or consolidating several apps' palettes. Triggers on: palette, neutrals, grey ramp, dark mode, theme tokens, oklch, retint, hue, contrast audit, design tokens, Tailwind @theme colours.

相关技能