# IGNY8 Frontend Component System

**Last Updated:** January 3, 2026  
**Version:** 1.3.2

> **🔒 ENFORCED BY ESLINT** - Violations will trigger warnings/errors during build.
> This document is the single source of truth for all UI components.

---

## Quick Reference Card

| Element | Component | Import Path |
|---------|-----------|-------------|
| Button | `Button` | `components/ui/button/Button` |
| Icon Button | `IconButton` | `components/ui/button/IconButton` |
| Button Group | `ButtonGroup` | `components/ui/button-group/ButtonGroup` |
| Text Input | `InputField` | `components/form/input/InputField` |
| Checkbox | `Checkbox` | `components/form/input/Checkbox` |
| Radio | `Radio` | `components/form/input/Radio` |
| File Upload | `FileInput` | `components/form/input/FileInput` |
| Textarea | `TextArea` | `components/form/input/TextArea` |
| Dropdown | `Select` | `components/form/Select` |
| Searchable Dropdown | `SelectDropdown` | `components/form/SelectDropdown` |
| Multi-Select | `MultiSelect` | `components/form/MultiSelect` |
| Toggle Switch | `Switch` | `components/form/switch/Switch` |
| Badge | `Badge` | `components/ui/badge/Badge` |
| Card | `Card` | `components/ui/card/Card` |
| Modal | `Modal` | `components/ui/modal` |
| Alert | `Alert` | `components/ui/alert/Alert` |
| Spinner | `Spinner` | `components/ui/spinner/Spinner` |
| Tabs | `Tabs` | `components/ui/tabs/Tabs` |
| Tooltip | `Tooltip` | `components/ui/tooltip/Tooltip` |
| Calendar Tooltip | `CalendarItemTooltip` | `components/ui/tooltip/CalendarItemTooltip` |
| Toast | `useToast` | `components/ui/toast/ToastContainer` |
| Icons | `*Icon` | `icons` (e.g., `../../icons`) |

---

## 1. BUTTONS

### Button (Standard)

```tsx
import Button from '../../components/ui/button/Button';

<Button
  variant="primary"     // primary | secondary | outline | ghost | gradient
  tone="brand"          // brand | success | warning | danger | neutral
  size="md"             // xs | sm | md | lg | xl | 2xl
  shape="rounded"       // rounded | pill
  startIcon={<Icon />}  // Icon before text
  endIcon={<Icon />}    // Icon after text
  onClick={handler}
  disabled={false}
  fullWidth={false}
  type="button"         // button | submit | reset
  className=""          // Additional classes
>
  Button Text
</Button>
```

**Common Patterns:**
```tsx
// Primary action
<Button variant="primary" tone="brand">Save</Button>

// Success/confirm
<Button variant="primary" tone="success">Approve</Button>

// Danger/destructive
<Button variant="primary" tone="danger">Delete</Button>

// Secondary/cancel
<Button variant="outline" tone="neutral">Cancel</Button>

// With icon
<Button startIcon={<PlusIcon className="w-4 h-4" />}>Add Item</Button>
```

### IconButton (Icon-only)

```tsx
import IconButton from '../../components/ui/button/IconButton';

<IconButton
  icon={<CloseIcon />}  // Required: Icon component
  variant="ghost"       // solid | outline | ghost
  tone="neutral"        // brand | success | warning | danger | neutral
  size="sm"             // xs | sm | md | lg
  shape="rounded"       // rounded | circle
  onClick={handler}
  disabled={false}
  title="Close"         // Required: Accessibility label
  aria-label="Close"    // Optional: Override aria-label
/>
```

**Common Patterns:**
```tsx
// Close button
<IconButton icon={<CloseIcon />} variant="ghost" tone="neutral" title="Close" />

// Delete button
<IconButton icon={<TrashBinIcon />} variant="ghost" tone="danger" title="Delete" />

// Edit button
<IconButton icon={<PencilIcon />} variant="ghost" tone="brand" title="Edit" />

// Add button (circular)
<IconButton icon={<PlusIcon />} variant="solid" tone="brand" shape="circle" title="Add" />
```

---

## 2. FORM INPUTS

### InputField (Text/Number/Email/Password)

```tsx
import InputField from '../../components/form/input/InputField';

<InputField
  type="text"           // text | number | email | password | date | time
  label="Field Label"
  placeholder="Enter value..."
  value={value}
  onChange={(e) => setValue(e.target.value)}
  id="field-id"
  name="field-name"
  disabled={false}
  error={false}         // Shows error styling
  success={false}       // Shows success styling
  hint="Helper text"    // Text below input
  min="0"               // For number inputs
  max="100"             // For number inputs
  step={1}              // For number inputs
/>
```

### TextArea (Multi-line)

```tsx
import TextArea from '../../components/form/input/TextArea';

<TextArea
  placeholder="Enter description..."
  rows={4}
  value={value}
  onChange={(value) => setValue(value)}
  disabled={false}
  error={false}
  hint="Helper text"
/>
```

### Checkbox

```tsx
import Checkbox from '../../components/form/input/Checkbox';

<Checkbox
  label="Accept terms"
  checked={checked}
  onChange={(checked) => setChecked(checked)}
  id="checkbox-id"
  disabled={false}
/>
```

### Radio

```tsx
import Radio from '../../components/form/input/Radio';

<Radio
  id="radio-option-1"
  name="radio-group"
  value="option1"
  label="Option 1"
  checked={selected === 'option1'}
  onChange={(value) => setSelected(value)}
/>
```

### Select (Dropdown)

```tsx
import Select from '../../components/form/Select';

<Select
  options={[
    { value: 'opt1', label: 'Option 1' },
    { value: 'opt2', label: 'Option 2' },
  ]}
  placeholder="Select..."
  defaultValue=""
  onChange={(value) => setValue(value)}
  className=""
/>
```

### SelectDropdown (Searchable)

```tsx
import SelectDropdown from '../../components/form/SelectDropdown';

<SelectDropdown
  label="Select Item"
  options={options}
  value={value}
  onChange={(value) => setValue(value)}
  placeholder="Search..."
  searchable={true}
/>
```

### Switch (Toggle)

```tsx
import Switch from '../../components/form/switch/Switch';

<Switch
  label="Enable feature"
  checked={enabled}           // Controlled mode
  onChange={(checked) => setEnabled(checked)}
  disabled={false}
  color="blue"                // blue | gray
/>
```

### FileInput

```tsx
import FileInput from '../../components/form/input/FileInput';

<FileInput
  onChange={(files) => handleFiles(files)}
  accept=".csv,.json"
  multiple={false}
/>
```

---

## 3. DISPLAY COMPONENTS

### Badge

```tsx
import Badge from '../../components/ui/badge/Badge';

<Badge
  tone="success"        // brand | success | warning | danger | info | neutral | purple | indigo | pink | teal | cyan | blue
  variant="soft"        // solid | soft | outline | light
  size="sm"             // xs | sm | md
  startIcon={<Icon />}
  endIcon={<Icon />}
>
  Label
</Badge>
```

**Status Badge Patterns:**
```tsx
<Badge tone="success" variant="soft">Active</Badge>
<Badge tone="warning" variant="soft">Pending</Badge>
<Badge tone="danger" variant="soft">Failed</Badge>
<Badge tone="info" variant="soft">Draft</Badge>
<Badge tone="neutral" variant="soft">Archived</Badge>
```

### Card

```tsx
import { Card, CardTitle, CardContent, CardDescription, CardAction, CardIcon } from '../../components/ui/card/Card';

<Card
  variant="surface"     // surface | panel | frosted | borderless | gradient
  padding="md"          // none | sm | md | lg
  shadow="sm"           // none | sm | md
>
  <CardIcon><Icon /></CardIcon>
  <CardTitle>Title</CardTitle>
  <CardDescription>Description text</CardDescription>
  <CardContent>Main content</CardContent>
  <CardAction onClick={handler}>Action</CardAction>
</Card>
```

### Alert

```tsx
import Alert from '../../components/ui/alert/Alert';

<Alert
  variant="success"     // success | error | warning | info
  title="Alert Title"
  message="Alert message text"
  showLink={false}
  linkHref="#"
  linkText="Learn more"
/>
```

### Modal

```tsx
import { Modal } from '../../components/ui/modal';

<Modal
  isOpen={isOpen}
  onClose={() => setIsOpen(false)}
  showCloseButton={true}
  isFullscreen={false}
>
  <div className="p-6">
    Modal content
  </div>
</Modal>
```

### Spinner

```tsx
import { Spinner } from '../../components/ui/spinner/Spinner';

<Spinner
  size="md"             // sm | md | lg
  color="primary"       // primary | success | error | warning | info
/>
```

### Tooltip

```tsx
import { Tooltip } from '../../components/ui/tooltip/Tooltip';

<Tooltip text="Tooltip text" placement="top">
  <span>Hover target</span>
</Tooltip>
```

### Toast (Notifications)

```tsx
import { useToast } from '../../components/ui/toast/ToastContainer';

const toast = useToast();

// Show notifications
toast.success('Success', 'Operation completed');
toast.error('Error', 'Something went wrong');
toast.warning('Warning', 'Please review');
toast.info('Info', 'Here is some information');
```

---

## 4. ICONS

### Importing Icons

```tsx
// Always import from central icons folder
import { PlusIcon, CloseIcon, CheckCircleIcon } from '../../icons';

// Use consistent sizing
<PlusIcon className="w-4 h-4" />      // Small (in buttons, badges)
<PlusIcon className="w-5 h-5" />      // Medium (standalone)
<PlusIcon className="w-6 h-6" />      // Large (headers, features)
```

### Available Icons

**Core Icons:**
- `PlusIcon`, `CloseIcon`, `CheckCircleIcon`, `AlertIcon`, `InfoIcon`, `ErrorIcon`
- `BoltIcon`, `ArrowUpIcon`, `ArrowDownIcon`, `ArrowRightIcon`, `ArrowLeftIcon`
- `PencilIcon`, `TrashBinIcon`, `DownloadIcon`, `CopyIcon`
- `EyeIcon`, `EyeCloseIcon`, `LockIcon`, `UserIcon`
- `FolderIcon`, `FileIcon`, `GridIcon`, `ListIcon`
- `ChevronDownIcon`, `ChevronUpIcon`, `ChevronLeftIcon`, `ChevronRightIcon`
- `AngleDownIcon`, `AngleUpIcon`, `AngleLeftIcon`, `AngleRightIcon`

**Module Icons:**
- `TaskIcon`, `PageIcon`, `TableIcon`, `CalendarIcon`
- `PlugInIcon`, `DocsIcon`, `MailIcon`, `ChatIcon`
- `PieChartIcon`, `BoxCubeIcon`, `GroupIcon`
- `ShootingStarIcon`, `DollarLineIcon`

**Aliases (for compatibility):**
- `TrashIcon` → `TrashBinIcon`
- `XIcon` / `XMarkIcon` → `CloseIcon`
- `SearchIcon` → `GridIcon`
- `SettingsIcon` → `BoxCubeIcon`
- `FilterIcon` → `ListIcon`

### Adding New Icons

1. Add SVG file to `src/icons/`
2. Export in `src/icons/index.ts`:
```ts
import { ReactComponent as NewIcon } from "./new-icon.svg?react";
export { NewIcon };
```

---

## 5. FOLDER STRUCTURE

```
src/
├── components/
│   ├── ui/                    # UI Components (display/interaction)
│   │   ├── accordion/
│   │   ├── alert/
│   │   │   ├── Alert.tsx
│   │   │   └── AlertModal.tsx
│   │   ├── avatar/
│   │   ├── badge/
│   │   │   └── Badge.tsx
│   │   ├── breadcrumb/
│   │   ├── button/
│   │   │   ├── Button.tsx        # ← Standard button
│   │   │   ├── IconButton.tsx    # ← Icon-only button
│   │   │   └── ButtonWithTooltip.tsx
│   │   ├── button-group/
│   │   ├── card/
│   │   ├── dataview/
│   │   ├── dropdown/
│   │   ├── list/
│   │   ├── modal/
│   │   ├── pagination/
│   │   ├── progress/
│   │   ├── ribbon/
│   │   ├── spinner/
│   │   ├── table/
│   │   ├── tabs/
│   │   ├── toast/
│   │   ├── tooltip/
│   │   └── videos/
│   │
│   └── form/                  # Form Components (inputs)
│       ├── input/
│       │   ├── InputField.tsx    # ← Text/number/email inputs
│       │   ├── Checkbox.tsx      # ← Checkbox
│       │   ├── Radio.tsx         # ← Radio button
│       │   ├── RadioSm.tsx       # ← Small radio button
│       │   ├── FileInput.tsx     # ← File upload
│       │   └── TextArea.tsx      # ← Multi-line text
│       ├── switch/
│       │   └── Switch.tsx        # ← Toggle switch
│       ├── Select.tsx            # ← Dropdown select
│       ├── SelectDropdown.tsx    # ← Searchable dropdown
│       ├── MultiSelect.tsx       # ← Multi-select dropdown
│       ├── Label.tsx             # ← Form labels
│       ├── Form.tsx              # ← Form wrapper
│       └── date-picker.tsx       # ← Date picker
│
├── icons/                     # All SVG icons
│   ├── index.ts               # ← Export all icons from here
│   ├── plus.svg
│   ├── close.svg
│   └── ... (50+ icons)
│
└── styles/
    └── design-system.css      # ← Global design tokens
```

---

## 6. ESLINT ENFORCEMENT

### Rules File Location
`eslint-plugin-igny8-design-system.cjs` (project root)

### Active Rules

| Rule | Severity | Description |
|------|----------|-------------|
| `no-raw-button` | warn | Use `Button` or `IconButton` instead of `<button>` |
| `no-raw-input` | warn | Use `InputField`, `Checkbox`, `Radio`, `FileInput` instead of `<input>` |
| `no-raw-select` | warn | Use `Select` or `SelectDropdown` instead of `<select>` |
| `no-raw-textarea` | warn | Use `TextArea` instead of `<textarea>` |
| `no-restricted-imports` | error | Block imports from `@heroicons/*`, `lucide-react`, `@mui/icons-material` |

### Running Lint Check
```bash
npm run lint
```

### Viewing Violations
```bash
npm run lint 2>&1 | grep "igny8-design-system"
```

---

## 7. MIGRATION EXAMPLES

### Raw Button → Button Component

```tsx
// ❌ BEFORE
<button 
  className="px-4 py-2 bg-brand-500 text-white rounded hover:bg-brand-600"
  onClick={handleClick}
>
  Save
</button>

// ✅ AFTER
<Button variant="primary" tone="brand" onClick={handleClick}>
  Save
</Button>
```

### Raw Button → IconButton

```tsx
// ❌ BEFORE
<button 
  className="p-1 hover:bg-gray-100 rounded"
  onClick={onClose}
>
  <CloseIcon className="w-4 h-4" />
</button>

// ✅ AFTER
<IconButton 
  icon={<CloseIcon />} 
  variant="ghost" 
  tone="neutral" 
  size="sm"
  onClick={onClose}
  title="Close"
/>
```

### Raw Input → InputField

```tsx
// ❌ BEFORE
<input 
  type="text"
  className="border rounded px-3 py-2 focus:ring-2"
  value={value}
  onChange={(e) => setValue(e.target.value)}
  placeholder="Enter name"
/>

// ✅ AFTER
<InputField
  type="text"
  label="Name"
  value={value}
  onChange={(e) => setValue(e.target.value)}
  placeholder="Enter name"
/>
```

### Raw Select → Select Component

```tsx
// ❌ BEFORE
<select 
  className="border rounded px-3 py-2"
  value={status}
  onChange={(e) => setStatus(e.target.value)}
>
  <option value="">Select status</option>
  <option value="active">Active</option>
  <option value="inactive">Inactive</option>
</select>

// ✅ AFTER
<Select
  options={[
    { value: 'active', label: 'Active' },
    { value: 'inactive', label: 'Inactive' },
  ]}
  placeholder="Select status"
  defaultValue={status}
  onChange={(value) => setStatus(value)}
/>
```

### External Icon → Internal Icon

```tsx
// ❌ BEFORE
import { XIcon } from '@heroicons/react/24/outline';
<XIcon className="w-5 h-5" />

// ✅ AFTER
import { CloseIcon } from '../../icons';
<CloseIcon className="w-5 h-5" />
```

---

## 8. SITE-SPECIFIC COMPONENTS (v1.3.2)

### SiteInfoBar

Reusable site info header component for site-specific pages.

```tsx
import { SiteInfoBar } from '../../components/common/SiteInfoBar';

<SiteInfoBar
  site={currentSite}       // Site object with name, domain, etc.
  onSiteChange={handleSiteChange}  // Optional: Callback when site changes
  showSelector={true}      // Whether to show site selector dropdown
/>
```

### OnboardingWizard Components

Located in `components/onboarding/`:

```tsx
import { OnboardingWizard } from '../../components/onboarding/OnboardingWizard';
import {
  Step1Welcome,
  Step2AddSite,
  Step3ConnectIntegration,
  Step4AddKeywords,
  Step5Complete,
} from '../../components/onboarding/steps';
```

### CalendarItemTooltip

Tooltip specifically designed for calendar items.

```tsx
import { CalendarItemTooltip } from '../../components/ui/tooltip';

<CalendarItemTooltip
  item={contentItem}       // Content object
  onView={handleView}      // Optional: View callback
  onRemove={handleRemove}  // Optional: Remove callback
/>
```

---

## 9. LIVE REFERENCE

View all components with live examples at: `/ui-elements`

This page shows every component with all prop variations.

---

## 10. AI AGENT INSTRUCTIONS

When working on this codebase, AI agents MUST:

1. **Never use raw HTML elements** (`<button>`, `<input>`, `<select>`, `<textarea>`)
2. **Import icons only from `src/icons`** - never from external libraries
3. **Follow the import paths** specified in this document
4. **Check ESLint** after making changes: `npm run lint`
5. **Use semantic color tokens** - never hardcoded hex values or Tailwind defaults

### Color Rules
```tsx
// ✅ CORRECT - Use semantic tokens
className="bg-brand-500 text-gray-900 border-success-500"

// ❌ WRONG - Tailwind defaults (DISABLED)
className="bg-blue-500 text-slate-900 border-green-500"

// ❌ WRONG - Hardcoded hex
className="bg-[#0077B6]"
style={{ color: '#DC2626' }}
```
5. **Reference this document** for correct component usage
6. **Use consistent icon sizing**: `className="w-4 h-4"` for small, `w-5 h-5` for medium

If a component doesn't exist, create it in `components/ui/` or `components/form/` first.
