# LookupEditor

A lookup input component that provides a read-only text field with an action button to open external selection dialogs or modal windows.

## Features

- **Read-Only Input**: Displays selected values as text without direct editing
- **Action Trigger**: Built-in action button to open lookup dialogs or modal windows
- **Multiple Variants**: Support for plain, outlined, and filled styles
- **Form Integration**: Works seamlessly with forms and validation
- **Keyboard Support**: Handles keyboard navigation and events
- **Focus Events**: Supports focus and blur event handling
- **Clearable Values**: Optional clear functionality for non-mandatory fields
- **Display Modes**: Supports both edit and display modes

## Installation

```bash
npm install @ticatec/uniface-element
```

## Usage

### Basic Usage

```svelte
<script>
  import LookupEditor from '@ticatec/uniface-element/lookup-editor';
  
  let selectedValue = null;
  let displayText = '';
  
  function handleLookupAction() {
    // Open your lookup dialog/modal here
    console.log('Opening lookup dialog...');
    
    // Example: simulate user selection
    setTimeout(() => {
      selectedValue = { id: 1, name: 'John Doe' };
      displayText = 'John Doe';
    }, 1000);
  }
</script>

<LookupEditor 
  bind:value={selectedValue}
  text={displayText}
  onAction={handleLookupAction}
  placeholder="Click to select a user"
  variant="outlined"
  style="width: 300px;"
/>
```

### Employee Lookup

```svelte
<script>
  import LookupEditor from '@ticatec/uniface-element/lookup-editor';
  import EmployeeLookupDialog from './EmployeeLookupDialog.svelte';
  
  let selectedEmployee = null;
  let employeeName = '';
  let showLookupDialog = false;
  
  function openEmployeeLookup() {
    showLookupDialog = true;
  }
  
  function handleEmployeeSelected(employee) {
    selectedEmployee = employee;
    employeeName = `${employee.firstName} ${employee.lastName}`;
    showLookupDialog = false;
  }
  
  function handleValueChange(value) {
    console.log('Employee value changed:', value);
  }
</script>

<LookupEditor 
  bind:value={selectedEmployee}
  text={employeeName}
  onAction={openEmployeeLookup}
  onchange={handleValueChange}
  placeholder="Select an employee"
  variant="filled"
  mandatory
/>

{#if showLookupDialog}
  <EmployeeLookupDialog 
    on:select={handleEmployeeSelected}
    on:close={() => showLookupDialog = false}
  />
{/if}
```

### Customer Lookup with Focus Events

```svelte
<script>
  import LookupEditor from '@ticatec/uniface-element/lookup-editor';
  
  let selectedCustomer = null;
  let customerDisplay = '';
  
  function handleCustomerLookup() {
    // Open customer selection modal
    openCustomerModal();
  }
  
  function handleFocus(event) {
    console.log('Lookup gained focus');
    // Could highlight the field or show hints
  }
  
  function handleBlur(event) {
    console.log('Lookup lost focus');
    // Could validate or save state
  }
</script>

<LookupEditor 
  bind:value={selectedCustomer}
  text={customerDisplay}
  onAction={handleCustomerLookup}
  onfocus={handleFocus}
  onblur={handleBlur}
  placeholder="Search customers..."
  variant="outlined"
/>
```

### Product Lookup in Form

```svelte
<script>
  import LookupEditor from '@ticatec/uniface-element/lookup-editor';
  import FormField from '@ticatec/uniface-element/form-field';
  
  let orderData = {
    product: null,
    quantity: 1,
    notes: ''
  };
  
  let productName = '';
  let errors = {};
  
  function openProductCatalog() {
    // Open product selection dialog
    console.log('Opening product catalog...');
  }
  
  function validateForm() {
    errors = {};
    
    if (!orderData.product) {
      errors.product = 'Please select a product';
    }
    
    if (!orderData.quantity || orderData.quantity < 1) {
      errors.quantity = 'Quantity must be at least 1';
    }
    
    return Object.keys(errors).length === 0;
  }
</script>

<form on:submit|preventDefault={validateForm}>
  <FormField label="Product" required error={errors.product}>
    <LookupEditor 
      bind:value={orderData.product}
      text={productName}
      onAction={openProductCatalog}
      placeholder="Select a product"
      variant="outlined"
      mandatory
    />
  </FormField>
  
  <FormField label="Quantity" required error={errors.quantity}>
    <input 
      type="number" 
      bind:value={orderData.quantity}
      min="1"
      placeholder="Enter quantity"
    />
  </FormField>
  
  <button type="submit">Place Order</button>
</form>
```

## API Reference

### Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `value` | `any` | `null` | The selected value/object |
| `text` | `string` | `''` | Display text shown in the input field |
| `variant` | `'' \| 'plain' \| 'outlined' \| 'filled'` | `''` | Visual style variant |
| `placeholder` | `string` | `''` | Placeholder text when no value is selected |
| `disabled` | `boolean` | `false` | Whether the component is disabled |
| `readonly` | `boolean` | `false` | Whether the component is read-only |
| `mandatory` | `boolean` | `false` | Whether a value is required (affects clear button) |
| `compact` | `boolean` | `false` | Whether to use compact styling |
| `style` | `string` | `''` | Custom CSS styles |
| `displayMode` | `DisplayMode` | `DisplayMode.Edit` | Display mode (edit or display) |

### Events

| Event | Type | Description |
|-------|------|-------------|
| `onAction` | `() => void` | Fired when the action button is clicked |
| `onchange` | `(value: any) => void` | Fired when the value changes |
| `onfocus` | `(event: FocusEvent) => void` | Fired when the input gains focus |
| `onblur` | `(event: FocusEvent) => void` | Fired when the input loses focus |

### Keyboard Events

The component also forwards these keyboard events:

- `on:keydown` - Keyboard key press events

## Advanced Usage

### Multi-Step Lookup

```svelte
<script>
  import LookupEditor from '@ticatec/uniface-element/lookup-editor';
  
  let selectedLocation = null;
  let locationText = '';
  let currentStep = 'country'; // 'country' -> 'state' -> 'city'
  
  function handleLocationLookup() {
    switch (currentStep) {
      case 'country':
        openCountrySelector();
        break;
      case 'state':
        openStateSelector();
        break;
      case 'city':
        openCitySelector();
        break;
    }
  }
  
  function handleLocationChange(location) {
    selectedLocation = location;
    if (location) {
      locationText = `${location.city}, ${location.state}, ${location.country}`;
    } else {
      locationText = '';
      currentStep = 'country';
    }
  }
</script>

<LookupEditor 
  bind:value={selectedLocation}
  text={locationText}
  onAction={handleLocationLookup}
  onchange={handleLocationChange}
  placeholder="Select location (Country ’ State ’ City)"
  variant="outlined"
/>
```

### Lookup with Validation

```svelte
<script>
  import LookupEditor from '@ticatec/uniface-element/lookup-editor';
  
  let selectedItem = null;
  let itemText = '';
  let isValid = true;
  let validationMessage = '';
  
  function validateSelection(item) {
    if (!item) {
      isValid = false;
      validationMessage = 'Selection is required';
      return false;
    }
    
    if (item.status === 'inactive') {
      isValid = false;
      validationMessage = 'Selected item is inactive';
      return false;
    }
    
    isValid = true;
    validationMessage = '';
    return true;
  }
  
  function handleSelectionChange(value) {
    validateSelection(value);
  }
</script>

<div class="lookup-container">
  <LookupEditor 
    bind:value={selectedItem}
    text={itemText}
    onAction={openLookupDialog}
    onchange={handleSelectionChange}
    placeholder="Select an item"
    variant="outlined"
    style={isValid ? '' : 'border-color: #f44336;'}
  />
  
  {#if !isValid}
    <div class="error-message">{validationMessage}</div>
  {/if}
</div>

<style>
  .lookup-container {
    position: relative;
  }
  
  .error-message {
    color: #f44336;
    font-size: 0.875rem;
    margin-top: 4px;
  }
</style>
```

### Lookup with Recent Selections

```svelte
<script>
  import LookupEditor from '@ticatec/uniface-element/lookup-editor';
  
  let selectedUser = null;
  let userDisplayName = '';
  let recentSelections = [];
  let showRecentMenu = false;
  
  function handleUserLookup() {
    // Show recent selections first, then full lookup
    if (recentSelections.length > 0) {
      showRecentMenu = true;
    } else {
      openFullUserLookup();
    }
  }
  
  function handleUserSelected(user) {
    selectedUser = user;
    userDisplayName = user.displayName;
    
    // Add to recent selections
    recentSelections = [
      user,
      ...recentSelections.filter(u => u.id !== user.id)
    ].slice(0, 5); // Keep only 5 recent items
    
    showRecentMenu = false;
  }
  
  function handleFocus() {
    // Could show recent selections on focus
    if (recentSelections.length > 0 && !selectedUser) {
      showRecentMenu = true;
    }
  }
  
  function handleBlur() {
    // Hide recent menu when focus is lost
    setTimeout(() => {
      showRecentMenu = false;
    }, 200); // Delay to allow clicking on menu items
  }
</script>

<div class="lookup-with-recent">
  <LookupEditor 
    bind:value={selectedUser}
    text={userDisplayName}
    onAction={handleUserLookup}
    onfocus={handleFocus}
    onblur={handleBlur}
    placeholder="Select a user"
    variant="outlined"
  />
  
  {#if showRecentMenu}
    <div class="recent-menu">
      <div class="recent-header">Recent Selections</div>
      {#each recentSelections as user}
        <button 
          class="recent-item"
          on:click={() => handleUserSelected(user)}
        >
          {user.displayName}
        </button>
      {/each}
      <button 
        class="recent-item show-all"
        on:click={openFullUserLookup}
      >
        Show All Users...
      </button>
    </div>
  {/if}
</div>

<style>
  .lookup-with-recent {
    position: relative;
  }
  
  .recent-menu {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    background: white;
    border: 1px solid #ddd;
    border-radius: 4px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
    z-index: 1000;
    max-height: 200px;
    overflow-y: auto;
  }
  
  .recent-header {
    padding: 8px 12px;
    font-size: 0.875rem;
    font-weight: 600;
    color: #666;
    border-bottom: 1px solid #eee;
  }
  
  .recent-item {
    display: block;
    width: 100%;
    padding: 8px 12px;
    border: none;
    background: white;
    text-align: left;
    cursor: pointer;
    transition: background-color 0.2s;
  }
  
  .recent-item:hover {
    background-color: #f5f5f5;
  }
  
  .recent-item.show-all {
    font-style: italic;
    color: #666;
    border-top: 1px solid #eee;
  }
</style>
```

## Styling

### CSS Variables

The LookupEditor component inherits styling from the CommonPicker component and supports these CSS variables:

```css
:root {
  --uniface-picker-border-color: #d1d5db;
  --uniface-picker-focus-border-color: #3b82f6;
  --uniface-picker-background: white;
  --uniface-picker-text-color: #374151;
  --uniface-picker-placeholder-color: #9ca3af;
}
```

### Custom Styling

```css
.custom-lookup {
  --uniface-picker-border-color: #e2e8f0;
  --uniface-picker-focus-border-color: #2563eb;
  border-radius: 8px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}

.custom-lookup input {
  font-weight: 500;
}

.custom-lookup .action-button {
  color: #2563eb;
}
```

### Variant Styles

```svelte
<!-- Outlined variant -->
<LookupEditor variant="outlined" />

<!-- Filled variant -->
<LookupEditor variant="filled" />

<!-- Plain variant -->
<LookupEditor variant="plain" />
```

## Integration Patterns

### With Modal Dialogs

```svelte
<script>
  import LookupEditor from '@ticatec/uniface-element/lookup-editor';
  import Modal from '@ticatec/uniface-element/modal';
  
  let showModal = false;
  let selectedItem = null;
  let itemDisplay = '';
  
  function openLookup() {
    showModal = true;
  }
  
  function handleItemSelected(item) {
    selectedItem = item;
    itemDisplay = item.name;
    showModal = false;
  }
</script>

<LookupEditor 
  bind:value={selectedItem}
  text={itemDisplay}
  onAction={openLookup}
  placeholder="Select an item"
  variant="outlined"
/>

<Modal bind:show={showModal} title="Select Item">
  <!-- Your lookup/selection content here -->
  <ItemSelectionList on:select={handleItemSelected} />
</Modal>
```

### With External APIs

```svelte
<script>
  import LookupEditor from '@ticatec/uniface-element/lookup-editor';
  
  let selectedRecord = null;
  let recordDisplay = '';
  let isLoading = false;
  
  async function handleLookup() {
    isLoading = true;
    
    try {
      // Open external lookup system
      const result = await openExternalLookup();
      
      if (result) {
        selectedRecord = result;
        recordDisplay = result.displayName;
      }
    } catch (error) {
      console.error('Lookup failed:', error);
    } finally {
      isLoading = false;
    }
  }
</script>

<LookupEditor 
  bind:value={selectedRecord}
  text={recordDisplay}
  onAction={handleLookup}
  disabled={isLoading}
  placeholder={isLoading ? 'Loading...' : 'Select a record'}
  variant="outlined"
/>
```

## Best Practices

### 1. Clear Value Display

Always provide meaningful display text:

```svelte
<script>
  // Good: Clear, descriptive display
  $: displayText = selectedCustomer ? 
    `${selectedCustomer.name} (${selectedCustomer.code})` : '';
  
  // Avoid: Just showing IDs or unclear text
  // $: displayText = selectedCustomer?.id;
</script>
```

### 2. Handle Loading States

Show appropriate feedback during lookup operations:

```svelte
<script>
  let isLookupOpen = false;
  
  function handleLookup() {
    isLookupOpen = true;
    // Open lookup dialog
  }
</script>

<LookupEditor 
  disabled={isLookupOpen}
  placeholder={isLookupOpen ? 'Lookup in progress...' : 'Select item'}
  onAction={handleLookup}
/>
```

### 3. Validate Selections

Always validate lookup selections:

```svelte
<script>
  function handleSelectionChange(value) {
    if (value && !value.isActive) {
      // Clear invalid selections
      selectedItem = null;
      displayText = '';
      showError('Selected item is not active');
    }
  }
</script>
```

### 4. Provide Context

Help users understand what they're selecting:

```svelte
<LookupEditor 
  placeholder="Select employee (use employee search)"
  text={selectedEmployee ? 
    `${selectedEmployee.name} - ${selectedEmployee.department}` : 
    ''
  }
/>
```

## Accessibility Features

- **Keyboard Navigation**: Full keyboard support with tab and enter keys
- **Screen Reader Support**: Proper labeling and announcements
- **Focus Management**: Clear focus indicators and logical tab order
- **ARIA Attributes**: Appropriate roles and properties for assistive technology

## Browser Support

- **Modern Browsers**: Chrome, Firefox, Safari, Edge (latest versions)
- **Mobile Browsers**: iOS Safari, Chrome Mobile, Firefox Mobile
- **Keyboard Navigation**: Full support across all platforms

## Related Components

- **CommonPicker**: Base picker component used internally
- **FormField**: Form field wrapper for labels and validation
- **Modal**: Modal dialogs for lookup interfaces
- **ListBox**: List selection component for lookup dialogs

## License

MIT License - see LICENSE file for details.