<div align="center">
  <img src="../assets/typedialog_logo_h_s.svg" alt="TypeDialog Logo" width="600" />
</div>

# Field Types Reference

Complete reference for all supported field types in TypeDialog forms.

## Overview

TypeDialog supports multiple field types for different input scenarios. Each backend (CLI, TUI, Web) renders these types appropriately for its interface.

## Supported Field Types

### Text

Single-line text input.

```toml
[[elements]]
name = "username"
type = "text"
prompt = "Enter username"
placeholder = "john_doe"
default = "admin"
required = true
```text

**Attributes**:

- `prompt`: Display label
- `placeholder`: Example text
- `default`: Pre-filled value
- `required`: Validation flag

**Backend rendering**:

- CLI: Inline text prompt with validation
- TUI: Text input field in input panel
- Web: HTML `<input type="text">`

---

### Password

Secure password input (masked characters).

```toml
[[elements]]
name = "api_token"
type = "password"
prompt = "API Token"
required = true
help = "Your secret authentication token"
```text

**Attributes**:

- `prompt`: Display label
- `required`: Validation flag
- `help`: Additional guidance

**Backend rendering**:

- CLI: Hidden input with asterisks
- TUI: Masked input field
- Web: HTML `<input type="password">`

---

### Confirm

Boolean yes/no selection.

```toml
[[elements]]
name = "enable_feature"
type = "confirm"
prompt = "Enable experimental features?"
default = false
```text

**Attributes**:

- `prompt`: Question to display
- `default`: Initial value (true/false)

**Backend rendering**:

- CLI: Yes/No buttons
- TUI: Radio buttons (Yes/No)
- Web: Radio buttons or toggle switch

---

### Select

Single selection from predefined options.

```toml
[[elements]]
name = "database_driver"
type = "select"
prompt = "Database type"
required = true

[[elements.options]]
value = "sqlite3"
label = "SQLite (embedded)"

[[elements.options]]
value = "mysql"
label = "MySQL (server)"

[[elements.options]]
value = "postgresql"
label = "PostgreSQL (server)"
```text

**Attributes**:

- `prompt`: Display label
- `options`: Array of value/label pairs
- `required`: Validation flag
- `default`: Pre-selected value

**Backend rendering**:

- CLI: Arrow-key navigation list
- TUI: Dropdown or scrollable list
- Web: HTML `<select>` dropdown

---

### MultiSelect

Multiple selections from predefined options with flexible display modes.

```toml
# Basic example with grid display
[[elements]]
name = "languages"
type = "multiselect"
prompt = "Which languages are used?"
display_mode = "grid"
searchable = true
default = "rust"
options = [
    { value = "rust", label = "🦀 Rust" },
    { value = "python", label = "🐍 Python" },
    { value = "javascript", label = "📜 JavaScript" }
]

# Dropdown example with validation
[[elements]]
name = "user_roles"
type = "multiselect"
prompt = "Assign roles"
display_mode = "dropdown"
searchable = true
min_selected = 1
max_selected = 5
required = true
options = [
    { value = "admin", label = "Administrator" },
    { value = "editor", label = "Editor" },
    { value = "viewer", label = "Viewer" }
]
```text

**Display Modes**:

- `"list"` (default): Vertical checkbox list
- `"grid"`: Responsive grid layout (2-3 columns)
- `"dropdown"`: HTML `<select multiple>` dropdown

**Attributes**:

- `prompt`: Display label
- `options`: Array of value/label pairs
- `display_mode`: Rendering style ("list", "grid", "dropdown")
- `searchable`: Enable search/filter in dropdown mode
- `default`: Pre-selected values (comma-separated)
- `min_selected`: Minimum number of selections
- `max_selected`: Maximum number of selections
- `required`: Validation flag
- `page_size`: Number of visible items (CLI/TUI only)
- `vim_mode`: Enable vim navigation (CLI/TUI only)

**Backend rendering**:

- CLI: Checkbox list with space to toggle
- TUI: Multi-selection list with checkboxes
- Web: Grid/List checkboxes or HTML `<select multiple>` based on `display_mode`

---

### Date

Date selection with validation.

```toml
[[elements]]
name = "start_date"
type = "date"
prompt = "Project start date"
min_date = "2024-01-01"
max_date = "2025-12-31"
week_start = "Mon"
required = true
```text

**Attributes**:

- `prompt`: Display label
- `min_date`: Earliest allowed date (ISO 8601)
- `max_date`: Latest allowed date (ISO 8601)
- `week_start`: Calendar week start day
- `default`: Pre-filled date

**Backend rendering**:

- CLI: Date input with format validation
- TUI: Calendar picker widget
- Web: HTML `<input type="date">`

---

### Editor

Multi-line text editor for code/configuration.

```toml
[[elements]]
name = "config_file"
type = "editor"
prompt = "Configuration content"
file_extension = "toml"
prefix_text = "[settings]\n"
required = true
```text

**Attributes**:

- `prompt`: Display label
- `file_extension`: File type for syntax highlighting
- `prefix_text`: Pre-filled content
- `required`: Validation flag

**Backend rendering**:

- CLI: Opens external editor ($EDITOR)
- TUI: Built-in multi-line editor
- Web: HTML `<textarea>` with monospace font

---

### Custom

Custom type with external validation.

```toml
[[elements]]
name = "port"
type = "custom"
custom_type = "Port"
prompt = "Server port"
placeholder = "8080"
required = true
```text

**Attributes**:

- `custom_type`: Type name for validation
- `prompt`: Display label
- `placeholder`: Example value
- `required`: Validation flag

**Backend rendering**:

- All backends: Text input with custom validator
- Validation delegated to Nickel contracts

---

### RepeatingGroup

Dynamic array of structured items (add/edit/delete).

```toml
[[elements]]
name = "udp_trackers"
type = "repeatinggroup"
prompt = "UDP Tracker Listeners"
fragment = "fragments/udp_trackers_item.toml"
min_items = 0
max_items = 10
default_items = 1
unique = true
required = false
help = "Configure UDP tracker bind addresses"
```text

**Attributes**:

- `prompt`: Display label for the array
- `fragment`: Path to fragment file defining array element structure
- `min_items`: Minimum required items (0 = optional)
- `max_items`: Maximum allowed items
- `default_items`: Initial number of items to show
- `unique`: Enforce uniqueness constraint (all fields must differ between items)
- `required`: Whether array is required
- `help`: Additional guidance text

**Uniqueness Constraints** (Web/TUI/CLI):

- When `unique = true`: ALL fields in each item must be different from all other items
  - Example: Cannot add `{bind_address: "0.0.0.0:6969"}` twice
  - Triggers validation alert: "This item already exists"
- Within a fragment, individual fields can be marked with `unique_key = true` to enforce uniqueness on that field only
  - Example: Port numbers must be unique, but bind addresses can repeat

**Fragment structure** (`udp_trackers_item.toml`):

```toml
name = "udp_trackers_item"
description = "UDP Tracker configuration"
display_mode = "complete"

[[elements]]
name = "bind_address"
type = "text"
prompt = "UDP Bind Address"
placeholder = "0.0.0.0:6969"
default = "0.0.0.0:6969"
required = true
order = 0
```text

**Backend rendering**:

- **CLI**: Interactive menu system ✓
  - `[A] Add new item` - Open fragment form for new item
  - `[E] Edit item` - Select and edit existing item
  - `[D] Delete item` - Select and remove item
  - `[C] Continue` - Validate min_items and proceed
  - ✅ **Duplicate detection enforced** if `unique = true`
  - ✅ **max_items limit enforced** with clear feedback

- **TUI**: Split-pane interface ✓
  - Left pane: List of items with navigation
  - Right pane: Preview or edit form
  - Keyboard: A=add, E=edit, D=delete, Enter=continue
  - ✅ **Duplicate detection enforced** if `unique = true`
  - ✅ **max_items limit enforced** with error overlay
  - Item counter showing progress

- **Web**: Inline expandable cards (no modal nesting) ✓
  - Item cards showing summary of field values
  - ➕ Add Item button expands inline form
  - ✏️ Edit button expands item for inline editing
  - 🗑️ Delete button with confirmation
  - Live counter: `Items: X / max_items`
  - ✅ **Duplicate detection enforced** if `unique = true`
  - ✅ **max_items limit enforced** with alert message
  - Independent state per repeating group

**JSON output**:

```json
{
  "udp_trackers": [
    { "bind_address": "0.0.0.0:6969" },
    { "bind_address": "0.0.0.0:6970" }
  ]
}
```text

**Nickel schema mapping**:

```nickel
{
  TrackerUdp = { bind_address | String },
  Config = {
    udp_trackers | Array TrackerUdp | optional
  },
}
```text

**Use cases**:

- Multiple listeners (UDP/HTTP servers)
- Array of database connections
- List of API endpoints
- Collection of users/accounts
- Multiple environment variables
- Array of network interfaces

---

## Display Elements (Non-Input)

These are not input fields but display-only elements for form organization.

### Section Header

Visual separator with title.

```toml
[[elements]]
name = "database_header"
type = "section_header"
title = "📊 Database Configuration"
border_top = true
border_bottom = true
```text

### Section

Informational text block.

```toml
[[elements]]
name = "info"
type = "section"
content = "Configure your database connection settings below."
```text

### Group

Container for loading fragments.

```toml
[[elements]]
name = "mysql_group"
type = "group"
when = "database_driver == mysql"
includes = ["fragments/database-mysql-section.toml"]
```text

---

## Conditional Display

All field types support conditional visibility via `when` attribute:

```toml
[[elements]]
name = "mysql_password"
type = "password"
prompt = "MySQL Password"
when = "database_driver == mysql"
required = true
```text

### Comparison Operators

**Equality and inequality**:

- `==`: Equal to
- `!=`: Not equal to

```toml
[[elements]]
name = "postgres_config"
type = "text"
when = "database_driver == postgresql"

[[elements]]
name = "legacy_warning"
type = "section"
content = "⚠️ SQLite is for development only"
when = "database_driver != postgresql"
```text

**Numeric comparisons**:

- `>`: Greater than
- `<`: Less than
- `>=`: Greater than or equal
- `<=`: Less than or equal

```toml
[[elements]]
name = "performance_warning"
type = "section"
content = "⚠️ High port number may require elevated privileges"
when = "port >= 1024"

[[elements]]
name = "pool_size_warning"
type = "section"
when = "connection_pool > 100"
```text

### String Operators

**String matching**:

- `contains`: Check if field contains substring
- `startswith`: Check if field starts with prefix
- `endswith`: Check if field ends with suffix

```toml
[[elements]]
name = "rust_specific"
type = "text"
prompt = "Rust toolchain version"
when = "language contains rust"

[[elements]]
name = "protocol_warning"
type = "section"
when = "url startswith https"

[[elements]]
name = "yaml_parser"
type = "select"
when = "config_file endswith .yaml"
```text

### Array Membership

**`in` operator**: Check if value exists in array field

```toml
[[elements]]
name = "rust_features"
type = "multiselect"
prompt = "Rust-specific features"
when = "rust in detected_languages"
options = [
    { value = "clippy", label = "Clippy linting" },
    { value = "cargo_audit", label = "Security auditing" }
]

[[elements]]
name = "python_virtualenv"
type = "confirm"
when = "python in languages"
```text

**Note**: The `in` operator works with:

- Array fields (JSON array values)
- MultiSelect fields (comma-separated strings)

### File System Conditions

**`file_exists(path)`**: Check if file or directory exists

```toml
[[elements]]
name = "use_existing_config"
type = "confirm"
prompt = "Existing config.toml found. Use it?"
when = "file_exists(config.toml)"

[[elements]]
name = "create_new_config"
type = "text"
prompt = "Configuration name"
when = "!file_exists(.env)"
```text

**Negation with `!`**:

- `!file_exists(path)`: File does NOT exist

```toml
[[elements]]
name = "docker_setup"
type = "group"
includes = ["fragments/docker-init.toml"]
when = "!file_exists(Dockerfile)"
```text

### Future Support

**Planned features**:

- Parentheses for grouping: `(a == b) && (c == d)`
- Logical AND: `&&`
- Logical OR: `||`

---

## i18n Support

All fields support internationalization via `i18n = true`:

```toml
[[elements]]
name = "username"
type = "text"
prompt = "form.username.prompt"
placeholder = "form.username.placeholder"
i18n = true
```text

Translations resolved from Fluent `.ftl` files in `locales/` directory.

---

## Nickel Integration

Fields automatically map to Nickel contracts:

| Field Type | Nickel Contract |
 | ------------ | ---------------- |
| Text | `String` |
| Password | `String` |
| Confirm | `Bool` |
| Select | `String` (enum) |
| MultiSelect | `Array String` |
| Date | `String` (ISO 8601) |
| Editor | `String` |
| Custom | Custom contract |
| RepeatingGroup | `Array Record` |

Example Nickel schema:

```nickel
{
  Config = {
    username | String,
    password | String,
    enable_feature | Bool,
    database_driver | [| 'sqlite3, 'mysql, 'postgresql |],
    features | Array String,
    start_date | String,
    udp_trackers | Array { bind_address | String },
  }
}
```text

---

## Backend-Specific Features

### CLI Backend

- Inline validation with immediate feedback
- Arrow key navigation for Select/MultiSelect
- External editor support for Editor type
- Interactive menu for RepeatingGroup

### TUI Backend

- 3-panel layout (fields, input, preview)
- Mouse and keyboard navigation
- Real-time form updates
- Split-pane UI for RepeatingGroup

### Web Backend

- HTML5 input types for validation
- CSS styling for consistent appearance
- HTMX for reactive updates
- Modal overlays for RepeatingGroup

---

## Field Validation

Validation occurs at multiple levels:

1. **Client-side** (TypeDialog):
   - Required fields
   - Field type constraints
   - Min/max values (dates, numbers)
   - Array min/max items (RepeatingGroup)

2. **Schema validation** (Nickel):
   - Contract enforcement
   - Custom predicates
   - Business logic rules

3. **Server-side** (Application):
   - Final validation before processing
   - Database constraints
   - External API verification

---

## Related Documentation

- [configuration.md](configuration.md) - Backend configurations
- [nickel.md](nickel.md) - Nickel schema integration
- [fragments/README.md](../provisioning/fragments/README.md) - Fragment system
- [examples/](../examples/) - Working examples
