# Dynamic UI Global Conventions

Universal prop naming patterns across ALL Dynamic UI components.

---

## Color Variants

**ALL components use `color` prop** (never `theme` or `variant` for colors).

```typescript
type ComponentColor = 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info' | 'light' | 'dark';
```

```tsx
// ✅ CORRECT
<DButton color="primary" text="Submit" />
<DBadge color="success" text="Active" />
<DAlert color="warning">Warning</DAlert>

// ❌ WRONG — theme/variant are silently ignored
<DButton theme="primary" text="Submit" />
<DButton variant="primary" text="Submit" />
```

---

## Text as Prop

### DBadge — use the `text` prop (children are ignored)

DBadge renders `text` only, so children do not display.

```tsx
// ✅ CORRECT
<DBadge text="New" />

// ❌ WRONG — children won't display
<DBadge>New</DBadge>
```

### DButton — prefer the `text` prop

DButton renders `children || text`: children DO display and override `text`.
Use `text` for plain labels (project convention); reserve children for rich
markup.

```tsx
// ✅ Preferred — text prop for the label
<DButton text="Click me" />

// ✅ Children also render (override text) — for rich markup only
<DButton><strong>Bold</strong></DButton>
```

**Components whose content is always children**: DAlert, DCard.Body, DOffcanvas.Body, DModal.Body

---

## Visual Style Variants

### `variant` vs `color` (DButton)

- **`variant`**: Visual style — `undefined` (solid), `'outline'`, `'link'`
- **`color`**: Color — `'primary'`, `'success'`, etc.

```tsx
<DButton color="primary" text="Solid" />
<DButton variant="outline" color="primary" text="Outlined" />
<DButton variant="link" color="primary" text="Link" />
// ❌ variant="primary" is WRONG — 'primary' is a color, not a variant
```

---

## Size Variants

`size="sm" | "lg"` (default is medium/undefined). DIcon is different: uses CSS values like `size="24px"`.

---

## Boolean State Props

No `is` prefix: use `disabled`, `loading`, `invalid`, `valid`, `checked`, `searchable`, `clearable` (not `isDisabled`, `isLoading`, etc.).

---

## Controlled vs Uncontrolled State

### `open` vs `openDefault`

**Affected components**: DOffcanvas, DModal, DCollapse

```tsx
// ✅ CORRECT - Controlled (you manage state)
const [isOpen, setIsOpen] = useState(false);
<DOffcanvas
  open={isOpen}
  onClose={() => setIsOpen(false)}
  staticBackdrop={false}
>
  <DOffcanvas.Header showCloseButton onClose={() => setIsOpen(false)}>
    <h5>Title</h5>
  </DOffcanvas.Header>
</DOffcanvas>

// ❌ WRONG - Won't react to state changes
<DOffcanvas openDefault={isOpen} onClose={onClose}>
  <DOffcanvas.Header onClose={onClose}>
    <h5>Title</h5>
  </DOffcanvas.Header>
</DOffcanvas>
```

**Key points**:
- Use `open` for controlled state (state changes trigger open/close)
- Use `openDefault` only for initial state in uncontrolled mode
- Add `showCloseButton` to Header for X button
- Set `staticBackdrop={false}` to allow closing by clicking outside

---

## Icon Props

| Component | Icon Prop Type | Example |
|-----------|---------------|---------|
| DButton, DInput, DInputMask | `string` (Lucide icon name) | `iconStart="Search"` |
| DBadge | `string` | `icon="Check"` |

Icon props take a **string** Lucide icon name (e.g. `iconStart="Save"`), NOT JSX. Do not pass `<DIcon .../>` to these props.

---

## DInput Icon API

DInput takes **strings** (PascalCase Lucide names), NOT JSX:

```tsx
<DInput iconStart="Search" iconEnd={query ? "XCircle" : undefined} />
// ❌ iconStart={<DIcon icon="Search" />} — WRONG, will show "[object Object]"
```

Common icons: `"Search"`, `"Mail"`, `"User"`, `"Lock"`, `"Calendar"`, `"DollarSign"`, `"Phone"`, `"MapPin"`

---

## Common Patterns

### Pattern 1: Status Badge Mapping

Map domain status values to UI colors:

```tsx
import { ComponentColor } from '@dynamic-framework/ui-react';

type Status = 'active' | 'pending' | 'expired' | 'rejected';

const STATUS_COLORS: Record<Status, ComponentColor> = {
  active: 'success',
  pending: 'warning',
  expired: 'danger',
  rejected: 'danger',
};

// Usage
function StatusBadge({ status }: { status: Status }) {
  return (
    <DBadge
      color={STATUS_COLORS[status]}
      text={t(`status.${status}`)}
      soft  // Makes it soft variant (lighter background)
    />
  );
}
```

### Pattern 2: Type Icon Mapping

Map domain types to Lucide Icons (PascalCase):

```tsx
type PolicyType = 'auto' | 'home' | 'life' | 'health';

// ✅ CORRECT - Use Lucide PascalCase names
const TYPE_ICONS: Record<PolicyType, string> = {
  auto: 'Car',
  home: 'Home',
  life: 'Heart',
  health: 'Hospital',
};

// Usage
<DIcon icon={TYPE_ICONS[type]} size="24px" />

// ❌ WRONG - Using old Bootstrap bi- prefix
const TYPE_ICONS = {
  auto: 'bi-car-front',   // Will show "?" - use PascalCase
};
```

**Important**: Dynamic UI 2.0 uses Lucide icons with PascalCase names (e.g., `"CheckCircle"`, `"ArrowRight"`). See **components/icons.md** for the complete icon reference.

## Quick Examples

```tsx
// Status → color mapping
const STATUS_COLORS: Record<Status, ComponentColor> = { active: 'success', pending: 'warning', inactive: 'danger' };
<DBadge color={STATUS_COLORS[status]} text={t(`status.${status}`)} soft />

// Type → icon mapping
const TYPE_ICONS: Record<PolicyType, string> = { auto: 'Car', home: 'Home', life: 'HeartPulse' };
<DIcon icon={TYPE_ICONS[type]} size="24px" />

// Button with icon (string Lucide name)
<DButton text="Save" color="primary" iconStart="Save" />

// Input with icon (string)
<DInput iconStart="Search" value={query} onChange={setQuery} />
```

## Quick Reference

| Feature | Prop | Type | Example |
|---------|------|------|---------|
| Color | `color` | `ComponentColor` | `color="primary"` |
| Style | `variant` | `string` | `variant="outline"` |
| Size | `size` | `'sm' \| 'lg'` | `size="sm"` |
| Icon (Button) | `iconStart/End` | `string` | `iconStart="Save"` |
| Icon (Input) | `iconStart/End` | `string` | `iconStart="Search"` |

## Critical Reminders

1. Always `color`, never `theme` for colors
2. DButton/DBadge use `text` prop, not children
3. `variant` = style (outline/link), `color` = color (primary/success)
4. No `is` prefix on booleans
5. DButton/DInput icons = string (PascalCase Lucide names)
