# ContextMenu Component

A powerful and accessible context menu component that provides right-click contextual actions with full keyboard navigation support. Perfect for creating rich interactive experiences with contextual commands and options.

## Features

- **Contextual Actions**: Right-click to show relevant menu options
- **Keyboard Navigation**: Full arrow key navigation and keyboard shortcuts
- **Accessibility**: ARIA attributes and screen reader support
- **Auto Positioning**: Smart positioning to stay within viewport bounds
- **Icon Support**: Optional icons for menu items
- **Disabled States**: Support for disabled menu items
- **Separators**: Visual separation between menu groups
- **Event Handling**: Focus, blur, and hide event callbacks
- **Portal Rendering**: Renders outside component hierarchy for proper layering

## Basic Usage

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

let contextMenu;

const menuItems = [
  { text: 'Copy', action: () => console.log('Copy') },
  { text: 'Paste', action: () => console.log('Paste') },
  { separator: true },
  { text: 'Delete', action: () => console.log('Delete') }
];

const handleRightClick = (event) => {
  contextMenu.show(event, menuItems);
};
</script>

<div on:contextmenu={handleRightClick}>
  Right-click me to show context menu
</div>

<ContextMenu bind:this={contextMenu} />
```

## Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `onfocus` | `((event: FocusEvent) => void) \| null` | `null` | Focus event handler |
| `onblur` | `((event: FocusEvent) => void) \| null` | `null` | Blur event handler |
| `onhide` | `(() => void) \| null` | `null` | Hide event handler |

## Methods

| Method | Signature | Description |
|--------|-----------|-------------|
| `show(event, items, width?, height?)` | Shows the context menu at the event position |
| `hide()` | Hides the context menu |

### show() Parameters

- `event`: MouseEvent - The triggering mouse event (for positioning)
- `items`: ContextMenuItem[] - Array of menu items to display
- `width`: number (optional, default: 150) - Menu width in pixels
- `height`: number (optional, default: 150) - Menu height in pixels

## ContextMenuItem Interface

```typescript
interface ContextMenuItem {
  text: string;           // Display text for the menu item
  action?: () => void;    // Action to execute when clicked
  disabled?: boolean;     // Whether the item is disabled
  separator?: boolean;    // Whether this is a separator item
  icon?: string;         // Icon class or name
  style?: string;        // Custom CSS styles
}
```

## Basic Examples

### Simple Context Menu

```svelte
<script>
let contextMenu;

const items = [
  { text: 'New File', action: () => createFile() },
  { text: 'New Folder', action: () => createFolder() },
  { separator: true },
  { text: 'Refresh', action: () => refresh() }
];

const showMenu = (event) => {
  contextMenu.show(event, items);
};
</script>

<div class="file-explorer" on:contextmenu={showMenu}>
  <p>Right-click for options</p>
</div>

<ContextMenu bind:this={contextMenu} />
```

### With Icons and Disabled Items

```svelte
<script>
let contextMenu;
let canPaste = false;

const items = [
  { 
    text: 'Cut', 
    icon: 'icon-cut',
    action: () => cut() 
  },
  { 
    text: 'Copy', 
    icon: 'icon-copy',
    action: () => copy() 
  },
  { 
    text: 'Paste', 
    icon: 'icon-paste',
    action: () => paste(),
    disabled: !canPaste 
  },
  { separator: true },
  { 
    text: 'Delete', 
    icon: 'icon-delete',
    action: () => deleteItem() 
  }
];
</script>

<div on:contextmenu={(e) => contextMenu.show(e, items)}>
  Content with edit operations
</div>

<ContextMenu bind:this={contextMenu} />
```

### Dynamic Menu Items

```svelte
<script>
let contextMenu;
let selectedItems = [];

const getMenuItems = (target) => {
  const baseItems = [
    { text: 'Properties', action: () => showProperties(target) }
  ];

  if (selectedItems.length > 0) {
    baseItems.unshift(
      { text: `Delete ${selectedItems.length} items`, action: () => deleteSelected() },
      { separator: true }
    );
  }

  if (target.type === 'file') {
    baseItems.unshift(
      { text: 'Open', action: () => openFile(target) },
      { text: 'Open with...', action: () => openWith(target) },
      { separator: true }
    );
  }

  return baseItems;
};

const handleContextMenu = (event, target) => {
  const items = getMenuItems(target);
  contextMenu.show(event, items);
};
</script>

<div class="item-list">
  {#each items as item}
    <div class="item" on:contextmenu={(e) => handleContextMenu(e, item)}>
      {item.name}
    </div>
  {/each}
</div>

<ContextMenu bind:this={contextMenu} />
```

## Event Handling

```svelte
<script>
let contextMenu;
let menuVisible = false;

const handleFocus = (event) => {
  console.log('Context menu focused');
  menuVisible = true;
};

const handleBlur = (event) => {
  console.log('Context menu blurred');
  menuVisible = false;
};

const handleHide = () => {
  console.log('Context menu hidden');
  menuVisible = false;
};

const items = [
  { text: 'Action 1', action: () => console.log('Action 1') },
  { text: 'Action 2', action: () => console.log('Action 2') }
];
</script>

<div on:contextmenu={(e) => contextMenu.show(e, items)}>
  Right-click me
</div>

<ContextMenu 
  bind:this={contextMenu}
  onfocus={handleFocus}
  onblur={handleBlur}
  onhide={handleHide}
/>

<p>Menu visible: {menuVisible}</p>
```

## Advanced Examples

### File Manager Context Menu

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

let contextMenu;
let files = [
  { name: 'document.pdf', type: 'file', selected: false },
  { name: 'images', type: 'folder', selected: false },
  { name: 'script.js', type: 'file', selected: true }
];

let clipboard = null;

const getFileMenuItems = (file) => {
  const items = [];

  if (file.type === 'file') {
    items.push(
      { text: 'Open', icon: 'icon-open', action: () => openFile(file) },
      { text: 'Open with...', action: () => openWith(file) },
      { separator: true }
    );
  }

  items.push(
    { text: 'Cut', icon: 'icon-cut', action: () => cutFile(file) },
    { text: 'Copy', icon: 'icon-copy', action: () => copyFile(file) },
    { 
      text: 'Paste', 
      icon: 'icon-paste', 
      action: () => pasteFile(),
      disabled: !clipboard 
    },
    { separator: true },
    { text: 'Rename', action: () => renameFile(file) },
    { text: 'Delete', icon: 'icon-delete', action: () => deleteFile(file) },
    { separator: true },
    { text: 'Properties', action: () => showProperties(file) }
  );

  return items;
};

const getEmptySpaceMenuItems = () => [
  { text: 'New Folder', icon: 'icon-folder-plus', action: () => createFolder() },
  { text: 'New File', icon: 'icon-file-plus', action: () => createFile() },
  { separator: true },
  { 
    text: 'Paste', 
    icon: 'icon-paste', 
    action: () => pasteFile(),
    disabled: !clipboard 
  },
  { separator: true },
  { text: 'Refresh', icon: 'icon-refresh', action: () => refresh() }
];

const handleFileContextMenu = (event, file) => {
  const items = getFileMenuItems(file);
  contextMenu.show(event, items, 200, 300);
};

const handleEmptySpaceContextMenu = (event) => {
  const items = getEmptySpaceMenuItems();
  contextMenu.show(event, items);
};

const openFile = (file) => console.log('Opening', file.name);
const openWith = (file) => console.log('Open with...', file.name);
const cutFile = (file) => { clipboard = { type: 'cut', file }; };
const copyFile = (file) => { clipboard = { type: 'copy', file }; };
const pasteFile = () => console.log('Pasting', clipboard?.file?.name);
const renameFile = (file) => console.log('Renaming', file.name);
const deleteFile = (file) => console.log('Deleting', file.name);
const createFolder = () => console.log('Creating folder');
const createFile = () => console.log('Creating file');
const refresh = () => console.log('Refreshing');
const showProperties = (file) => console.log('Properties for', file.name);
</script>

<div class="file-manager" on:contextmenu={handleEmptySpaceContextMenu}>
  <h3>File Manager</h3>
  
  <div class="file-list">
    {#each files as file}
      <div 
        class="file-item" 
        class:selected={file.selected}
        on:contextmenu|stopPropagation={(e) => handleFileContextMenu(e, file)}
      >
        <span class="file-icon {file.type === 'folder' ? 'icon-folder' : 'icon-file'}"></span>
        <span class="file-name">{file.name}</span>
      </div>
    {/each}
  </div>
</div>

<ContextMenu bind:this={contextMenu} />

<style>
  .file-manager {
    padding: 20px;
    border: 1px solid #ddd;
    border-radius: 8px;
    min-height: 300px;
    background: #f9f9f9;
  }
  
  .file-list {
    margin-top: 16px;
  }
  
  .file-item {
    display: flex;
    align-items: center;
    padding: 8px;
    margin: 4px 0;
    border-radius: 4px;
    cursor: pointer;
    transition: background 0.2s;
  }
  
  .file-item:hover {
    background: #e9e9e9;
  }
  
  .file-item.selected {
    background: #007acc;
    color: white;
  }
  
  .file-icon {
    margin-right: 8px;
    width: 16px;
    height: 16px;
  }
</style>
```

### Table Row Context Menu

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

let contextMenu;
let users = [
  { id: 1, name: 'John Doe', email: 'john@example.com', active: true },
  { id: 2, name: 'Jane Smith', email: 'jane@example.com', active: false },
  { id: 3, name: 'Bob Johnson', email: 'bob@example.com', active: true }
];

const getUserMenuItems = (user) => [
  { text: 'View Profile', icon: 'icon-user', action: () => viewProfile(user) },
  { text: 'Edit User', icon: 'icon-edit', action: () => editUser(user) },
  { separator: true },
  { 
    text: user.active ? 'Deactivate' : 'Activate', 
    icon: user.active ? 'icon-pause' : 'icon-play',
    action: () => toggleUserStatus(user) 
  },
  { text: 'Reset Password', action: () => resetPassword(user) },
  { separator: true },
  { text: 'Delete User', icon: 'icon-trash', action: () => deleteUser(user) }
];

const handleRowContextMenu = (event, user) => {
  const items = getUserMenuItems(user);
  contextMenu.show(event, items, 180, 200);
};

const viewProfile = (user) => console.log('Viewing profile for', user.name);
const editUser = (user) => console.log('Editing', user.name);
const toggleUserStatus = (user) => {
  user.active = !user.active;
  users = [...users];
  console.log(`${user.active ? 'Activated' : 'Deactivated'} ${user.name}`);
};
const resetPassword = (user) => console.log('Resetting password for', user.name);
const deleteUser = (user) => {
  users = users.filter(u => u.id !== user.id);
  console.log('Deleted', user.name);
};
</script>

<div class="user-table">
  <h3>User Management</h3>
  
  <table>
    <thead>
      <tr>
        <th>Name</th>
        <th>Email</th>
        <th>Status</th>
      </tr>
    </thead>
    <tbody>
      {#each users as user}
        <tr on:contextmenu={(e) => handleRowContextMenu(e, user)}>
          <td>{user.name}</td>
          <td>{user.email}</td>
          <td>
            <span class="status" class:active={user.active}>
              {user.active ? 'Active' : 'Inactive'}
            </span>
          </td>
        </tr>
      {/each}
    </tbody>
  </table>
</div>

<ContextMenu bind:this={contextMenu} />

<style>
  .user-table {
    padding: 20px;
  }
  
  table {
    width: 100%;
    border-collapse: collapse;
    margin-top: 16px;
  }
  
  th, td {
    text-align: left;
    padding: 12px;
    border-bottom: 1px solid #ddd;
  }
  
  th {
    background: #f5f5f5;
    font-weight: 600;
  }
  
  tr:hover {
    background: #f9f9f9;
    cursor: context-menu;
  }
  
  .status {
    padding: 4px 8px;
    border-radius: 12px;
    font-size: 12px;
    font-weight: 500;
    background: #dc3545;
    color: white;
  }
  
  .status.active {
    background: #28a745;
  }
</style>
```

## Keyboard Navigation

The ContextMenu supports full keyboard navigation:

- **Arrow Up/Down**: Navigate between menu items
- **Enter/Space**: Execute the focused menu item
- **Escape**: Close the menu
- **Tab**: Close the menu (focus moves away)

## Accessibility

The ContextMenu component includes comprehensive accessibility features:

- Proper ARIA roles (`menu`, `menuitem`, `separator`)
- ARIA attributes (`aria-label`, `aria-disabled`)
- Keyboard navigation support
- Focus management
- Screen reader compatibility
- Semantic HTML structure

### Best Practices

```svelte
<!-- Good: Clear context indication -->
<div class="editable-content" on:contextmenu={showEditMenu}>
  <!-- content -->
</div>

<!-- Good: Appropriate menu items for context -->
const editMenuItems = [
  { text: 'Cut', action: () => cut() },
  { text: 'Copy', action: () => copy() },
  { text: 'Paste', action: () => paste(), disabled: !canPaste }
];

<!-- Good: Visual feedback for disabled items -->
.menu-item.disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
```

## Browser Support

Works in all modern browsers that support:
- ES6+ JavaScript
- Modern DOM APIs
- CSS custom properties
- Portal/Teleport functionality

## Performance Considerations

- Efficient event handling with proper cleanup
- Portal rendering for optimal layering
- Minimal DOM updates with reactive changes
- Smart positioning calculations
- Automatic cleanup on component destroy