# useCustomCommand - Exemplos Práticos

> 🎯 **Comandos temporários que existem apenas enquanto o componente está montado**

O `useCustomCommand` é o hook principal para criar comandos contextuais que aparecem automaticamente no Command Palette (Ctrl+Shift+P) e desaparecem quando o componente é desmontado.

## 📋 Índice

1. [Modal com Comandos](#modal-com-comandos)
2. [Editor de Texto](#editor-de-texto)
3. [Formulário com Ações](#formulário-com-ações)
4. [Lista com Ações Contextuais](#lista-com-ações-contextuais)
5. [Player de Mídia](#player-de-mídia)
6. [Dashboard com Widgets](#dashboard-com-widgets)
7. [Tabela de Dados](#tabela-de-dados)
8. [Integração com Rotas](#integração-com-rotas)

---

## Modal com Comandos

```tsx
import { useState } from 'react'
import { useCustomCommand } from '@darksnow-ui/commander'

function UserProfileModal({ user, isOpen, onClose }) {
  const [isEditing, setIsEditing] = useState(false)
  const [formData, setFormData] = useState(user)

  // Comando para fechar o modal (ESC)
  useCustomCommand({
    key: `modal:close:${user.id}`,
    label: 'Fechar Modal',
    icon: '❌',
    shortcut: 'escape',
    handle: async () => {
      onClose()
    }
  })

  // Comando para editar/salvar
  const saveCommand = useCustomCommand({
    key: `user:save:${user.id}`,
    label: isEditing ? 'Salvar Alterações' : 'Editar Perfil',
    icon: isEditing ? '💾' : '✏️',
    shortcut: isEditing ? 'ctrl+s' : 'ctrl+e',
    category: 'user',
    when: () => isOpen, // Só disponível quando modal está aberto
    handle: async () => {
      if (isEditing) {
        await api.updateUser(user.id, formData)
        setIsEditing(false)
        toast.success('Perfil atualizado!')
      } else {
        setIsEditing(true)
      }
    }
  })

  // Comando para deletar usuário
  useCustomCommand({
    key: `user:delete:${user.id}`,
    label: 'Deletar Usuário',
    icon: '🗑️',
    category: 'user',
    tags: ['danger', 'delete'],
    priority: -1, // Baixa prioridade na busca
    when: () => isOpen && user.role !== 'admin',
    handle: async () => {
      if (confirm('Tem certeza?')) {
        await api.deleteUser(user.id)
        onClose()
      }
    }
  })

  // Comando para enviar mensagem
  useCustomCommand({
    key: `user:message:${user.id}`,
    label: `Enviar mensagem para ${user.name}`,
    icon: '💬',
    shortcut: 'ctrl+m',
    category: 'communication',
    handle: async () => {
      openMessageComposer(user)
    }
  })

  if (!isOpen) return null

  return (
    <Modal onClose={onClose}>
      {/* UI do modal */}
    </Modal>
  )
}
```

---

## Editor de Texto

```tsx
import { useCustomCommand, useAction } from '@darksnow-ui/commander'

function RichTextEditor({ documentId, initialContent, onSave }) {
  const [content, setContent] = useState(initialContent)
  const [isDirty, setIsDirty] = useState(false)
  const [selectedText, setSelectedText] = useState('')
  const [undoStack, setUndoStack] = useState([])
  const [redoStack, setRedoStack] = useState([])

  // Comando de salvar
  const saveCommand = useCustomCommand({
    key: `doc:save:${documentId}`,
    label: 'Salvar Documento',
    icon: '💾',
    shortcut: 'ctrl+s',
    category: 'file',
    when: () => isDirty, // Só aparece quando há mudanças
    handle: async () => {
      const result = await onSave(content)
      setIsDirty(false)
      return result
    }
  })

  // Comandos de formatação
  useCustomCommand({
    key: `format:bold:${documentId}`,
    label: 'Negrito',
    icon: '🅱️',
    shortcut: 'ctrl+b',
    category: 'format',
    when: () => selectedText.length > 0,
    handle: async () => {
      document.execCommand('bold')
    }
  })

  useCustomCommand({
    key: `format:italic:${documentId}`,
    label: 'Itálico',
    icon: '𝐼',
    shortcut: 'ctrl+i',
    category: 'format',
    when: () => selectedText.length > 0,
    handle: async () => {
      document.execCommand('italic')
    }
  })

  // Comandos de edição
  useAction(
    `edit:undo:${documentId}`,
    'Desfazer',
    () => {
      if (undoStack.length > 0) {
        const previous = undoStack[undoStack.length - 1]
        setRedoStack([...redoStack, content])
        setContent(previous)
        setUndoStack(undoStack.slice(0, -1))
      }
    },
    {
      shortcut: 'ctrl+z',
      icon: '↩️',
      when: () => undoStack.length > 0
    }
  )

  useAction(
    `edit:redo:${documentId}`,
    'Refazer',
    () => {
      if (redoStack.length > 0) {
        const next = redoStack[redoStack.length - 1]
        setUndoStack([...undoStack, content])
        setContent(next)
        setRedoStack(redoStack.slice(0, -1))
      }
    },
    {
      shortcut: 'ctrl+y',
      icon: '↪️',
      when: () => redoStack.length > 0
    }
  )

  // Comandos avançados
  useCustomCommand({
    key: `edit:find:${documentId}`,
    label: 'Buscar e Substituir',
    icon: '🔍',
    shortcut: 'ctrl+f',
    category: 'edit',
    handle: async () => {
      const searchTerm = prompt('Buscar por:')
      if (searchTerm) {
        const replaceTerm = prompt('Substituir por:')
        if (replaceTerm !== null) {
          const newContent = content.replaceAll(searchTerm, replaceTerm)
          setContent(newContent)
          setIsDirty(true)
          return { replaced: content.split(searchTerm).length - 1 }
        }
      }
    }
  })

  // Comando de exportação
  useCustomCommand({
    key: `export:pdf:${documentId}`,
    label: 'Exportar como PDF',
    icon: '📄',
    shortcut: 'ctrl+shift+e',
    category: 'file',
    tags: ['export', 'pdf', 'download'],
    handle: async () => {
      const blob = await generatePDF(content)
      downloadBlob(blob, `document-${documentId}.pdf`)
    }
  })

  return (
    <div className="editor">
      <div className="toolbar">
        <button onClick={() => saveCommand.invoke()}>
          Salvar {isDirty && '*'}
        </button>
      </div>
      <textarea
        value={content}
        onChange={(e) => {
          setContent(e.target.value)
          setIsDirty(true)
          setUndoStack([...undoStack, content].slice(-50)) // Max 50 undos
        }}
        onSelect={(e) => {
          const target = e.target as HTMLTextAreaElement
          setSelectedText(
            target.value.substring(target.selectionStart, target.selectionEnd)
          )
        }}
      />
    </div>
  )
}
```

---

## Formulário com Ações

```tsx
import { useCustomCommand, useToggleCommand } from '@darksnow-ui/commander'

function ContactForm() {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    message: ''
  })
  const [isSubmitting, setIsSubmitting] = useState(false)
  const [autoSave, setAutoSave] = useState(true)

  // Toggle de auto-save
  useToggleCommand(
    'form:autosave',
    'Auto-save',
    autoSave,
    setAutoSave,
    {
      icon: autoSave ? '✅' : '❌',
      category: 'settings'
    }
  )

  // Comando para limpar formulário
  useCustomCommand({
    key: 'form:clear',
    label: 'Limpar Formulário',
    icon: '🧹',
    shortcut: 'ctrl+shift+delete',
    category: 'form',
    when: () => Object.values(formData).some(v => v !== ''),
    handle: async () => {
      if (confirm('Limpar todos os campos?')) {
        setFormData({ name: '', email: '', message: '' })
      }
    }
  })

  // Comando para preencher com dados de teste
  useCustomCommand({
    key: 'form:fill-test',
    label: 'Preencher com Dados de Teste',
    icon: '🧪',
    category: 'debug',
    tags: ['test', 'development'],
    when: () => process.env.NODE_ENV === 'development',
    handle: async () => {
      setFormData({
        name: 'João Silva',
        email: 'joao@example.com',
        message: 'Mensagem de teste para desenvolvimento'
      })
    }
  })

  // Comando para enviar
  const submitCommand = useCustomCommand({
    key: 'form:submit',
    label: 'Enviar Formulário',
    icon: '📤',
    shortcut: 'ctrl+enter',
    category: 'form',
    when: () => formData.name && formData.email && formData.message && !isSubmitting,
    handle: async () => {
      setIsSubmitting(true)
      try {
        await api.submitContact(formData)
        toast.success('Mensagem enviada!')
        setFormData({ name: '', email: '', message: '' })
      } catch (error) {
        toast.error('Erro ao enviar')
      } finally {
        setIsSubmitting(false)
      }
    }
  })

  // Auto-save com debounce
  useEffect(() => {
    if (!autoSave) return

    const timer = setTimeout(() => {
      if (Object.values(formData).some(v => v !== '')) {
        localStorage.setItem('contact-form-draft', JSON.stringify(formData))
      }
    }, 1000)

    return () => clearTimeout(timer)
  }, [formData, autoSave])

  return (
    <form onSubmit={(e) => {
      e.preventDefault()
      submitCommand.invoke()
    }}>
      {/* Campos do formulário */}
    </form>
  )
}
```

---

## Lista com Ações Contextuais

```tsx
import { useContextualCommands, useCustomCommand } from '@darksnow-ui/commander'

function TaskList({ projectId }) {
  const [tasks, setTasks] = useState([])
  const [selectedTasks, setSelectedTasks] = useState([])
  const [filter, setFilter] = useState('all')

  // Comandos para cada task individual
  useContextualCommands(
    tasks,
    (task) => ({
      key: `task:toggle:${task.id}`,
      label: task.completed ? `Reabrir: ${task.title}` : `Completar: ${task.title}`,
      icon: task.completed ? '↩️' : '✅',
      category: 'task',
      tags: ['task', task.priority],
      priority: task.priority === 'high' ? 10 : 5,
      handle: async () => {
        await api.updateTask(task.id, { completed: !task.completed })
        setTasks(tasks.map(t => 
          t.id === task.id ? { ...t, completed: !t.completed } : t
        ))
      }
    })
  )

  // Comandos para seleção múltipla
  useCustomCommand({
    key: 'tasks:select-all',
    label: 'Selecionar Todas',
    icon: '☑️',
    shortcut: 'ctrl+a',
    category: 'selection',
    when: () => tasks.length > 0,
    handle: async () => {
      setSelectedTasks(tasks.map(t => t.id))
    }
  })

  useCustomCommand({
    key: 'tasks:complete-selected',
    label: `Completar ${selectedTasks.length} tarefas`,
    icon: '✅',
    category: 'bulk',
    when: () => selectedTasks.length > 0,
    handle: async () => {
      await api.bulkUpdate(selectedTasks, { completed: true })
      setTasks(tasks.map(t => 
        selectedTasks.includes(t.id) ? { ...t, completed: true } : t
      ))
      setSelectedTasks([])
    }
  })

  // Comandos de filtro
  useCustomCommand({
    key: 'filter:active',
    label: 'Mostrar Apenas Ativas',
    icon: '🔵',
    shortcut: 'alt+1',
    category: 'view',
    when: () => filter !== 'active',
    handle: async () => setFilter('active')
  })

  useCustomCommand({
    key: 'filter:completed',
    label: 'Mostrar Apenas Completas',
    icon: '🟢',
    shortcut: 'alt+2',
    category: 'view',
    when: () => filter !== 'completed',
    handle: async () => setFilter('completed')
  })

  // Comando para adicionar nova task
  useCustomCommand({
    key: 'task:add',
    label: 'Nova Tarefa',
    icon: '➕',
    shortcut: 'ctrl+n',
    category: 'task',
    handle: async () => {
      const title = prompt('Título da tarefa:')
      if (title) {
        const newTask = await api.createTask({ projectId, title })
        setTasks([...tasks, newTask])
      }
    }
  })

  const filteredTasks = tasks.filter(task => {
    if (filter === 'active') return !task.completed
    if (filter === 'completed') return task.completed
    return true
  })

  return (
    <div>
      <div className="filters">
        <button onClick={() => setFilter('all')}>Todas</button>
        <button onClick={() => setFilter('active')}>Ativas</button>
        <button onClick={() => setFilter('completed')}>Completas</button>
      </div>
      
      {filteredTasks.map(task => (
        <TaskItem
          key={task.id}
          task={task}
          isSelected={selectedTasks.includes(task.id)}
          onToggleSelect={() => {
            setSelectedTasks(
              selectedTasks.includes(task.id)
                ? selectedTasks.filter(id => id !== task.id)
                : [...selectedTasks, task.id]
            )
          }}
        />
      ))}
    </div>
  )
}
```

---

## Player de Mídia

```tsx
import { useCustomCommand, useAction } from '@darksnow-ui/commander'

function VideoPlayer({ video }) {
  const videoRef = useRef(null)
  const [isPlaying, setIsPlaying] = useState(false)
  const [volume, setVolume] = useState(1)
  const [playbackRate, setPlaybackRate] = useState(1)
  const [currentTime, setCurrentTime] = useState(0)

  // Play/Pause
  useCustomCommand({
    key: `video:playpause:${video.id}`,
    label: isPlaying ? 'Pausar' : 'Reproduzir',
    icon: isPlaying ? '⏸️' : '▶️',
    shortcut: 'space',
    category: 'playback',
    handle: async () => {
      if (isPlaying) {
        videoRef.current?.pause()
      } else {
        videoRef.current?.play()
      }
      setIsPlaying(!isPlaying)
    }
  })

  // Controles de velocidade
  const speeds = [0.5, 0.75, 1, 1.25, 1.5, 2]
  speeds.forEach(speed => {
    useAction(
      `video:speed:${speed}:${video.id}`,
      `Velocidade ${speed}x`,
      () => {
        if (videoRef.current) {
          videoRef.current.playbackRate = speed
          setPlaybackRate(speed)
        }
      },
      {
        category: 'playback',
        icon: '⚡',
        when: () => playbackRate !== speed
      }
    )
  })

  // Volume
  useCustomCommand({
    key: `video:mute:${video.id}`,
    label: volume > 0 ? 'Silenciar' : 'Ativar Som',
    icon: volume > 0 ? '🔇' : '🔊',
    shortcut: 'm',
    category: 'audio',
    handle: async () => {
      if (videoRef.current) {
        const newVolume = volume > 0 ? 0 : 1
        videoRef.current.volume = newVolume
        setVolume(newVolume)
      }
    }
  })

  // Navegação
  useAction(
    `video:skip-forward:${video.id}`,
    'Avançar 10s',
    () => {
      if (videoRef.current) {
        videoRef.current.currentTime += 10
      }
    },
    {
      shortcut: 'right',
      icon: '⏩',
      category: 'navigation'
    }
  )

  useAction(
    `video:skip-backward:${video.id}`,
    'Voltar 10s',
    () => {
      if (videoRef.current) {
        videoRef.current.currentTime -= 10
      }
    },
    {
      shortcut: 'left',
      icon: '⏪',
      category: 'navigation'
    }
  )

  // Fullscreen
  useCustomCommand({
    key: `video:fullscreen:${video.id}`,
    label: 'Tela Cheia',
    icon: '🖥️',
    shortcut: 'f',
    category: 'view',
    handle: async () => {
      if (videoRef.current) {
        if (document.fullscreenElement) {
          document.exitFullscreen()
        } else {
          videoRef.current.requestFullscreen()
        }
      }
    }
  })

  // Screenshot
  useCustomCommand({
    key: `video:screenshot:${video.id}`,
    label: 'Capturar Tela',
    icon: '📸',
    shortcut: 's',
    category: 'tools',
    handle: async () => {
      const canvas = document.createElement('canvas')
      canvas.width = videoRef.current.videoWidth
      canvas.height = videoRef.current.videoHeight
      const ctx = canvas.getContext('2d')
      ctx.drawImage(videoRef.current, 0, 0)
      
      canvas.toBlob((blob) => {
        const url = URL.createObjectURL(blob)
        const a = document.createElement('a')
        a.href = url
        a.download = `screenshot-${video.id}-${Date.now()}.png`
        a.click()
      })
    }
  })

  return (
    <div className="video-player">
      <video
        ref={videoRef}
        src={video.url}
        onTimeUpdate={(e) => setCurrentTime(e.currentTarget.currentTime)}
      />
      {/* Controles do player */}
    </div>
  )
}
```

---

## Dashboard com Widgets

```tsx
import { useCustomCommand, useModalCommand } from '@darksnow-ui/commander'

function Dashboard() {
  const [widgets, setWidgets] = useState([])
  const [layout, setLayout] = useState('grid')
  const [refreshInterval, setRefreshInterval] = useState(30000)

  // Comando para adicionar widget
  const addWidgetCommand = useModalCommand(
    'dashboard:add-widget',
    'Adicionar Widget',
    async () => {
      const widgetType = await showWidgetPicker()
      if (widgetType) {
        const newWidget = await createWidget(widgetType)
        setWidgets([...widgets, newWidget])
        return newWidget
      }
    },
    {
      icon: '➕',
      shortcut: 'ctrl+shift+w',
      category: 'dashboard'
    }
  )

  // Comandos para cada widget
  widgets.forEach(widget => {
    // Refresh individual
    useCustomCommand({
      key: `widget:refresh:${widget.id}`,
      label: `Atualizar: ${widget.title}`,
      icon: '🔄',
      category: 'widget',
      tags: ['refresh', widget.type],
      handle: async () => {
        await widget.refresh()
        toast.success(`${widget.title} atualizado`)
      }
    })

    // Configurar widget
    useModalCommand(
      `widget:config:${widget.id}`,
      `Configurar: ${widget.title}`,
      async () => {
        const config = await showWidgetConfig(widget)
        if (config) {
          await updateWidget(widget.id, config)
          setWidgets(widgets.map(w => 
            w.id === widget.id ? { ...w, ...config } : w
          ))
        }
      },
      {
        icon: '⚙️',
        category: 'widget'
      }
    )

    // Remover widget
    useCustomCommand({
      key: `widget:remove:${widget.id}`,
      label: `Remover: ${widget.title}`,
      icon: '🗑️',
      category: 'widget',
      priority: -1,
      handle: async () => {
        if (confirm(`Remover ${widget.title}?`)) {
          setWidgets(widgets.filter(w => w.id !== widget.id))
        }
      }
    })
  })

  // Comandos de layout
  useCustomCommand({
    key: 'dashboard:layout:grid',
    label: 'Layout em Grade',
    icon: '⚏',
    category: 'view',
    when: () => layout !== 'grid',
    handle: async () => setLayout('grid')
  })

  useCustomCommand({
    key: 'dashboard:layout:list',
    label: 'Layout em Lista',
    icon: '☰',
    category: 'view',
    when: () => layout !== 'list',
    handle: async () => setLayout('list')
  })

  // Refresh global
  useCustomCommand({
    key: 'dashboard:refresh-all',
    label: 'Atualizar Todos os Widgets',
    icon: '🔄',
    shortcut: 'ctrl+r',
    category: 'dashboard',
    handle: async () => {
      await Promise.all(widgets.map(w => w.refresh()))
      toast.success('Dashboard atualizado')
    }
  })

  // Auto-refresh toggle
  useToggleCommand(
    'dashboard:auto-refresh',
    'Auto-refresh',
    refreshInterval > 0,
    (enabled) => setRefreshInterval(enabled ? 30000 : 0),
    {
      category: 'settings',
      icon: '⏱️'
    }
  )

  // Exportar dashboard
  useCustomCommand({
    key: 'dashboard:export',
    label: 'Exportar Dashboard',
    icon: '📊',
    shortcut: 'ctrl+e',
    category: 'dashboard',
    tags: ['export', 'download'],
    handle: async () => {
      const format = await showExportOptions()
      if (format) {
        const data = await exportDashboard(widgets, format)
        downloadFile(data, `dashboard-${Date.now()}.${format}`)
      }
    }
  })

  return (
    <div className={`dashboard layout-${layout}`}>
      <button onClick={() => addWidgetCommand.invoke()}>
        Add Widget
      </button>
      
      {widgets.map(widget => (
        <Widget key={widget.id} {...widget} />
      ))}
    </div>
  )
}
```

---

## Tabela de Dados

```tsx
import { useCustomCommand, useContextualCommands } from '@darksnow-ui/commander'

function DataTable({ data, columns, onUpdate }) {
  const [selectedRows, setSelectedRows] = useState([])
  const [sortConfig, setSortConfig] = useState(null)
  const [filters, setFilters] = useState({})
  const [editingCell, setEditingCell] = useState(null)

  // Comandos para linhas selecionadas
  useCustomCommand({
    key: 'table:export-selected',
    label: `Exportar ${selectedRows.length} linhas`,
    icon: '📥',
    shortcut: 'ctrl+shift+e',
    category: 'table',
    when: () => selectedRows.length > 0,
    handle: async () => {
      const selectedData = data.filter(row => selectedRows.includes(row.id))
      const csv = convertToCSV(selectedData)
      downloadFile(csv, 'export.csv')
    }
  })

  useCustomCommand({
    key: 'table:delete-selected',
    label: `Deletar ${selectedRows.length} linhas`,
    icon: '🗑️',
    shortcut: 'delete',
    category: 'table',
    when: () => selectedRows.length > 0,
    priority: -1,
    handle: async () => {
      if (confirm(`Deletar ${selectedRows.length} linhas?`)) {
        await onUpdate('delete', selectedRows)
        setSelectedRows([])
      }
    }
  })

  // Comandos de ordenação para cada coluna
  columns.forEach(column => {
    if (column.sortable) {
      useCustomCommand({
        key: `sort:${column.key}:asc`,
        label: `Ordenar por ${column.label} (A-Z)`,
        icon: '⬆️',
        category: 'sort',
        when: () => sortConfig?.key !== column.key || sortConfig?.direction !== 'asc',
        handle: async () => {
          setSortConfig({ key: column.key, direction: 'asc' })
        }
      })

      useCustomCommand({
        key: `sort:${column.key}:desc`,
        label: `Ordenar por ${column.label} (Z-A)`,
        icon: '⬇️',
        category: 'sort',
        when: () => sortConfig?.key !== column.key || sortConfig?.direction !== 'desc',
        handle: async () => {
          setSortConfig({ key: column.key, direction: 'desc' })
        }
      })
    }
  })

  // Comandos contextuais para cada linha
  useContextualCommands(
    data,
    (row) => ({
      key: `row:edit:${row.id}`,
      label: `Editar: ${row.name || row.title || row.id}`,
      icon: '✏️',
      category: 'row',
      handle: async () => {
        const updatedRow = await showRowEditor(row)
        if (updatedRow) {
          await onUpdate('update', row.id, updatedRow)
        }
      }
    })
  )

  // Comandos de filtro
  useCustomCommand({
    key: 'table:clear-filters',
    label: 'Limpar Filtros',
    icon: '🧹',
    category: 'filter',
    when: () => Object.keys(filters).length > 0,
    handle: async () => {
      setFilters({})
    }
  })

  // Comando de busca global
  useCustomCommand({
    key: 'table:search',
    label: 'Buscar na Tabela',
    icon: '🔍',
    shortcut: 'ctrl+f',
    category: 'table',
    handle: async () => {
      const searchTerm = prompt('Buscar por:')
      if (searchTerm) {
        setFilters({ ...filters, global: searchTerm })
      }
    }
  })

  // Copiar dados selecionados
  useCustomCommand({
    key: 'table:copy-selected',
    label: 'Copiar Seleção',
    icon: '📋',
    shortcut: 'ctrl+c',
    category: 'table',
    when: () => selectedRows.length > 0,
    handle: async () => {
      const selectedData = data.filter(row => selectedRows.includes(row.id))
      const text = selectedData.map(row => 
        columns.map(col => row[col.key]).join('\t')
      ).join('\n')
      
      await navigator.clipboard.writeText(text)
      toast.success('Copiado para área de transferência')
    }
  })

  const sortedAndFilteredData = useMemo(() => {
    let result = [...data]
    
    // Apply filters
    Object.entries(filters).forEach(([key, value]) => {
      if (key === 'global') {
        result = result.filter(row => 
          Object.values(row).some(v => 
            String(v).toLowerCase().includes(value.toLowerCase())
          )
        )
      } else {
        result = result.filter(row => 
          String(row[key]).toLowerCase().includes(value.toLowerCase())
        )
      }
    })
    
    // Apply sorting
    if (sortConfig) {
      result.sort((a, b) => {
        const aVal = a[sortConfig.key]
        const bVal = b[sortConfig.key]
        
        if (sortConfig.direction === 'asc') {
          return aVal > bVal ? 1 : -1
        } else {
          return aVal < bVal ? 1 : -1
        }
      })
    }
    
    return result
  }, [data, filters, sortConfig])

  return (
    <div className="data-table">
      <table>
        <thead>
          <tr>
            {columns.map(column => (
              <th key={column.key}>
                {column.label}
                {column.sortable && (
                  <button onClick={() => {
                    const newDir = sortConfig?.key === column.key && 
                                 sortConfig?.direction === 'asc' ? 'desc' : 'asc'
                    setSortConfig({ key: column.key, direction: newDir })
                  }}>
                    {sortConfig?.key === column.key ? 
                      (sortConfig.direction === 'asc' ? '⬆️' : '⬇️') : '↕️'
                    }
                  </button>
                )}
              </th>
            ))}
          </tr>
        </thead>
        <tbody>
          {sortedAndFilteredData.map(row => (
            <tr 
              key={row.id}
              className={selectedRows.includes(row.id) ? 'selected' : ''}
              onClick={() => {
                setSelectedRows(
                  selectedRows.includes(row.id) ?
                    selectedRows.filter(id => id !== row.id) :
                    [...selectedRows, row.id]
                )
              }}
            >
              {columns.map(column => (
                <td key={column.key}>
                  {row[column.key]}
                </td>
              ))}
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  )
}
```

---

## Integração com Rotas

```tsx
import { useNavigationCommand, useCustomCommand } from '@darksnow-ui/commander'
import { useRouter, useParams } from 'next/router'

function ProductPage() {
  const router = useRouter()
  const { productId } = useParams()
  const [product, setProduct] = useState(null)
  const [relatedProducts, setRelatedProducts] = useState([])

  // Navegação entre produtos
  useNavigationCommand(
    'nav:products',
    'Voltar para Produtos',
    '/products',
    router.push,
    {
      icon: '🏪',
      shortcut: 'alt+p'
    }
  )

  // Navegação para produtos relacionados
  relatedProducts.forEach(related => {
    useNavigationCommand(
      `nav:product:${related.id}`,
      `Ver: ${related.name}`,
      `/products/${related.id}`,
      router.push,
      {
        icon: '🔗',
        category: 'related',
        tags: ['product', related.category]
      }
    )
  })

  // Ações do produto
  useCustomCommand({
    key: `product:share:${productId}`,
    label: 'Compartilhar Produto',
    icon: '🔗',
    shortcut: 'ctrl+shift+s',
    category: 'product',
    handle: async () => {
      const url = `${window.location.origin}/products/${productId}`
      
      if (navigator.share) {
        await navigator.share({
          title: product.name,
          text: product.description,
          url
        })
      } else {
        await navigator.clipboard.writeText(url)
        toast.success('Link copiado!')
      }
    }
  })

  // Adicionar ao carrinho
  const addToCartCommand = useCustomCommand({
    key: `product:cart:${productId}`,
    label: 'Adicionar ao Carrinho',
    icon: '🛒',
    shortcut: 'ctrl+enter',
    category: 'product',
    priority: 10,
    when: () => product?.inStock,
    handle: async () => {
      await addToCart(productId)
      toast.success('Adicionado ao carrinho!')
    }
  })

  // Admin commands
  const isAdmin = useIsAdmin()
  
  useCustomCommand({
    key: `product:edit:${productId}`,
    label: 'Editar Produto',
    icon: '✏️',
    category: 'admin',
    when: () => isAdmin,
    handle: async () => {
      router.push(`/admin/products/${productId}/edit`)
    }
  })

  useCustomCommand({
    key: `product:analytics:${productId}`,
    label: 'Ver Analytics',
    icon: '📊',
    category: 'admin',
    when: () => isAdmin,
    handle: async () => {
      const analytics = await fetchProductAnalytics(productId)
      showAnalyticsModal(analytics)
    }
  })

  return (
    <div>
      {/* UI do produto */}
      <button onClick={() => addToCartCommand.invoke()}>
        Adicionar ao Carrinho
      </button>
    </div>
  )
}
```

---

## 💡 Dicas e Melhores Práticas

### 1. **Use IDs únicos nas keys**
```tsx
// ✅ Bom - ID único por instância
useCustomCommand({
  key: `modal:save:${modalId}`,
  // ...
})

// ❌ Evite - Pode causar conflitos
useCustomCommand({
  key: 'modal:save',
  // ...
})
```

### 2. **Aproveite a função `when`**
```tsx
// Comando só aparece quando relevante
useCustomCommand({
  key: 'form:submit',
  label: 'Enviar',
  when: () => isFormValid && !isSubmitting,
  handle: async () => { /* ... */ }
})
```

### 3. **Use categorias para organização**
```tsx
// Agrupe comandos relacionados
category: 'file'    // Operações de arquivo
category: 'edit'    // Edição
category: 'view'    // Visualização
category: 'tools'   // Ferramentas
category: 'debug'   // Desenvolvimento
```

### 4. **Retorne valores úteis**
```tsx
// Retorne informações sobre a operação
handle: async () => {
  const result = await saveFile()
  return {
    success: true,
    fileSize: result.size,
    savedAt: new Date()
  }
}
```

### 5. **Use os hooks especializados**
```tsx
// Para ações simples
useAction('toggle:sidebar', 'Toggle Sidebar', () => {
  setSidebarOpen(!sidebarOpen)
})

// Para toggles
useToggleCommand('dark:mode', 'Dark Mode', isDark, setIsDark)

// Para modais
useModalCommand('user:edit', 'Edit User', async () => {
  return await showUserEditModal()
})
```

### 6. **Integre com o estado do componente**
```tsx
// Comandos que refletem o estado atual
const [filter, setFilter] = useState('all')

['all', 'active', 'completed'].forEach(filterType => {
  useCustomCommand({
    key: `filter:${filterType}`,
    label: `Show ${filterType}`,
    when: () => filter !== filterType,
    handle: async () => setFilter(filterType)
  })
})
```

---

## 🎯 Conclusão

O `useCustomCommand` transforma qualquer componente em uma interface poderosa e acessível. Os comandos aparecem automaticamente no Command Palette, permitindo que usuários avançados naveguem e controlem sua aplicação com eficiência.

**Lembre-se**: Os comandos são temporários e existem apenas enquanto o componente está montado, garantindo que o Command Palette sempre reflita o contexto atual da aplicação.