# PopupHint

A global tooltip system that provides contextual hints and information when users hover over elements, with automatic positioning and timing controls.

## Features

- **Global Access**: Available throughout the application via `window.Hint`
- **Mouse Tracking**: Automatically positions hints near mouse cursor
- **Delayed Display**: 500ms delay before showing to prevent flickering
- **Auto Hide**: Automatically hides when mouse leaves the element
- **Portal Rendering**: Renders hints in document body for proper z-index layering
- **Responsive Positioning**: Automatically adjusts position to stay within viewport
- **Event Management**: Proper cleanup of event listeners
- **Lightweight**: Minimal performance impact with efficient event handling

## Installation

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

## Setup

First, add the PopupHint component to your root layout or app component:

```svelte
<script>
  import PopupHint from '@ticatec/uniface-element/PopupHint';
</script>

<!-- Your app content -->
<main>
  <!-- Your components -->
</main>

<!-- PopupHint - Global instance -->
<PopupHint />
```

## Basic Usage

Once the PopupHint is mounted, you can show hints from anywhere in your application:

```javascript
// Show a hint when hovering over an element
function handleMouseEnter(event) {
  window.Hint.show(
    event.target,           // Target element
    'This is a helpful hint!', // Hint text
    event.clientX,          // Mouse X position
    event.clientY           // Mouse Y position
  );
}
```

## API Reference

### Global Methods

#### `window.Hint.show(element, text, x, y)`

Shows a hint tooltip near the specified coordinates.

**Parameters:**
- `element` (Element): The target element that triggered the hint
- `text` (string): The hint text to display
- `x` (number): Mouse X coordinate
- `y` (number): Mouse Y coordinate

**Behavior:**
- Adds automatic `mouseleave` event listener to hide hint
- 500ms delay before showing to prevent accidental triggers
- Automatically positions hint near cursor with offset

### Types

```typescript
export type ShowHint = (element: Element, text: string, x: number, y: number) => void;

export default interface IHint {
  show: ShowHint;
}
```

## Examples

### Basic Button Hints

```svelte
<script>
  function showHint(text) {
    return function(event) {
      window.Hint.show(event.target, text, event.clientX, event.clientY);
    };
  }
</script>

<div class="button-group">
  <button on:mouseenter={showHint('Save your current work')}>
    Save
  </button>
  
  <button on:mouseenter={showHint('Cancel all changes')}>
    Cancel
  </button>
  
  <button on:mouseenter={showHint('Export data to Excel format')}>
    Export
  </button>
</div>
```

### Icon Tooltips

```svelte
<script>
  import Icon from '@ticatec/uniface-element/Icon';
  
  const iconHints = {
    edit: 'Edit this item',
    delete: 'Delete this item (cannot be undone)',
    share: 'Share with others',
    bookmark: 'Add to bookmarks',
    download: 'Download file'
  };
  
  function handleIconHover(iconType) {
    return function(event) {
      const hint = iconHints[iconType];
      if (hint) {
        window.Hint.show(event.target, hint, event.clientX, event.clientY);
      }
    };
  }
</script>

<div class="toolbar">
  <Icon 
    name="icon_google_edit" 
    on:mouseenter={handleIconHover('edit')}
  />
  <Icon 
    name="icon_google_delete" 
    on:mouseenter={handleIconHover('delete')}
  />
  <Icon 
    name="icon_google_share" 
    on:mouseenter={handleIconHover('share')}
  />
  <Icon 
    name="icon_google_bookmark" 
    on:mouseenter={handleIconHover('bookmark')}
  />
  <Icon 
    name="icon_google_download" 
    on:mouseenter={handleIconHover('download')}
  />
</div>

<style>
  .toolbar {
    display: flex;
    gap: 8px;
    padding: 12px;
  }
</style>
```

### Form Field Hints

```svelte
<script>
  import FormField from '@ticatec/uniface-element/FormField';
  import TextEditor from '@ticatec/uniface-element/TextEditor';
  
  let formData = {
    username: '',
    email: '',
    password: ''
  };
  
  const fieldHints = {
    username: 'Username must be 3-20 characters, letters and numbers only',
    email: 'We\'ll use this email for account recovery and notifications',
    password: 'Password must be at least 8 characters with uppercase, lowercase, and numbers'
  };
  
  function showFieldHint(fieldName) {
    return function(event) {
      window.Hint.show(event.target, fieldHints[fieldName], event.clientX, event.clientY);
    };
  }
</script>

<form class="registration-form">
  <FormField label="Username">
    <TextEditor 
      variant="outlined"
      bind:value={formData.username}
      placeholder="Enter username"
      on:mouseenter={showFieldHint('username')}
    />
  </FormField>
  
  <FormField label="Email">
    <TextEditor 
      variant="outlined"
      bind:value={formData.email}
      placeholder="Enter email address"
      on:mouseenter={showFieldHint('email')}
    />
  </FormField>
  
  <FormField label="Password">
    <TextEditor 
      variant="outlined"
      type="password"
      bind:value={formData.password}
      placeholder="Enter password"
      on:mouseenter={showFieldHint('password')}
    />
  </FormField>
</form>
```

### Data Table Row Hints

```svelte
<script>
  let users = [
    { 
      id: 1, 
      name: 'John Doe', 
      email: 'john@example.com', 
      status: 'active',
      lastLogin: '2024-01-15 14:30:00',
      role: 'Administrator'
    },
    { 
      id: 2, 
      name: 'Jane Smith', 
      email: 'jane@example.com', 
      status: 'inactive',
      lastLogin: '2024-01-10 09:15:00',
      role: 'User'
    }
  ];
  
  function showUserHint(user) {
    return function(event) {
      const hint = `
        Last Login: ${user.lastLogin}
        Role: ${user.role}
        Status: ${user.status.toUpperCase()}
        ID: ${user.id}
      `;
      window.Hint.show(event.target, hint, event.clientX, event.clientY);
    };
  }
  
  function showStatusHint(status) {
    return function(event) {
      const hints = {
        active: 'User is currently active and can access the system',
        inactive: 'User account has been deactivated',
        pending: 'User registration is pending approval',
        suspended: 'User account has been temporarily suspended'
      };
      
      window.Hint.show(event.target, hints[status] || 'Unknown status', event.clientX, event.clientY);
    };
  }
</script>

<table class="user-table">
  <thead>
    <tr>
      <th>Name</th>
      <th>Email</th>
      <th>Status</th>
    </tr>
  </thead>
  <tbody>
    {#each users as user}
      <tr on:mouseenter={showUserHint(user)}>
        <td>{user.name}</td>
        <td>{user.email}</td>
        <td>
          <span 
            class="status status-{user.status}"
            on:mouseenter={showStatusHint(user.status)}
          >
            {user.status}
          </span>
        </td>
      </tr>
    {/each}
  </tbody>
</table>

<style>
  .user-table {
    width: 100%;
    border-collapse: collapse;
  }
  
  .user-table th,
  .user-table td {
    padding: 12px;
    text-align: left;
    border-bottom: 1px solid #ddd;
  }
  
  .user-table tr:hover {
    background-color: #f5f5f5;
  }
  
  .status {
    padding: 4px 8px;
    border-radius: 12px;
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
  }
  
  .status-active {
    background: #d4edda;
    color: #155724;
  }
  
  .status-inactive {
    background: #f8d7da;
    color: #721c24;
  }
</style>
```

### Chart and Graph Hints

```svelte
<script>
  let chartData = [
    { month: 'Jan', sales: 12000, growth: '+15%' },
    { month: 'Feb', sales: 13500, growth: '+12.5%' },
    { month: 'Mar', sales: 11200, growth: '-17%' },
    { month: 'Apr', sales: 14800, growth: '+32%' },
    { month: 'May', sales: 16200, growth: '+9.5%' }
  ];
  
  function showChartHint(dataPoint) {
    return function(event) {
      const hint = `
        Month: ${dataPoint.month}
        Sales: $${dataPoint.sales.toLocaleString()}
        Growth: ${dataPoint.growth}
      `;
      window.Hint.show(event.target, hint, event.clientX, event.clientY);
    };
  }
</script>

<div class="chart-container">
  <h3>Sales Chart</h3>
  <div class="chart">
    {#each chartData as data, i}
      <div 
        class="chart-bar"
        style="height: {(data.sales / 20000) * 200}px;"
        on:mouseenter={showChartHint(data)}
      >
        <div class="bar-label">{data.month}</div>
      </div>
    {/each}
  </div>
</div>

<style>
  .chart-container {
    padding: 20px;
  }
  
  .chart {
    display: flex;
    align-items: flex-end;
    gap: 12px;
    height: 250px;
    border-bottom: 2px solid #333;
    padding: 20px 0;
  }
  
  .chart-bar {
    background: linear-gradient(to top, #007bff, #66b3ff);
    width: 60px;
    border-radius: 4px 4px 0 0;
    cursor: pointer;
    transition: transform 0.2s;
    position: relative;
  }
  
  .chart-bar:hover {
    transform: scale(1.05);
  }
  
  .bar-label {
    position: absolute;
    bottom: -25px;
    left: 50%;
    transform: translateX(-50%);
    font-size: 12px;
    font-weight: 600;
  }
</style>
```

### Image Gallery with Metadata

```svelte
<script>
  let images = [
    {
      id: 1,
      src: 'https://picsum.photos/300/200?random=1',
      title: 'Sunset Landscape',
      description: 'Beautiful sunset over mountains',
      camera: 'Canon EOS R5',
      settings: 'f/8, 1/250s, ISO 100',
      location: 'Rocky Mountains, Colorado'
    },
    {
      id: 2,
      src: 'https://picsum.photos/300/200?random=2',
      title: 'Urban Architecture',
      description: 'Modern building design',
      camera: 'Sony A7R IV',
      settings: 'f/11, 1/125s, ISO 200',
      location: 'Downtown Seattle'
    }
  ];
  
  function showImageHint(image) {
    return function(event) {
      const hint = `
        ${image.title}
        
        ${image.description}
        
        Camera: ${image.camera}
        Settings: ${image.settings}
        Location: ${image.location}
      `;
      window.Hint.show(event.target, hint, event.clientX, event.clientY);
    };
  }
</script>

<div class="gallery">
  {#each images as image}
    <div 
      class="image-card"
      on:mouseenter={showImageHint(image)}
    >
      <img src={image.src} alt={image.title} />
      <div class="image-overlay">
        <h4>{image.title}</h4>
      </div>
    </div>
  {/each}
</div>

<style>
  .gallery {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: 20px;
    padding: 20px;
  }
  
  .image-card {
    position: relative;
    border-radius: 8px;
    overflow: hidden;
    cursor: pointer;
    transition: transform 0.2s;
  }
  
  .image-card:hover {
    transform: translateY(-4px);
  }
  
  .image-card img {
    width: 100%;
    height: 200px;
    object-fit: cover;
  }
  
  .image-overlay {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    background: linear-gradient(transparent, rgba(0,0,0,0.7));
    color: white;
    padding: 20px;
  }
  
  .image-overlay h4 {
    margin: 0;
    font-size: 16px;
  }
</style>
```

### Progress Indicators with Status

```svelte
<script>
  let tasks = [
    { 
      id: 1, 
      name: 'Database Migration', 
      progress: 75, 
      status: 'In Progress',
      eta: '2 hours remaining',
      details: 'Migrating user data tables (3 of 4 completed)'
    },
    { 
      id: 2, 
      name: 'API Testing', 
      progress: 100, 
      status: 'Completed',
      eta: 'Finished',
      details: 'All endpoints tested successfully with 100% coverage'
    },
    { 
      id: 3, 
      name: 'UI Updates', 
      progress: 45, 
      status: 'In Progress',
      eta: '4 hours remaining',
      details: 'Updating 12 components (5 of 12 completed)'
    }
  ];
  
  function showProgressHint(task) {
    return function(event) {
      const hint = `
        Task: ${task.name}
        Status: ${task.status}
        Progress: ${task.progress}%
        ETA: ${task.eta}
        
        Details: ${task.details}
      `;
      window.Hint.show(event.target, hint, event.clientX, event.clientY);
    };
  }
</script>

<div class="progress-dashboard">
  <h3>Task Progress</h3>
  {#each tasks as task}
    <div class="progress-item">
      <div class="progress-info">
        <span class="task-name">{task.name}</span>
        <span class="progress-percent">{task.progress}%</span>
      </div>
      <div 
        class="progress-bar"
        on:mouseenter={showProgressHint(task)}
      >
        <div 
          class="progress-fill"
          style="width: {task.progress}%"
        ></div>
      </div>
    </div>
  {/each}
</div>

<style>
  .progress-dashboard {
    max-width: 500px;
    padding: 20px;
  }
  
  .progress-item {
    margin-bottom: 16px;
  }
  
  .progress-info {
    display: flex;
    justify-content: space-between;
    margin-bottom: 8px;
  }
  
  .task-name {
    font-weight: 600;
  }
  
  .progress-percent {
    color: #666;
  }
  
  .progress-bar {
    height: 8px;
    background: #e0e0e0;
    border-radius: 4px;
    overflow: hidden;
    cursor: pointer;
  }
  
  .progress-fill {
    height: 100%;
    background: linear-gradient(90deg, #007bff, #28a745);
    transition: width 0.3s ease;
  }
</style>
```

### Conditional Hints with Dynamic Content

```svelte
<script>
  let user = {
    name: 'John Doe',
    email: 'john@example.com',
    role: 'admin',
    lastActive: '2024-01-15T10:30:00Z',
    permissions: ['read', 'write', 'delete', 'admin']
  };
  
  function showUserBadgeHint(event) {
    const now = new Date();
    const lastActive = new Date(user.lastActive);
    const hoursAgo = Math.floor((now - lastActive) / (1000 * 60 * 60));
    
    let activityStatus;
    if (hoursAgo < 1) {
      activityStatus = 'Active now';
    } else if (hoursAgo < 24) {
      activityStatus = `Active ${hoursAgo} hours ago`;
    } else {
      const daysAgo = Math.floor(hoursAgo / 24);
      activityStatus = `Active ${daysAgo} days ago`;
    }
    
    const hint = `
      ${user.name} (${user.role.toUpperCase()})
      ${user.email}
      
      ${activityStatus}
      
      Permissions: ${user.permissions.join(', ')}
    `;
    
    window.Hint.show(event.target, hint, event.clientX, event.clientY);
  }
  
  function showPermissionHint(permission) {
    return function(event) {
      const permissionDescriptions = {
        read: 'Can view all content and data',
        write: 'Can create and edit content',
        delete: 'Can remove content and data',
        admin: 'Full administrative access to all features'
      };
      
      const hint = permissionDescriptions[permission] || 'Unknown permission';
      window.Hint.show(event.target, hint, event.clientX, event.clientY);
    };
  }
</script>

<div class="user-profile">
  <div 
    class="user-badge"
    on:mouseenter={showUserBadgeHint}
  >
    <div class="avatar">
      {user.name.split(' ').map(n => n[0]).join('')}
    </div>
    <div class="user-info">
      <div class="user-name">{user.name}</div>
      <div class="user-role">{user.role}</div>
    </div>
  </div>
  
  <div class="permissions">
    <h4>Permissions</h4>
    <div class="permission-badges">
      {#each user.permissions as permission}
        <span 
          class="permission-badge"
          on:mouseenter={showPermissionHint(permission)}
        >
          {permission}
        </span>
      {/each}
    </div>
  </div>
</div>

<style>
  .user-profile {
    max-width: 300px;
    padding: 20px;
    border: 1px solid #ddd;
    border-radius: 8px;
  }
  
  .user-badge {
    display: flex;
    align-items: center;
    gap: 12px;
    cursor: pointer;
    padding: 8px;
    border-radius: 6px;
    transition: background-color 0.2s;
  }
  
  .user-badge:hover {
    background-color: #f5f5f5;
  }
  
  .avatar {
    width: 40px;
    height: 40px;
    background: #007bff;
    color: white;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: bold;
  }
  
  .user-name {
    font-weight: 600;
  }
  
  .user-role {
    color: #666;
    font-size: 14px;
    text-transform: capitalize;
  }
  
  .permissions {
    margin-top: 20px;
  }
  
  .permissions h4 {
    margin: 0 0 12px 0;
  }
  
  .permission-badges {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
  }
  
  .permission-badge {
    background: #e3f2fd;
    color: #1976d2;
    padding: 4px 8px;
    border-radius: 12px;
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
    transition: background-color 0.2s;
  }
  
  .permission-badge:hover {
    background: #bbdefb;
  }
</style>
```

## Best Practices

1. **Meaningful Content**: Provide genuinely helpful information in hints
2. **Appropriate Timing**: The 500ms delay prevents accidental triggers
3. **Concise Text**: Keep hint text brief but informative
4. **Consistent Positioning**: Use mouse coordinates for natural positioning
5. **Performance**: Avoid complex calculations in hint generation
6. **Accessibility**: Consider keyboard users and screen readers
7. **Content Hierarchy**: Use hints for secondary information, not primary actions

## Styling

The PopupHint component can be styled through CSS:

```css
.uniface-popup-hint {
  position: fixed;
  background: rgba(0, 0, 0, 0.8);
  color: white;
  padding: 8px 12px;
  border-radius: 6px;
  font-size: 13px;
  line-height: 1.4;
  z-index: 10000;
  pointer-events: none;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
  max-width: 300px;
  word-wrap: break-word;
}

.uniface-popup-hint::before {
  content: '';
  position: absolute;
  top: -4px;
  left: 8px;
  width: 0;
  height: 0;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-bottom: 4px solid rgba(0, 0, 0, 0.8);
}
```

## Accessibility

- Hints are supplementary information, not critical UI elements
- Does not interfere with keyboard navigation
- Content is descriptive text that enhances understanding
- Compatible with screen readers when used appropriately
- Does not trap focus or block interaction

## Performance Considerations

- Uses event delegation for efficient memory management
- Automatic cleanup of event listeners prevents memory leaks
- Portal rendering ensures proper layering without layout recalculation
- Minimal DOM manipulation for smooth performance

## Related Components

- [Tooltip](../tooltip/README.md) - For more structured tooltip content
- [MessageBox](../message-box/README.md) - For modal information dialogs
- [Toast](../toast/README.md) - For notification messages
- [Dialog](../dialog/README.md) - For complex interactive content