# Dialog Components

A comprehensive dialog system built with Svelte, providing flexible modal dialogs with drag-and-drop functionality, action buttons, and advanced lifecycle management.

## Features

- **Multiple Dialog Types**: Dialog, CommonDialog, and DialogBoard components
- **Drag & Drop**: Movable dialogs with title bar dragging
- **Action Buttons**: Configurable button actions with automatic result handling
- **Close Confirmation**: Optional confirmation dialogs before closing
- **Modal Management**: Stack-based dialog management with overlay
- **Responsive Design**: Automatic sizing and positioning
- **Accessibility**: ARIA support and keyboard navigation
- **Lifecycle Hooks**: onClose callbacks with result handling
- **Global Dialog API**: Window-level dialog management
- **Customizable Styling**: Flexible theming and sizing options

## Installation

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

```typescript
import Dialog, { CommonDialog, DialogBoard } from '@ticatec/uniface-element/Dialog';
```

Or if using within the same project:
```typescript
import Dialog, { CommonDialog, DialogBoard } from '$lib/dialog';
```

## Components Overview

### Dialog
The base dialog component with full customization options.

### CommonDialog
A simplified dialog with built-in confirm/cancel actions.

### DialogBoard
The dialog container and management system.

## Setup

### 1. Add DialogBoard to Your App

First, add the DialogBoard component to your main app layout:

```svelte
<!-- App.svelte or +layout.svelte -->
<script>
  import { DialogBoard } from '$lib/dialog';
</script>

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

<!-- Dialog container (should be at the end) -->
<DialogBoard />
```

### 2. Initialize Global Dialog API

The DialogBoard automatically initializes the global `window.Dialog` API when mounted.

## Dialog Component

### Basic Usage

```svelte
<script>
  import Dialog from '$lib/dialog';
  import { ModalResult } from '$lib/dialog/ModalResult';
  
  let showDialog = false;
  
  const actions = [
    {
      label: 'Save',
      type: 'primary',
      handler: async () => {
        // Save logic here
        console.log('Saving...');
        return true; // Return true to close dialog
      }
    }
  ];
  
  function handleClose(result) {
    console.log('Dialog closed with result:', result);
    showDialog = false;
  }
</script>

{#if showDialog}
  <Dialog 
    title="My Dialog" 
    {actions} 
    onClose={handleClose}
    width="500px"
    height="300px"
  >
    <p>Dialog content goes here...</p>
  </Dialog>
{/if}
```

### Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `title` | `string` | `''` | Dialog title displayed in title bar |
| `width` | `string` | `'unset'` | Dialog width (CSS value) |
| `height` | `string` | `'unset'` | Dialog height (CSS value) |
| `actions` | `ButtonActions \| null` | `null` | Array of action buttons |
| `closeConfirm` | `DialogCloseConfirm \| null` | `null` | Confirmation function before closing |
| `content$style` | `string` | `''` | Custom styles for content area |
| `closeAction` | `ButtonAction \| null` | `null` | Custom close button configuration |
| `onClose` | `OnClose \| null` | `null` | Callback when dialog closes |
| `dialog$style` | `string` | `''` | Custom styles for dialog container |

### Methods

| Method | Description |
|--------|-------------|
| `close(result: ModalResult)` | Programmatically close the dialog with a result |

## CommonDialog Component

A simplified dialog with built-in confirm/cancel pattern.

### Basic Usage

```svelte
<script>
  import { CommonDialog } from '$lib/dialog';
  
  let showDialog = false;
  
  async function handleConfirm() {
    // Your confirm logic
    console.log('Confirmed!');
    return true; // Return true to close dialog
  }
  
  function handleClose(result) {
    console.log('Dialog result:', result);
    showDialog = false;
  }
</script>

{#if showDialog}
  <CommonDialog 
    title="Confirm Action"
    confirmHandler={handleConfirm}
    onClose={handleClose}
    width="400px"
  >
    <p>Are you sure you want to proceed?</p>
  </CommonDialog>
{/if}
```

### Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `title` | `string` | `''` | Dialog title |
| `width` | `string` | `'unset'` | Dialog width |
| `height` | `string` | `'unset'` | Dialog height |
| `closeConfirm` | `DialogCloseConfirm \| null` | `null` | Close confirmation function |
| `content$style` | `string` | `''` | Content area styles |
| `enableConfirm` | `boolean` | `true` | Enable/disable confirm button |
| `confirmHandler` | `(() => Promise<any>) \| null` | `null` | Confirm button handler |
| `confirmText` | `string \| null` | `null` | Custom confirm button text |
| `onClose` | `OnClose \| null` | `null` | Close callback |

## Global Dialog API

Use the global `window.Dialog` API to show dialogs from anywhere in your application.

### Showing a Dialog

```svelte
<script>
  import MyDialogContent from './MyDialogContent.svelte';
  
  function openDialog() {
    window.Dialog.showModal(MyDialogContent, {
      title: 'My Dialog',
      data: { /* initial data */ },
      onSave: (data) => console.log('Saved:', data)
    });
  }
</script>

<button on:click={openDialog}>Open Dialog</button>
```

### Creating Dialog Content Components

```svelte
<!-- MyDialogContent.svelte -->
<script>
  import Dialog from '$lib/dialog';
  import { ModalResult } from '$lib/dialog/ModalResult';
  
  // Props passed from showModal
  export let title = 'Dialog';
  export let data = {};
  export let onSave = null;
  
  const actions = [
    {
      label: 'Save',
      type: 'primary',
      handler: async () => {
        // Validation logic
        if (!data.name) {
          alert('Name is required');
          return false; // Don't close dialog
        }
        
        // Save logic
        await onSave?.(data);
        return true; // Close dialog
      }
    }
  ];
  
  const closeConfirm = async () => {
    if (hasChanges) {
      return await window.MessageBox.showConfirm(
        'You have unsaved changes. Are you sure?',
        'Confirm Close'
      ) === ModalResult.Ok;
    }
    return true;
  };
</script>

<Dialog {title} {actions} {closeConfirm} width="600px">
  <!-- Your dialog content -->
  <form>
    <input bind:value={data.name} placeholder="Name" />
    <!-- More form fields -->
  </form>
</Dialog>
```

## Action Buttons

### Button Configuration

```typescript
type ButtonAction = {
  label: string;
  type?: 'primary' | 'secondary' | 'danger';
  disabled?: boolean;
  handler?: (event: MouseEvent) => Promise<boolean> | boolean;
};

type ButtonActions = (ButtonAction | null)[];
```

### Examples

```svelte
<script>
  const actions = [
    {
      label: 'Delete',
      type: 'danger',
      handler: async () => {
        const confirmed = await confirmDelete();
        if (confirmed) {
          await deleteItem();
          return true; // Close dialog
        }
        return false; // Keep dialog open
      }
    },
    null, // Separator
    {
      label: 'Save',
      type: 'primary',
      disabled: !isValid,
      handler: async () => {
        await saveData();
        return true;
      }
    }
  ];
</script>
```

## Close Confirmation

Add confirmation before closing with unsaved changes:

```svelte
<script>
  let originalData = JSON.stringify(data);
  
  const closeConfirm = async () => {
    const hasChanges = JSON.stringify(data) !== originalData;
    if (hasChanges) {
      return await window.MessageBox.showConfirm(
        'You have unsaved changes. Close anyway?',
        'Confirm Close'
      ) === ModalResult.Ok;
    }
    return true;
  };
</script>

<Dialog {closeConfirm} {/* other props */}>
  <!-- content -->
</Dialog>
```

## Modal Results

```typescript
enum ModalResult {
  Cancel = 0, // User cancelled or closed dialog
  Ok = 1      // User confirmed or completed action
}
```

### Handling Results

```svelte
<script>
  function handleDialogClose(result) {
    if (result === ModalResult.Ok) {
      console.log('User confirmed');
    } else {
      console.log('User cancelled');
    }
  }
</script>
```

## Dialog Sizing and Positioning

### Responsive Sizing

```svelte
<!-- Fixed size -->
<Dialog width="500px" height="400px">

<!-- Responsive size -->
<Dialog width="90vw" height="80vh">

<!-- Auto size with max constraints -->
<Dialog 
  width="min(800px, 90vw)" 
  height="min(600px, 80vh)"
>
```

### Custom Styling

```svelte
<Dialog 
  dialog$style="border-radius: 12px; box-shadow: 0 20px 40px rgba(0,0,0,0.3);"
  content$style="padding: 2rem; background: #f9f9f9;"
>
```

## Advanced Examples

### Form Dialog with Validation

```svelte
<!-- UserFormDialog.svelte -->
<script>
  import Dialog from '$lib/dialog';
  import FormField from '$lib/form-field';
  import TextEditor from '$lib/text-editor';
  
  export let user = { name: '', email: '' };
  export let onSave = null;
  
  let errors = {};
  
  function validate() {
    errors = {};
    if (!user.name) errors.name = 'Name is required';
    if (!user.email) errors.email = 'Email is required';
    if (user.email && !user.email.includes('@')) errors.email = 'Invalid email';
    return Object.keys(errors).length === 0;
  }
  
  const actions = [
    {
      label: 'Save User',
      type: 'primary',
      handler: async () => {
        if (!validate()) return false;
        
        try {
          await onSave?.(user);
          return true;
        } catch (error) {
          console.error('Save failed:', error);
          return false;
        }
      }
    }
  ];
</script>

<Dialog title="User Details" {actions} width="500px">
  <div style="padding: 1rem;">
    <FormField label="Name" error={errors.name}>
      <TextEditor bind:value={user.name} />
    </FormField>
    
    <FormField label="Email" error={errors.email}>
      <TextEditor bind:value={user.email} type="email" />
    </FormField>
  </div>
</Dialog>
```

### Master-Detail Dialog

```svelte
<!-- ProjectDialog.svelte -->
<script>
  import Dialog from '$lib/dialog';
  import DataTable from '$lib/data-table';
  
  export let project = { name: '', tasks: [] };
  
  let selectedTask = null;
  
  const actions = [
    {
      label: 'Add Task',
      type: 'secondary',
      handler: () => {
        project.tasks = [...project.tasks, { name: 'New Task', status: 'pending' }];
        return false; // Keep dialog open
      }
    },
    {
      label: 'Save Project',
      type: 'primary',
      handler: async () => {
        await saveProject(project);
        return true;
      }
    }
  ];
  
  const taskColumns = [
    { title: 'Task Name', field: 'name' },
    { title: 'Status', field: 'status' }
  ];
</script>

<Dialog title="Project Details" {actions} width="800px" height="600px">
  <div style="display: flex; height: 100%; gap: 1rem; padding: 1rem;">
    <!-- Project Info -->
    <div style="flex: 1;">
      <h3>Project Information</h3>
      <FormField label="Project Name">
        <TextEditor bind:value={project.name} />
      </FormField>
    </div>
    
    <!-- Tasks List -->
    <div style="flex: 2;">
      <h3>Tasks</h3>
      <DataTable 
        list={project.tasks}
        columns={taskColumns}
        bind:selectedRow={selectedTask}
      />
    </div>
  </div>
</Dialog>
```

## Styling

### CSS Variables

```css
.uniface-dialog {
  --dialog-background: white;
  --dialog-border-radius: 8px;
  --dialog-shadow: 0 10px 30px rgba(0,0,0,0.2);
  --title-bar-background: #f5f5f5;
  --title-bar-color: #333;
}
```

### Custom Dialog Styles

```scss
.custom-dialog {
  .uniface-dialog-box {
    border-radius: 12px;
    overflow: hidden;
    
    .title-bar {
      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
      color: white;
    }
    
    .dialog-content {
      background: #fafafa;
    }
  }
}
```

## Accessibility

- **ARIA Labels**: Proper labeling for screen readers
- **Keyboard Navigation**: Tab through buttons and form elements
- **Focus Management**: Auto-focus on dialog open, restore on close
- **Escape Key**: Close dialog with Escape key
- **Modal Behavior**: Trap focus within dialog

## Best Practices

### 1. Dialog Size Guidelines
- Mobile: Use `width="95vw"` for mobile-friendly dialogs
- Desktop: Prefer fixed widths like `"500px"` or `"800px"`
- Content-driven: Use `"auto"` with max-width constraints

### 2. Action Button Patterns
- Primary action on the right
- Destructive actions with `type="danger"`
- Use separators (`null`) to group related actions

### 3. Form Validation
- Validate before allowing dialog to close
- Show field-level errors
- Disable submit button when form is invalid

### 4. Data Management
- Use reactive statements to enable/disable buttons
- Implement close confirmation for forms with changes
- Pass callbacks for data persistence

### 5. Error Handling
- Handle async errors in action handlers
- Show user-friendly error messages
- Keep dialog open on save failures

## Type Definitions

```typescript
interface DialogCloseConfirm {
  (): Promise<boolean>;
}

interface ButtonAction {
  label: string;
  type?: 'primary' | 'secondary' | 'danger';
  disabled?: boolean;
  handler?: (event: MouseEvent) => Promise<boolean> | boolean;
}

type ButtonActions = (ButtonAction | null)[];

type OnClose = (result: ModalResult) => void;

interface IDialog {
  showModal: (component: any, params: any) => void;
}
```

## Migration Guide

### From v1.x to v2.x
- `DialogBoard` is now required in your app
- Global dialog API is automatically initialized
- Modal results are now enum-based instead of string-based

## Notes

- Dialogs are automatically managed by the DialogBoard component
- Multiple dialogs can be open simultaneously (stacked)
- Drag and drop functionality is enabled by default on the title bar
- The dialog system uses Svelte transitions for smooth animations
- Action button handlers should return `true` to close the dialog, `false` to keep it open