Files
igny8/docs/30-FRONTEND/COMPONENT-SYSTEM.md
IGNY8 VPS (Salman) c777e5ccb2 dos updates
2026-01-20 14:45:21 +00:00

684 lines
17 KiB
Markdown

# IGNY8 Frontend Component System
**Last Updated:** January 20, 2026
**Version:** 1.8.4
> **🔒 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.