canonrs-server 0.1.0

CanonRS server-side rendering support
# Combobox Component

**Type:** Complex Interactive Component (Type 3)  
**Status:** Production-Ready  
**Tokens:** 100% Canonical (64 tokens aplicados)  
**Famílias:** C + B + A (Forms + Selection + Overlay)

---

## Purpose

Rich autocomplete select with search, filtering, and overlay. Designed for large option lists (>50 items) where native Select UX is insufficient.

**⚠️ Important:** Use **Select** for simple lists. See `/docs/canon/12-select-vs-combobox.md` for decision guide.

---

## Usage
```rust
use rs_design::ui::combobox::*;

// Basic combobox
let selected = RwSignal::new(String::new());
let countries = vec![
    ComboboxOption::new("us", "United States"),
    ComboboxOption::new("br", "Brazil"),
    ComboboxOption::new("uk", "United Kingdom"),
];

<Combobox
    options=countries
    value=selected
    placeholder="Select country..."
    search_placeholder="Search countries..."
/>

// With validation
<Combobox
    options=users
    value=selected_user
    validation=ComboboxValidation::Error
    placeholder="Select user..."
/>

// Different sizes
<Combobox
    options=items
    value=selected
    size=Some(ComboboxSize::Lg)
/>

// With disabled options
let options = vec![
    ComboboxOption::new("1", "Available"),
    ComboboxOption::new("2", "Busy").disabled(),
    ComboboxOption::new("3", "Available"),
];

<Combobox options=options value=selected />
```

---

## Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `options` | `Vec<ComboboxOption>` | **required** | List of options |
| `value` | `RwSignal<String>` | **required** | Selected value (reactive) |
| `size` | `Option<ComboboxSize>` | `Md` | Size variant |
| `validation` | `ComboboxValidation` | `None` | Validation state |
| `mode` | `ComboboxSelectionMode` | `Single` | Selection mode |
| `disabled` | `bool` | `false` | Disabled state |
| `placeholder` | `String` | `"Select option..."` | Trigger placeholder |
| `search_placeholder` | `String` | `"Search..."` | Search input placeholder |
| `empty_message` | `String` | `"No results found."` | Empty state message |
| `class` | `String` | `""` | Additional classes |

---

## Variants

### ComboboxSize
- `Sm` - Small (compact UIs)
- `Md` (default) - Medium (standard)
- `Lg` - Large (prominent controls)

### ComboboxValidation
- `None` (default) - No validation state
- `Error` - Error state (red border + ring)
- `Success` - Success state (green border + ring)
- `Warning` - Warning state (yellow border + ring)

### ComboboxSelectionMode
- `Single` (default) - Single selection
- `Multi` - Multiple selection (future)

---

## ComboboxOption
```rust
ComboboxOption::new(value, label)
    .disabled()  // Mark as disabled
```

**Properties:**
- `value: String` - Option value
- `label: String` - Display label
- `disabled: bool` - Disabled state

---

## Tokens Applied (64 total)

### Canônicos - Core (13 tokens)
- `radius.sm` - List items rounding
- `radius.md` - Trigger + popover rounding
- `radius.lg` - (reserved for large variant)
- `space.xs` - Tight spacing
- `space.sm` - Small padding
- `space.md` - Default padding
- `space.lg` - Large padding
- `space.xl` - (reserved)
- `border.width.thin` - Border thickness
- `shadow.sm` - Trigger shadow
- `shadow.md` - Popover shadow
- `z.dropdown` - Popover z-index

### Canônicos - Typography (13 tokens)
- `font.family.sans` - All text
- `font.size.xs` - (reserved)
- `font.size.sm` - List items, search
- `font.size.md` - Trigger text
- `font.size.lg` - Large variant
- `font.weight.regular` - List items
- `font.weight.medium` - Trigger text
- `font.weight.semibold` - (reserved)
- `line.height.tight` - Compact list items
- `line.height.normal` - Trigger
- `line.height.relaxed` - Empty state

### Canônicos - Color (15 tokens)
- `color.bg.surface` - Trigger, search input
- `color.bg.muted` - Hover state
- `color.bg.elevated` - Popover background
- `color.fg.default` - Text color
- `color.fg.muted` - Placeholder, empty state
- `color.fg.inverted` - (reserved)
- `color.border.default` - Popover border
- `color.border.muted` - (reserved)
- `color.primary.bg` - Selected item bg
- `color.primary.fg` - Selected item text
- `color.primary.border` - Focus border
- `color.danger.border` - Error validation
- `color.success.border` - Success validation
- `color.warning.border` - Warning validation

### Canônicos - State (4 tokens)
- `state.focus.ring` - Focus indicator
- `state.disabled.opacity` - Disabled appearance
- `state.hover.opacity` - Hover feedback
- `state.active.opacity` - Active state

### Canônicos - Motion (4 tokens)
- `motion.duration.fast` - Quick transitions
- `motion.duration.normal` - Popover open/close
- `motion.ease.standard` - Default easing
- `motion.ease.emphasized` - (reserved)

### Família A - Overlay & Layering (4 tokens)
- `overlay.backdrop.opacity` - Popover backdrop blur
- `overlay.dismiss.outside` - Click outside to close
- `overlay.dismiss.escape` - ESC key to close
- `overlay.focus_trap` - Focus dentro do popover

### Família B - Selection & Lists (5 tokens)
- `list.item.height` - Consistent item height
- `list.item.padding` - Item internal padding
- `selection.mode.single` - Single selection (default)
- `selection.mode.multi` - Multiple selection (future)
- `selection.indicator.check` - Check icon
- `empty.state.style` - Empty state styling

### Família C - Forms & Validation (5 tokens)
- `field.height` - Trigger height
- `field.padding` - Trigger padding
- `field.border` - Trigger border
- `field.placeholder` - Placeholder color
- `validation.error/success/warning` - Validation colors

**Total: 64 tokens (100% canônicos + Família A + B + C)**

---

## Accessibility

- `role="combobox"` (ARIA compliant)
-`role="listbox"` for options list
-`role="option"` for each item
-`aria-expanded`, `aria-selected`, `aria-disabled`
- ✅ Keyboard navigation (Arrow keys, Enter, Escape)
- ✅ Search with live filtering
- ✅ Focus trap dentro do popover
- ✅ Screen reader announcements

---

## Select vs Combobox Decision Guide

Use **Select** when:
- List has < 50 items
- No search needed
- SSR is critical
- Mobile-first
- Native UX preferred

Use **Combobox** when:
- List has > 50 items
- Search/filter essential
- Rich UX needed
- Desktop-first
- Custom overlay required

**Full guide:** `/docs/canon/12-select-vs-combobox.md`

---

## Canon Rules Applied

- **Rule #1 (Types):** Type 3 (Complex Interactive)
- **Rule #5 (SSR):** Partial SSR (Popover client-side)
- **Canon (Visual State):** 100% token-driven
- **Canon (Família A):** Overlay compliant
- **Canon (Família B):** Selection compliant
- **Canon (Família C):** Forms compliant

---

## File Structure
```
combobox/
├── combobox.rs         # Main Combobox + ComboboxItem
├── variants.rs         # Size, Validation
├── types.rs            # ComboboxOption, SelectionMode
├── mod.rs              # Module exports
└── README.md           # This file
```

---

## Examples

### Form Integration
```rust
<Field validation=country_validation>
    <FieldLabel r#for="country">"Country"</FieldLabel>
    <Combobox
        options=countries
        value=selected_country
        placeholder="Select your country"
        search_placeholder="Search countries..."
        validation=country_validation
    />
    <FieldError errors=country_errors />
</Field>
```

### Dynamic/Async Options
```rust
let users = Resource::new(
    || (),
    |_| async { fetch_users().await }
);

<Suspense fallback=|| view! { <p>"Loading..."</p> }>
    {move || users.get().map(|result| match result {
        Ok(users) => view! {
            <Combobox
                options=users.into_iter()
                    .map(|u| ComboboxOption::new(u.id, u.name))
                    .collect()
                value=selected_user
            />
        },
        Err(_) => view! { <p>"Error loading users"</p> }
    })}
</Suspense>
```

### With Custom Empty State
```rust
<Combobox
    options=products
    value=selected_product
    empty_message="No products match your search. Try different keywords."
    search_placeholder="Search products by name or SKU..."
/>
```

---

## Performance Notes

- **Filtering:** O(n) on each keystroke - use for lists < 1000 items
- **Rendering:** Virtual scrolling NOT implemented - consider for lists > 500 items
- **SSR:** Popover mounts client-side (acceptable trade-off for UX)
- **Bundle:** ~8KB (includes Popover dependency)

For lists > 1000 items, consider server-side search or pagination.

---

**Status:** ✅ Production-Ready  
**Canonicity:** 100% (64 tokens, 3 famílias)  
**Last Updated:** 2025-12-30