# Drawer Component

A slide-out panel component built with Svelte, providing smooth side navigation and content display with configurable positioning and animations.

## Features

- **Left/Right Positioning**: Configurable drawer position (left or right side)
- **Smooth Animations**: Fly-in transitions with customizable duration
- **Overlay Background**: Semi-transparent backdrop with click-to-close
- **Customizable Width**: Adjustable drawer width
- **Auto-Hide Management**: Intelligent visibility state management
- **Event Handling**: Click outside to close functionality
- **Responsive Design**: Adapts to different screen sizes
- **Accessibility Support**: Proper ARIA attributes
- **CSS Customization**: Themeable with CSS variables
- **Lightweight**: Minimal performance impact

## Installation

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

```typescript
import Drawer from '@ticatec/uniface-element/Drawer';
```

Or if using within the same project:
```typescript
import Drawer from '$lib/drawer';
```

## Basic Usage

```svelte
<script>
  import Drawer from '$lib/drawer';
  import Button from '$lib/button';
  
  let showDrawer = false;
  
  function openDrawer() {
    showDrawer = true;
  }
  
  function closeDrawer() {
    showDrawer = false;
  }
</script>

<Button label="Open Drawer" onClick={openDrawer} />

<Drawer bind:visible={showDrawer}>
  <div style="padding: 1rem;">
    <h2>Drawer Content</h2>
    <p>This is the drawer content area.</p>
    <Button label="Close" onClick={closeDrawer} />
  </div>
</Drawer>
```

## Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `visible` | `boolean` | `false` | Controls drawer visibility |
| `width` | `number` | `300` | Drawer width in pixels |
| `position` | `'left' \| 'right'` | `'left'` | Drawer slide-in position |

## Examples

### Basic Left Drawer

```svelte
<script>
  import Drawer from '$lib/drawer';
  
  let leftDrawerVisible = false;
</script>

<button on:click={() => leftDrawerVisible = true}>
  Open Left Drawer
</button>

<Drawer bind:visible={leftDrawerVisible}>
  <div class="drawer-content">
    <h3>Navigation Menu</h3>
    <ul>
      <li><a href="/home">Home</a></li>
      <li><a href="/about">About</a></li>
      <li><a href="/contact">Contact</a></li>
    </ul>
  </div>
</Drawer>
```

### Right Side Drawer

```svelte
<script>
  import Drawer from '$lib/drawer';
  
  let rightDrawerVisible = false;
</script>

<button on:click={() => rightDrawerVisible = true}>
  Open Right Drawer
</button>

<Drawer bind:visible={rightDrawerVisible} position="right">
  <div class="drawer-content">
    <h3>Settings Panel</h3>
    <div class="setting-item">
      <label>
        <input type="checkbox" /> Enable notifications
      </label>
    </div>
    <div class="setting-item">
      <label>
        <input type="checkbox" /> Dark mode
      </label>
    </div>
  </div>
</Drawer>
```

### Custom Width Drawer

```svelte
<script>
  import Drawer from '$lib/drawer';
  
  let wideDrawerVisible = false;
</script>

<button on:click={() => wideDrawerVisible = true}>
  Open Wide Drawer
</button>

<Drawer bind:visible={wideDrawerVisible} width={400}>
  <div class="drawer-content">
    <h3>Wide Content Panel</h3>
    <p>This drawer is wider to accommodate more content.</p>
    <div class="content-grid">
      <div class="card">Card 1</div>
      <div class="card">Card 2</div>
      <div class="card">Card 3</div>
    </div>
  </div>
</Drawer>
```

### Mobile Navigation Drawer

```svelte
<script>
  import Drawer from '$lib/drawer';
  import Icon from '$lib/icon';
  
  let mobileMenuVisible = false;
  
  const menuItems = [
    { label: 'Dashboard', icon: 'dashboard', href: '/dashboard' },
    { label: 'Projects', icon: 'folder', href: '/projects' },
    { label: 'Team', icon: 'people', href: '/team' },
    { label: 'Settings', icon: 'settings', href: '/settings' }
  ];
  
  function closeMenu() {
    mobileMenuVisible = false;
  }
</script>

<!-- Mobile header with menu button -->
<header class="mobile-header">
  <button class="menu-button" on:click={() => mobileMenuVisible = true}>
    <Icon name="menu" />
  </button>
  <h1>My App</h1>
</header>

<!-- Mobile navigation drawer -->
<Drawer bind:visible={mobileMenuVisible} width={280}>
  <nav class="mobile-nav">
    <div class="nav-header">
      <h2>Menu</h2>
      <button class="close-button" on:click={closeMenu}>
        <Icon name="close" />
      </button>
    </div>
    
    <ul class="nav-menu">
      {#each menuItems as item}
        <li>
          <a href={item.href} on:click={closeMenu}>
            <Icon name={item.icon} />
            <span>{item.label}</span>
          </a>
        </li>
      {/each}
    </ul>
    
    <div class="nav-footer">
      <div class="user-info">
        <Icon name="account_circle" />
        <span>John Doe</span>
      </div>
    </div>
  </nav>
</Drawer>

<style>
  .mobile-header {
    display: flex;
    align-items: center;
    padding: 1rem;
    background: #fff;
    border-bottom: 1px solid #e1e1e1;
  }
  
  .menu-button {
    background: none;
    border: none;
    margin-right: 1rem;
    cursor: pointer;
  }
  
  .mobile-nav {
    height: 100%;
    display: flex;
    flex-direction: column;
  }
  
  .nav-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 1rem;
    border-bottom: 1px solid #e1e1e1;
  }
  
  .nav-menu {
    flex: 1;
    list-style: none;
    padding: 0;
    margin: 0;
  }
  
  .nav-menu a {
    display: flex;
    align-items: center;
    padding: 1rem;
    text-decoration: none;
    color: #333;
    border-bottom: 1px solid #f0f0f0;
  }
  
  .nav-menu a:hover {
    background: #f5f5f5;
  }
  
  .nav-footer {
    padding: 1rem;
    border-top: 1px solid #e1e1e1;
  }
  
  .user-info {
    display: flex;
    align-items: center;
    gap: 0.5rem;
  }
</style>
```

### Filter/Search Drawer

```svelte
<script>
  import Drawer from '$lib/drawer';
  import TextEditor from '$lib/text-editor';
  import Checkbox from '$lib/checkbox';
  import Button from '$lib/button';
  
  let filterDrawerVisible = false;
  let filters = {
    searchTerm: '',
    categories: [],
    priceRange: { min: 0, max: 1000 },
    inStock: false
  };
  
  const categories = ['Electronics', 'Clothing', 'Books', 'Home & Garden'];
  
  function applyFilters() {
    console.log('Applying filters:', filters);
    filterDrawerVisible = false;
  }
  
  function resetFilters() {
    filters = {
      searchTerm: '',
      categories: [],
      priceRange: { min: 0, max: 1000 },
      inStock: false
    };
  }
</script>

<button on:click={() => filterDrawerVisible = true}>
  Show Filters
</button>

<Drawer bind:visible={filterDrawerVisible} position="right" width={350}>
  <div class="filter-panel">
    <div class="filter-header">
      <h3>Filters</h3>
      <button class="reset-button" on:click={resetFilters}>
        Reset All
      </button>
    </div>
    
    <div class="filter-section">
      <label>Search:</label>
      <TextEditor bind:value={filters.searchTerm} placeholder="Search products..." />
    </div>
    
    <div class="filter-section">
      <label>Categories:</label>
      {#each categories as category}
        <Checkbox 
          label={category}
          checked={filters.categories.includes(category)}
          onchange={(checked) => {
            if (checked) {
              filters.categories = [...filters.categories, category];
            } else {
              filters.categories = filters.categories.filter(c => c !== category);
            }
          }}
        />
      {/each}
    </div>
    
    <div class="filter-section">
      <label>Price Range:</label>
      <div class="price-inputs">
        <input type="number" bind:value={filters.priceRange.min} min="0" />
        <span>to</span>
        <input type="number" bind:value={filters.priceRange.max} min="0" />
      </div>
    </div>
    
    <div class="filter-section">
      <Checkbox 
        label="In Stock Only"
        bind:checked={filters.inStock}
      />
    </div>
    
    <div class="filter-actions">
      <Button label="Apply Filters" type="primary" onClick={applyFilters} />
    </div>
  </div>
</Drawer>

<style>
  .filter-panel {
    padding: 1rem;
    height: 100%;
    display: flex;
    flex-direction: column;
  }
  
  .filter-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 1rem;
    padding-bottom: 1rem;
    border-bottom: 1px solid #e1e1e1;
  }
  
  .filter-section {
    margin-bottom: 1.5rem;
  }
  
  .filter-section label {
    display: block;
    font-weight: 600;
    margin-bottom: 0.5rem;
  }
  
  .price-inputs {
    display: flex;
    align-items: center;
    gap: 0.5rem;
  }
  
  .price-inputs input {
    width: 80px;
    padding: 0.25rem;
    border: 1px solid #ccc;
    border-radius: 4px;
  }
  
  .filter-actions {
    margin-top: auto;
    padding-top: 1rem;
    border-top: 1px solid #e1e1e1;
  }
  
  .reset-button {
    background: none;
    border: none;
    color: #666;
    cursor: pointer;
    text-decoration: underline;
  }
</style>
```

## Animation and Transitions

The drawer uses Svelte's `fly` transition with the following behavior:

- **Slide Direction**: Based on position (left slides from left, right slides from right)
- **Duration**: 1000ms (1 second) by default
- **Opacity**: Starts at 0.5 and fades to 1.0
- **Easing**: Linear transition

### Customizing Animation

While the component doesn't expose animation props directly, you can modify the transition by editing the component or using CSS transitions:

```css
.uniface-drawer > div {
  transition: transform 0.3s ease-out;
}
```

## Interaction Patterns

### Click Outside to Close

The drawer automatically closes when clicking on the overlay background:

```svelte
<!-- This behavior is built-in -->
<Drawer bind:visible={showDrawer}>
  <!-- Clicking outside this content area will close the drawer -->
</Drawer>
```

### Prevent Close on Content Click

Content clicks are automatically prevented from bubbling to the overlay:

```svelte
<Drawer bind:visible={showDrawer}>
  <!-- Clicking inside here won't close the drawer -->
  <div>
    <button>This won't close the drawer</button>
  </div>
</Drawer>
```

### Manual Close Control

```svelte
<script>
  import Drawer from '$lib/drawer';
  
  let drawerVisible = false;
  
  function closeDrawer() {
    drawerVisible = false;
  }
  
  // Close on Escape key
  function handleKeydown(event) {
    if (event.key === 'Escape' && drawerVisible) {
      closeDrawer();
    }
  }
</script>

<svelte:window on:keydown={handleKeydown} />

<Drawer bind:visible={drawerVisible}>
  <div class="drawer-content">
    <button class="close-button" on:click={closeDrawer}>
      ✕ Close
    </button>
    <!-- Content -->
  </div>
</Drawer>
```

## Styling

### CSS Variables

The drawer can be customized using CSS variables:

```css
:root {
  --uniface-drawer-bg: #ffffff;
  --uniface-drawer-shadow: rgba(0, 0, 0, 0.16) 0 3px 6px, rgba(0, 0, 0, 0.23) 0 3px 6px;
  --uniface-drawer-border-color: #e1e1e1;
}
```

### Custom Styling

```css
/* Dark theme drawer */
.dark-drawer {
  --uniface-drawer-bg: #2a2a2a;
  --uniface-drawer-border-color: #444;
  --uniface-drawer-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
  color: white;
}

/* Rounded drawer */
.rounded-drawer .uniface-drawer > div {
  border-radius: 0 12px 12px 0;
}

.rounded-drawer .uniface-drawer > div.right {
  border-radius: 12px 0 0 12px;
}

/* Custom overlay */
.custom-overlay .uniface-drawer {
  background-color: rgba(0, 0, 0, 0.7);
  backdrop-filter: blur(4px);
}
```

### Responsive Design

```scss
.drawer-content {
  padding: 1rem;
  
  @media (max-width: 768px) {
    padding: 0.5rem;
  }
}

/* Full-width drawer on mobile */
@media (max-width: 480px) {
  .uniface-drawer > div {
    width: 100% !important;
  }
}
```

## Accessibility

- **ARIA Attributes**: The drawer includes appropriate `aria-hidden` attributes
- **Focus Management**: Consider adding focus trapping for better accessibility
- **Keyboard Support**: Implement Escape key handling for closing
- **Screen Reader Support**: Add descriptive labels and roles

### Enhanced Accessibility Example

```svelte
<script>
  import Drawer from '$lib/drawer';
  
  let drawerVisible = false;
  let drawerContent;
  
  function openDrawer() {
    drawerVisible = true;
    // Focus first interactive element when opened
    setTimeout(() => {
      const firstButton = drawerContent?.querySelector('button, a, input, select, textarea');
      firstButton?.focus();
    }, 100);
  }
  
  function handleKeydown(event) {
    if (event.key === 'Escape' && drawerVisible) {
      drawerVisible = false;
    }
  }
</script>

<svelte:window on:keydown={handleKeydown} />

<button on:click={openDrawer} aria-label="Open navigation menu">
  Open Menu
</button>

<Drawer bind:visible={drawerVisible}>
  <nav bind:this={drawerContent} aria-label="Main navigation" role="navigation">
    <h2 id="drawer-title">Navigation Menu</h2>
    <!-- Content with proper focus management -->
  </nav>
</Drawer>
```

## Best Practices

### 1. Content Organization
- Keep drawer content focused and organized
- Use clear headings and sections
- Limit content to essential items

### 2. Width Guidelines
- **Mobile**: Use 80-90% of screen width or full width
- **Tablet**: 300-400px is typically appropriate
- **Desktop**: 250-350px for navigation, up to 500px for detailed content

### 3. Performance
- Avoid heavy content in drawers that open frequently
- Use lazy loading for complex drawer content
- Consider virtualization for long lists

### 4. User Experience
- Provide clear close buttons or instructions
- Use consistent positioning across your application
- Ensure touch-friendly targets on mobile devices

## Common Use Cases

### Navigation Drawer
```svelte
<!-- Mobile-first navigation -->
<Drawer bind:visible={navOpen} width={280}>
  <nav>
    <ul>
      <li><a href="/">Home</a></li>
      <li><a href="/products">Products</a></li>
      <li><a href="/contact">Contact</a></li>
    </ul>
  </nav>
</Drawer>
```

### Settings Panel
```svelte
<!-- Right-side settings -->
<Drawer bind:visible={settingsOpen} position="right" width={400}>
  <div class="settings-panel">
    <!-- Settings form content -->
  </div>
</Drawer>
```

### Filter/Search Panel
```svelte
<!-- Filter controls -->
<Drawer bind:visible={filtersOpen} position="right" width={350}>
  <div class="filters">
    <!-- Filter controls -->
  </div>
</Drawer>
```

### Shopping Cart
```svelte
<!-- Shopping cart drawer -->
<Drawer bind:visible={cartOpen} position="right" width={400}>
  <div class="cart">
    <!-- Cart items and checkout -->
  </div>
</Drawer>
```

## Notes

- The drawer uses fixed positioning and appears above all other content
- The overlay background has a z-index of 100
- Content inside the drawer is scrollable if it exceeds the viewport height
- The drawer automatically handles show/hide state management
- Click outside behavior is built-in and cannot be disabled