[TERMINAL · SKILLS]
> mounting /skills...
> indexing skill manifests...
> linking agents: claude · codex · gemini · cursor
> ready.
[░░░░░░░░░░░░░░░░░░░░░░░░░░░░] 0%
Use Cases/Build a Shared Component Library

Build a Shared Component Library

Build a shared component library with versioned packages, visual documentation, automated testing, design token integration, and tree-shaking support for cross-team UI consistency.

Development#typescript#tsconfig#type-checking#type-safety#javascript-migration
Works with:claude-codeopenai-codexgemini-clicursor

Skills stack · 3 skills

Avg quality 95/100·All SAFE
>

typescript

v1.0.0

Sets up and repairs TypeScript projects: picks tsconfig.json settings for a Node.js service, an npm library or a bundled web app, runs type-checking in CI, and replaces `any` and unsafe casts with types the compiler can verify. Use when someone asks to "set up TypeScript", "fix this tsconfig", "fix a TypeScript error", "upgrade to TypeScript 6 or 7", "migrate JavaScript to TypeScript", "publish types for a package", "run .ts files in Node" or "make this type-safe". Covers the changed defaults in TypeScript 6.0 and 7.0, module and moduleResolution, strict mode, project references, declaration output, narrowing, satisfies and common compiler errors.

93/100 quality
7.30× impact
SAFE· stale score
View skill
>

hono

v1.1.0

Hono is a small web framework built on Web Standards (Request/Response) that runs unchanged on Cloudflare Workers, Deno, Bun, Node.js, AWS Lambda and Vercel. Use it when the user asks to build a Hono API, add Zod validation, JWT auth, CORS or middleware, use the type-safe RPC client (hc), render JSX, stream responses, or deploy one codebase to several runtimes.

100/100 quality
6.20× impact
SAFE· stale score
View skill
>

zod

v1.1.0

Zod is a TypeScript-first schema library that validates data at runtime and infers static types from the same schema. Use when validating API request bodies, form input, environment variables or config files, parsing untrusted JSON, or migrating from Zod 3 to Zod 4. Covers z.object, safeParse, z.infer, coercion, discriminated unions, refinements, JSON Schema output and the v4 API changes.

93/100 quality
3.87× impact
SAFE· stale score
View skill
$

The Problem

Anna leads frontend at a 25-person company with 4 product teams. Each team builds their own buttons, modals, forms, and tables — resulting in 4 slightly different button styles, 3 modal implementations, and inconsistent spacing. When design updates the brand color, someone changes it in 2 of 4 apps. New developers can't find existing components and rebuild them. Bundle size is bloated because each app includes its own component code. They need a shared library: one set of components, versioned, documented, automatically tested, tree-shakeable, and synced with design tokens.

Step 1: Build the Component Library

typescript
// src/components/library.ts — Shared component library with versioning and documentation
import { readFile, writeFile, readdir } from "node:fs/promises";
import { join } from "node:path";
import { execSync } from "node:child_process";

interface Component {
  name: string;
  category: string;
  description: string;
  props: PropDef[];
  variants: string[];
  examples: Example[];
  version: string;
  dependencies: string[];
  changeLog: string[];
}

interface PropDef {
  name: string;
  type: string;
  required: boolean;
  defaultValue: any;
  description: string;
}

interface Example {
  name: string;
  code: string;
  description: string;
}

interface DesignTokens {
  colors: Record<string, string>;
  spacing: Record<string, string>;
  typography: Record<string, { fontFamily: string; fontSize: string; fontWeight: number; lineHeight: string }>;
  borderRadius: Record<string, string>;
  shadows: Record<string, string>;
}

// Generate CSS from design tokens
export function generateTokenCSS(tokens: DesignTokens): string {
  let css = ":root {\n";
  for (const [name, value] of Object.entries(tokens.colors)) css += `  --color-${name}: ${value};\n`;
  for (const [name, value] of Object.entries(tokens.spacing)) css += `  --space-${name}: ${value};\n`;
  for (const [name, config] of Object.entries(tokens.typography)) {
    css += `  --font-${name}-family: ${config.fontFamily};\n`;
    css += `  --font-${name}-size: ${config.fontSize};\n`;
    css += `  --font-${name}-weight: ${config.fontWeight};\n`;
    css += `  --font-${name}-line-height: ${config.lineHeight};\n`;
  }
  for (const [name, value] of Object.entries(tokens.borderRadius)) css += `  --radius-${name}: ${value};\n`;
  for (const [name, value] of Object.entries(tokens.shadows)) css += `  --shadow-${name}: ${value};\n`;
  css += "}\n";
  return css;
}

// Generate component documentation
export function generateDocs(components: Component[]): string {
  let md = "# Component Library\n\n";
  const categories = [...new Set(components.map((c) => c.category))];

  for (const category of categories) {
    md += `## ${category}\n\n`;
    const categoryComponents = components.filter((c) => c.category === category);
    for (const comp of categoryComponents) {
      md += `### ${comp.name}\n\n${comp.description}\n\n`;
      md += `**Props:**\n\n| Prop | Type | Required | Default | Description |\n|---|---|---|---|---|\n`;
      for (const prop of comp.props) {
        md += `| \`${prop.name}\` | \`${prop.type}\` | ${prop.required ? "Yes" : "No"} | ${prop.defaultValue !== undefined ? `\`${JSON.stringify(prop.defaultValue)}\`` : "-"} | ${prop.description} |\n`;
      }
      md += "\n**Variants:** " + comp.variants.join(", ") + "\n\n";
      for (const example of comp.examples) {
        md += `**${example.name}:** ${example.description}\n\n\`\`\`tsx\n${example.code}\n\`\`\`\n\n`;
      }
    }
  }
  return md;
}

// Validate component exports (ensure tree-shaking works)
export async function validateExports(packageDir: string): Promise<{ valid: boolean; issues: string[] }> {
  const issues: string[] = [];
  try {
    const pkgJson = JSON.parse(await readFile(join(packageDir, "package.json"), "utf-8"));
    if (!pkgJson.exports) issues.push("Missing 'exports' field — tree-shaking may not work");
    if (!pkgJson.sideEffects === false && pkgJson.sideEffects !== false) issues.push("Missing 'sideEffects: false' — bundlers can't tree-shake");
    if (!pkgJson.module && !pkgJson.exports?.["."]?.import) issues.push("Missing ESM entry point");
    if (!pkgJson.types && !pkgJson.typings) issues.push("Missing TypeScript types");
  } catch (e: any) { issues.push(`Can't read package.json: ${e.message}`); }
  return { valid: issues.length === 0, issues };
}

// Generate barrel exports with tree-shaking support
export function generateBarrelExport(components: Component[]): string {
  return components.map((c) => `export { ${c.name} } from './components/${c.name}';`).join("\n") + "\n";
}

// Check for breaking changes between versions
export function detectBreakingChanges(oldComponent: Component, newComponent: Component): string[] {
  const breaking: string[] = [];
  // Removed props
  for (const oldProp of oldComponent.props) {
    if (!newComponent.props.find((p) => p.name === oldProp.name)) {
      breaking.push(`Removed prop '${oldProp.name}'`);
    }
  }
  // Required props that were optional
  for (const newProp of newComponent.props) {
    const oldProp = oldComponent.props.find((p) => p.name === newProp.name);
    if (oldProp && !oldProp.required && newProp.required) {
      breaking.push(`Prop '${newProp.name}' changed from optional to required`);
    }
  }
  // Type changes
  for (const newProp of newComponent.props) {
    const oldProp = oldComponent.props.find((p) => p.name === newProp.name);
    if (oldProp && oldProp.type !== newProp.type) {
      breaking.push(`Prop '${newProp.name}' type changed from '${oldProp.type}' to '${newProp.type}'`);
    }
  }
  return breaking;
}

// Sample component definitions
export const LIBRARY_COMPONENTS: Component[] = [
  {
    name: "Button", category: "Actions", description: "Primary interaction element with multiple variants and sizes.",
    props: [
      { name: "variant", type: "'primary' | 'secondary' | 'danger' | 'ghost'", required: false, defaultValue: "primary", description: "Visual style variant" },
      { name: "size", type: "'sm' | 'md' | 'lg'", required: false, defaultValue: "md", description: "Button size" },
      { name: "disabled", type: "boolean", required: false, defaultValue: false, description: "Disable interaction" },
      { name: "loading", type: "boolean", required: false, defaultValue: false, description: "Show loading spinner" },
      { name: "onClick", type: "() => void", required: false, defaultValue: undefined, description: "Click handler" },
      { name: "children", type: "ReactNode", required: true, defaultValue: undefined, description: "Button content" },
    ],
    variants: ["primary", "secondary", "danger", "ghost"],
    examples: [
      { name: "Basic", code: '<Button variant="primary">Save</Button>', description: "Primary action button" },
      { name: "Loading", code: '<Button loading>Saving...</Button>', description: "Button with loading state" },
    ],
    version: "1.0.0", dependencies: [], changeLog: ["1.0.0: Initial release"],
  },
];

Results

  • 4 button styles → 1 — all teams use <Button variant="primary"> from shared library; design consistency across all products; brand color updates in one place
  • Bundle size -40% — tree-shaking eliminates unused components; each app imports only what it uses; sideEffects: false enables optimal bundling
  • New developer onboarding — browse component docs; see props, variants, and live examples; copy-paste working code; no rebuilding existing components
  • Breaking change detection — CI checks prop changes between versions; removing a prop or making it required triggers warning; consumers prepare before upgrading
  • Design token sync — Figma tokens exported → CSS variables generated → components use variables; design change propagates to all 4 apps automatically

Related use cases