# Componentizer

Scan a codebase for UI patterns that are duplicated or that bypass existing shared components. Works on any React/Astro/Vue project with a component library.

$ARGUMENTS

---

## What this skill does

1. **Violations scan** — finds places where raw markup bypasses existing shared components
2. **Duplication scan** — finds structural patterns repeated across 3+ files worth extracting
3. **Report** — prioritized table of findings with file, line, and recommendation
4. **Optionally create** — if asked to "fix", implement the missing shared components

---

## Step 1 — Discover the component library

Before scanning, find what shared components already exist. Look for barrel files:

```bash
# Find the shared UI barrel(s)
find . -name "index.ts" -path "*/ui/index*" | grep -v node_modules | grep -v dist
find . -name "index.ts" -path "*/components/ui*" | grep -v node_modules | grep -v dist
```

Read the barrel(s) to get the exact list of available components. This is your ground truth.

---

## Step 2 — Violations scan

These greps find the most common raw-markup violations. Adapt the `path` to the project's component directory.

```bash
COMP_DIR="src/components"   # adjust per project

# Raw <table> elements (should use a table component)
grep -rn "<table" "$COMP_DIR" --include="*.tsx" --include="*.jsx" --include="*.vue" -l

# Manual animate-pulse (should use a loading skeleton component)
grep -rn "animate-pulse" "$COMP_DIR" --include="*.tsx" -l

# Raw modal overlays (should use a modal/dialog component)
grep -rn "fixed inset-0" "$COMP_DIR" --include="*.tsx" -l

# Hardcoded error banners (should use an ErrorAlert or similar)
grep -rn "bg-red-\|text-red-4\|border-red-" "$COMP_DIR" --include="*.tsx" -l

# Hardcoded status colours (should use a StatusBadge or similar)
grep -rn "text-green-4\|text-yellow-4\|bg-green-4\|bg-yellow-4" "$COMP_DIR" --include="*.tsx" -l

# Raw empty state divs (should use an EmptyState component)
grep -rn "col-span-full.*text-center\|text-center.*py-8" "$COMP_DIR" --include="*.tsx" -l

# browser confirm() for destructive actions (should use ConfirmDialog)
grep -rn "window\.confirm\b\|if (!confirm" "$COMP_DIR" --include="*.tsx" -l
```

For each hit file: grep for the specific line, read ±5 lines of context, confirm it's a real violation (not inside an existing shared component implementation).

---

## Step 3 — Duplication scan

Find structural patterns repeated across multiple files:

```bash
COMP_DIR="src/components"

# Form row pattern (label + input wrapper)
grep -rn 'className="block text-sm font-medium' "$COMP_DIR" --include="*.tsx" -l

# Edit/delete button pairs
grep -rn "onDelete\|handleDelete" "$COMP_DIR" --include="*.tsx" -l

# Pagination controls
grep -rn "setPage\|prevPage\|nextPage\|page - 1\|page + 1" "$COMP_DIR" --include="*.tsx" -l

# Filter bars with search + select
grep -rn 'type="search"\|placeholder.*[Ss]earch' "$COMP_DIR" --include="*.tsx" -l

# Confirmation modals / browser confirms
grep -rn "window\.confirm\|confirm(" "$COMP_DIR" --include="*.tsx" -l
```

Count how many **distinct** files have each pattern. Only recommend extraction if **3+ files** share the same structure.

---

## Step 4 — Report

Output two tables:

### Violations (use existing shared components)
| File | Line | Raw pattern | Shared component to use |
|------|------|-------------|-------------------------|

### New shared components (pattern in 3+ files)
| Priority | Name | Pattern | Files | Minimal props |
|----------|------|---------|-------|---------------|

---

## Step 5 — Creating new shared components

If asked to create a component:

1. Place it in the shared UI directory alongside existing components
2. Follow the project's token system — no hardcoded colours
3. Export from the barrel `index.ts`
4. Document in the project's UI developer guide/skill if one exists
5. Migrate all existing usages found in the scan
6. Run the build to verify no TypeScript errors
7. Commit: `refactor(ui): extract <PatternName> into <ComponentName>`

### Generic component template (React/TypeScript)
```tsx
interface ComponentNameProps {
  // required props first
  // optional props with ?
  // children last if needed
}

export function ComponentName({ ... }: ComponentNameProps) {
  return (
    // use design tokens — var(--color-*), var(--radius-*), var(--shadow-*)
    // no hardcoded hex or Tailwind colour names
  );
}
```

---

## Token-saving tips

- **Never read entire files** — use `grep -n` to get line numbers, then read only ±10 lines of context
- Violations in test files or one-off scripts are lower priority
- A component that needs 10+ optional props to cover all usages is a leaky abstraction — don't extract it
- "3+ files" is a minimum, not a guarantee — also check structural similarity before recommending
