# Toast

A lightweight toast notification system for displaying temporary messages to users. Features customizable types (success, error, info), automatic dismissal, and smooth animations. Perfect for status updates, error messages, and user feedback.

## Installation

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

## Import

```typescript
import ToastBoard, { type Toast } from "@ticatec/uniface-element/ToastBoard";
```

## Basic Usage

```svelte
<script>
  import ToastBoard from "@ticatec/uniface-element/ToastBoard";
  
  function showSuccessToast() {
    window.Toast.show("Operation completed successfully!", "success", 3);
  }
  
  function showErrorToast() {
    window.Toast.show("Something went wrong!", "error", 5);
  }
  
  function showInfoToast() {
    window.Toast.show("Information message", "info");
  }
</script>

<!-- Include ToastBoard component (usually in your root layout) -->
<ToastBoard />

<!-- Trigger toasts from anywhere -->
<button on:click={showSuccessToast}>Show Success</button>
<button on:click={showErrorToast}>Show Error</button>
<button on:click={showInfoToast}>Show Info</button>
```

## Props (ToastBoard)

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `fromBottom` | `boolean` | `false` | Whether to show toasts from bottom of screen |

## Global Toast API

Once ToastBoard is mounted, the global `window.Toast` object becomes available:

### Toast.show()

```typescript
window.Toast.show(message: string, type?: "error" | "info" | "success", duration?: number)
```

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `message` | `string` | Required | The message to display |
| `type` | `"error" \| "info" \| "success"` | `"error"` | Toast type/styling |
| `duration` | `number` | `3` | Duration in seconds before auto-dismiss |

## Types

### Success Toast
- **Color**: Green background (`#2DC071`)
- **Usage**: Successful operations, confirmations
- **Example**: "Data saved successfully!"

### Error Toast
- **Color**: Red background (`#FF685B`)
- **Usage**: Error messages, failed operations
- **Example**: "Failed to save data"

### Info Toast
- **Color**: Blue background (`#0061FF`)
- **Usage**: General information, notifications
- **Example**: "New update available"

## Examples

### Basic Implementation

```svelte
<script>
  import ToastBoard from "@ticatec/uniface-element/ToastBoard";
  
  // Simple toast functions
  function success() {
    window.Toast.show("Success! Data has been saved.", "success", 4);
  }
  
  function error() {
    window.Toast.show("Error! Unable to process request.", "error", 6);
  }
  
  function info() {
    window.Toast.show("Info: Check your email for updates.", "info", 3);
  }
</script>

<!-- Mount the toast board -->
<ToastBoard />

<div class="demo">
  <h3>Toast Notifications</h3>
  <button on:click={success}>Success Toast</button>
  <button on:click={error}>Error Toast</button>
  <button on:click={info}>Info Toast</button>
</div>

<style>
  .demo {
    padding: 20px;
  }
  
  button {
    margin: 0 8px 8px 0;
    padding: 8px 16px;
    border: none;
    border-radius: 4px;
    cursor: pointer;
  }
</style>
```

### Form Validation with Toast

```svelte
<script>
  import ToastBoard from "@ticatec/uniface-element/ToastBoard";
  
  let email = '';
  let password = '';
  let loading = false;
  
  async function handleSubmit() {
    if (!email) {
      window.Toast.show("Email is required", "error", 4);
      return;
    }
    
    if (!email.includes('@')) {
      window.Toast.show("Please enter a valid email address", "error", 4);
      return;
    }
    
    if (!password) {
      window.Toast.show("Password is required", "error", 4);
      return;
    }
    
    if (password.length < 6) {
      window.Toast.show("Password must be at least 6 characters", "error", 4);
      return;
    }
    
    loading = true;
    
    try {
      // Simulate API call
      await new Promise(resolve => setTimeout(resolve, 2000));
      
      if (Math.random() > 0.5) {
        window.Toast.show("Login successful! Welcome back.", "success", 3);
        // Redirect or update UI
      } else {
        window.Toast.show("Invalid credentials. Please try again.", "error", 5);
      }
    } catch (error) {
      window.Toast.show("Network error. Please check your connection.", "error", 5);
    } finally {
      loading = false;
    }
  }
</script>

<ToastBoard />

<form on:submit|preventDefault={handleSubmit}>
  <h3>Login Form</h3>
  
  <div class="field">
    <label>Email:</label>
    <input 
      type="email" 
      bind:value={email} 
      placeholder="Enter your email" 
      disabled={loading}
    />
  </div>
  
  <div class="field">
    <label>Password:</label>
    <input 
      type="password" 
      bind:value={password} 
      placeholder="Enter your password" 
      disabled={loading}
    />
  </div>
  
  <button type="submit" disabled={loading}>
    {loading ? 'Logging in...' : 'Login'}
  </button>
</form>

<style>
  form {
    max-width: 300px;
    margin: 20px;
    padding: 20px;
    border: 1px solid #ddd;
    border-radius: 8px;
  }
  
  .field {
    margin-bottom: 16px;
  }
  
  label {
    display: block;
    margin-bottom: 4px;
    font-weight: 500;
  }
  
  input {
    width: 100%;
    padding: 8px 12px;
    border: 1px solid #ccc;
    border-radius: 4px;
    box-sizing: border-box;
  }
  
  button {
    width: 100%;
    padding: 10px;
    background: #007bff;
    color: white;
    border: none;
    border-radius: 4px;
    cursor: pointer;
  }
  
  button:disabled {
    background: #ccc;
    cursor: not-allowed;
  }
</style>
```

### File Upload with Progress Toast

```svelte
<script>
  import ToastBoard from "@ticatec/uniface-element/ToastBoard";
  
  let fileInput;
  let uploading = false;
  
  async function handleFileUpload(event) {
    const file = event.target.files[0];
    
    if (!file) {
      window.Toast.show("Please select a file to upload", "error", 3);
      return;
    }
    
    // File size validation (5MB limit)
    if (file.size > 5 * 1024 * 1024) {
      window.Toast.show("File size must be less than 5MB", "error", 4);
      return;
    }
    
    // File type validation
    const allowedTypes = ['image/jpeg', 'image/png', 'image/gif'];
    if (!allowedTypes.includes(file.type)) {
      window.Toast.show("Only JPEG, PNG, and GIF files are allowed", "error", 4);
      return;
    }
    
    uploading = true;
    window.Toast.show("Starting file upload...", "info", 2);
    
    try {
      // Simulate upload progress
      await simulateUpload(file);
      
      window.Toast.show(`File "${file.name}" uploaded successfully!`, "success", 4);
      
      // Clear the input
      fileInput.value = '';
      
    } catch (error) {
      window.Toast.show("Upload failed. Please try again.", "error", 5);
    } finally {
      uploading = false;
    }
  }
  
  async function simulateUpload(file) {
    // Simulate upload stages
    await new Promise(resolve => setTimeout(resolve, 1000));
    window.Toast.show("Processing file...", "info", 2);
    
    await new Promise(resolve => setTimeout(resolve, 1500));
    window.Toast.show("Uploading to server...", "info", 2);
    
    await new Promise(resolve => setTimeout(resolve, 1000));
    
    // Random failure simulation
    if (Math.random() < 0.2) {
      throw new Error("Upload failed");
    }
  }
</script>

<ToastBoard />

<div class="upload-container">
  <h3>File Upload</h3>
  
  <div class="upload-area">
    <input 
      bind:this={fileInput}
      type="file" 
      accept="image/*" 
      on:change={handleFileUpload}
      disabled={uploading}
      id="file-upload"
    />
    <label for="file-upload" class:uploading>
      {uploading ? '⏳ Uploading...' : '📁 Choose File'}
    </label>
  </div>
  
  <p class="help-text">
    Select JPEG, PNG, or GIF files (max 5MB)
  </p>
</div>

<style>
  .upload-container {
    max-width: 400px;
    margin: 20px;
    padding: 20px;
    border: 1px solid #ddd;
    border-radius: 8px;
  }
  
  .upload-area {
    margin: 16px 0;
  }
  
  input[type="file"] {
    display: none;
  }
  
  label {
    display: inline-block;
    padding: 12px 24px;
    background: #007bff;
    color: white;
    border-radius: 4px;
    cursor: pointer;
    transition: background 0.2s;
  }
  
  label:hover {
    background: #0056b3;
  }
  
  label.uploading {
    background: #6c757d;
    cursor: not-allowed;
  }
  
  .help-text {
    font-size: 14px;
    color: #666;
    margin: 8px 0 0 0;
  }
</style>
```

### API Integration with Toast

```svelte
<script>
  import ToastBoard from "@ticatec/uniface-element/ToastBoard";
  
  let users = [];
  let loading = false;
  let newUser = { name: '', email: '' };
  
  async function fetchUsers() {
    loading = true;
    window.Toast.show("Loading users...", "info", 2);
    
    try {
      // Simulate API call
      await new Promise(resolve => setTimeout(resolve, 1500));
      
      // Mock data
      users = [
        { id: 1, name: 'John Doe', email: 'john@example.com' },
        { id: 2, name: 'Jane Smith', email: 'jane@example.com' }
      ];
      
      window.Toast.show(`Loaded ${users.length} users successfully`, "success", 3);
      
    } catch (error) {
      window.Toast.show("Failed to load users", "error", 4);
    } finally {
      loading = false;
    }
  }
  
  async function addUser() {
    if (!newUser.name || !newUser.email) {
      window.Toast.show("Please fill in all fields", "error", 3);
      return;
    }
    
    loading = true;
    
    try {
      // Simulate API call
      await new Promise(resolve => setTimeout(resolve, 1000));
      
      const user = {
        id: Date.now(),
        name: newUser.name,
        email: newUser.email
      };
      
      users = [...users, user];
      newUser = { name: '', email: '' };
      
      window.Toast.show("User added successfully!", "success", 3);
      
    } catch (error) {
      window.Toast.show("Failed to add user", "error", 4);
    } finally {
      loading = false;
    }
  }
  
  async function deleteUser(userId) {
    if (!confirm('Are you sure you want to delete this user?')) {
      return;
    }
    
    try {
      // Simulate API call
      await new Promise(resolve => setTimeout(resolve, 800));
      
      users = users.filter(u => u.id !== userId);
      window.Toast.show("User deleted successfully", "success", 3);
      
    } catch (error) {
      window.Toast.show("Failed to delete user", "error", 4);
    }
  }
</script>

<ToastBoard />

<div class="app">
  <h3>User Management</h3>
  
  <div class="actions">
    <button on:click={fetchUsers} disabled={loading}>
      {loading ? 'Loading...' : 'Load Users'}
    </button>
  </div>
  
  <div class="add-user">
    <h4>Add New User</h4>
    <input 
      bind:value={newUser.name} 
      placeholder="Name" 
      disabled={loading}
    />
    <input 
      bind:value={newUser.email} 
      placeholder="Email" 
      disabled={loading}
    />
    <button on:click={addUser} disabled={loading}>
      {loading ? 'Adding...' : 'Add User'}
    </button>
  </div>
  
  <div class="users">
    <h4>Users ({users.length})</h4>
    {#each users as user}
      <div class="user-item">
        <div>
          <strong>{user.name}</strong>
          <span>{user.email}</span>
        </div>
        <button on:click={() => deleteUser(user.id)}>Delete</button>
      </div>
    {/each}
  </div>
</div>

<style>
  .app {
    max-width: 600px;
    margin: 20px;
    padding: 20px;
    border: 1px solid #ddd;
    border-radius: 8px;
  }
  
  .actions {
    margin-bottom: 20px;
  }
  
  .add-user {
    margin-bottom: 20px;
    padding: 16px;
    background: #f8f9fa;
    border-radius: 4px;
  }
  
  .add-user h4 {
    margin: 0 0 12px 0;
  }
  
  .add-user input {
    margin: 0 8px 8px 0;
    padding: 8px 12px;
    border: 1px solid #ccc;
    border-radius: 4px;
  }
  
  .users h4 {
    margin-bottom: 12px;
  }
  
  .user-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 12px;
    border: 1px solid #eee;
    border-radius: 4px;
    margin-bottom: 8px;
  }
  
  .user-item div {
    display: flex;
    flex-direction: column;
  }
  
  .user-item span {
    font-size: 14px;
    color: #666;
  }
  
  button {
    padding: 8px 16px;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    background: #007bff;
    color: white;
  }
  
  button:disabled {
    background: #ccc;
    cursor: not-allowed;
  }
</style>
```

### Bottom Positioned Toasts

```svelte
<script>
  import ToastBoard from "@ticatec/uniface-element/ToastBoard";
  
  function showBottomToast() {
    window.Toast.show("This toast appears from the bottom!", "info", 4);
  }
</script>

<!-- Position toasts at bottom of screen -->
<ToastBoard fromBottom={true} />

<button on:click={showBottomToast}>Show Bottom Toast</button>
```

## Features

- **Multiple Types**: Success, error, and info variants with distinct colors
- **Auto Dismissal**: Configurable duration with automatic hiding
- **Smooth Animations**: Fly-in transitions from top or bottom
- **Global Access**: Use from anywhere via `window.Toast.show()`
- **Positioning**: Support for top or bottom screen positioning
- **Stacking**: Multiple toasts can be displayed sequentially
- **Responsive**: Works on all screen sizes

## Styling

The toast component uses CSS custom properties for theming:

```css
:root {
  --uniface-toast-text-color: #ffffff;
  --uniface-toast-error-background-color: #FF685B;
  --uniface-toast-info-background-color: #0061FF;
  --uniface-toast-successful-background-color: #2DC071;
}
```

### Custom Styling

```css
/* Override toast colors */
:root {
  --uniface-toast-error-background-color: #dc3545;
  --uniface-toast-info-background-color: #17a2b8;
  --uniface-toast-successful-background-color: #28a745;
}

/* Custom toast board styles */
.uniface-toast-board {
  /* Your custom styles */
}
```

## Best Practices

1. **Global Setup**: Include ToastBoard once in your root layout/app component
2. **Message Clarity**: Use clear, concise messages that users can quickly understand
3. **Duration**: Use longer durations for error messages, shorter for success
4. **Type Consistency**: Use consistent toast types across your application
5. **Positioning**: Choose top or bottom positioning based on your UI layout
6. **Error Handling**: Always show toast feedback for async operations

## Accessibility

- High contrast colors for readability
- Automatic dismissal prevents screen clutter
- Non-intrusive positioning
- Clear visual hierarchy with distinct colors

## Browser Support

- Modern browsers with CSS custom properties support
- Compatible with Svelte 5+
- Smooth animations on supported browsers
- Graceful fallback for older browsers

## Related Components

- `MessageBox` - Modal dialog for important messages
- `AlertBar` - Persistent alert notifications
- `NotificationCenter` - Advanced notification management