npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@leve.ai/chat

v1.0.35

Published

Sistema de chat multiplataforma com suporte a WebSocket para Web e React Native

Readme

@leve.ai/chat

Sistema de chat multiplataforma com suporte a WebSocket para Web e React Native.

📦 Instalação

npm install @leve.ai/chat @leve.ai/socket-client
# ou
yarn add @leve.ai/chat @leve.ai/socket-client
# ou
pnpm add @leve.ai/chat @leve.ai/socket-client

🚀 Uso

Web (React, Next.js, Vite, etc.)

import { ChatWidget } from '@leve.ai/chat/web'
import { ChatProvider } from '@leve.ai/chat/shared'
// O CSS é importado automaticamente!

function App() {
  return (
    <ChatProvider
      user={{ id: 'user123', name: 'João' }}
      socketUrl="https://seu-servidor.com"
      socketApiKey="sua-api-key"
      socketNamespace="chat"
      autoShowOnMessage={true}
    >
      <YourApp />
      <ChatWidget
        theme={{
          primaryColor: '#3b82f6' // Personalize a cor primária!
        }}
      />
    </ChatProvider>
  )
}

Nota sobre estilos: Os estilos são importados automaticamente quando você importa os componentes. Se houver problemas de conflito de CSS, veja o Guia de Isolamento de CSS.

Personalização de cores: Você pode customizar as cores do chat usando a prop theme. Veja mais detalhes na seção de Personalização de Cores.

React Native (Expo, RN CLI)

import { ChatWidget } from '@leve.ai/chat/native'
import { ChatProvider } from '@leve.ai/chat/shared'

function App() {
  return (
    <ChatProvider
      user={{ id: 'user123', name: 'João' }}
      socketUrl="https://seu-servidor.com"
      socketApiKey="sua-api-key"
      socketNamespace="chat"
      autoShowOnMessage={true}
    >
      <YourApp />
      <ChatWidget />
    </ChatProvider>
  )
}

✨ Metro Bundler Compatível: A partir da v1.0.9, a biblioteca funciona nativamente com Metro bundler sem necessidade de configuração adicional. Para mais detalhes, veja METRO_COMPATIBILITY.md.

Apenas Hooks/Lógica (UI Customizado)

import { useChat, useOrderRooms } from '@leve.ai/chat/shared'

function CustomChatUI() {
  const { messages, sendMessage } = useChat()
  const { openOrderChat } = useOrderRooms({
    orderIds: ['order1', 'order2'],
    enabled: true
  })

  // Criar seu próprio UI
  return (
    <div>
      {messages.map(msg => (
        <div key={msg.id}>{msg.content}</div>
      ))}
    </div>
  )
}

📚 API Reference

ChatProvider

Provider principal do sistema de chat.

Props:

  • children: ReactNode - Componentes filhos
  • autoShowOnMessage?: boolean - Mostrar widget automaticamente ao receber mensagem (default: true)
<ChatProvider autoShowOnMessage={false}>
  {/* seu app */}
</ChatProvider>

useChat()

Hook principal para gerenciar o chat.

Retorno:

{
  // Estado
  messages: Message[]
  currentRoom: string | null
  isConnected: boolean
  connectionStatus: ConnectionStatus
  isWidgetVisible: boolean
  unreadCount: number
  users: User[]
  isLoading: boolean
  error: string | null
  rooms: ChatRoom[]
  currentView: 'rooms' | 'chat'

  // Ações
  sendMessage: (content: string, type?: MessageType) => Promise<void>
  markAsRead: (messageId: string) => void
  markAllAsRead: () => void
  clearMessages: () => void
  joinRoom: (roomId: string) => Promise<void>
  leaveRoom: () => void
  showWidget: () => void
  hideWidget: () => void
  toggleWidget: () => void

  // Gerenciamento de Salas
  addRoom: (room: ChatRoom) => void
  removeRoom: (roomId: string) => void
  updateRoom: (roomId: string, updates: Partial<ChatRoom>) => void

  // Socket
  socket: Socket | null
  authenticated: boolean
  subscribe: (channel: string) => void
  unsubscribe: (channel: string) => void
}

Exemplo:

const { messages, sendMessage, isConnected } = useChat()

const handleSend = async () => {
  await sendMessage('Olá!', MessageType.TEXT)
}

useOrderRooms(options)

Hook para gerenciar múltiplas salas de pedidos.

Params:

{
  orderIds: string[]        // IDs dos pedidos
  enabled?: boolean         // Ativar auto-subscribe (default: true)
}

Retorno:

{
  subscribeToOrderRooms: (orderIds: string[]) => void
  unsubscribeFromOrderRooms: () => void
  openOrderChat: (orderId: string) => Promise<void>
  getOrderRoomId: (orderId: string) => string
  subscribedRooms: string[]
  getOrderUnreadCount: (orderId: string) => number
  getTotalUnreadCount: () => number
  getAllOrdersUnreadCount: () => Record<string, number>
}

Exemplo:

const {
  openOrderChat,
  getOrderUnreadCount
} = useOrderRooms({
  orderIds: orders.map(o => o.id),
  enabled: true
})

// Abrir chat de pedido específico
const handleOpenChat = (orderId: string) => {
  openOrderChat(orderId)
}

// Pegar contador de não lidas
const unread = getOrderUnreadCount('order123')

useChatWidget()

Hook simplificado para controle do widget.

Retorno:

{
  isVisible: boolean
  unreadCount: number
  isConnected: boolean
  isLoading: boolean
  currentRoom: string | null
  showWidget: () => void
  hideWidget: () => void
  toggleWidget: () => void
  hasUnreadMessages: boolean
}

Exemplo:

function HeaderChatButton() {
  const { showWidget, unreadCount, hasUnreadMessages } = useChatWidget()

  return (
    <button onClick={showWidget} className="relative">
      <MessageCircle />
      {hasUnreadMessages && (
        <span className="badge">{unreadCount}</span>
      )}
    </button>
  )
}

🎨 Componentes

Web Components

ChatWidget

Widget completo de chat com todas as funcionalidades.

Props:

  • position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left' - Posição do widget (default: 'bottom-right')
  • maxHeight?: number - Altura máxima em pixels (default: 500)
  • maxWidth?: number - Largura máxima em pixels (default: 380)
  • zIndex?: number - z-index do widget (default: 9999)
  • className?: string - Classes CSS adicionais
  • widgetClassName?: string - Classes CSS para o container do widget
  • theme?: ChatTheme - Objeto de personalização de cores (veja Personalização de Cores)
import { ChatWidget } from '@leve.ai/chat/web'

<ChatWidget
  position="bottom-right"
  maxHeight={600}
  maxWidth={400}
  zIndex={10000}
/>
🎨 Personalização de Cores

O ChatWidget aceita uma prop theme para customizar as cores primárias:

Props do theme:

  • primaryColor?: string - Cor primária principal (default: '#fa5534')
  • primaryColorHover?: string - Cor ao passar o mouse (default: '#e04829')
  • primaryColorLight?: string - Cor primária mais clara (default: 'rgba(250, 85, 52, 0.9)')
<ChatWidget
  theme={{
    primaryColor: '#3b82f6',      // Azul
    primaryColorHover: '#2563eb', // Azul escuro
    primaryColorLight: 'rgba(59, 130, 246, 0.9)'
  }}
/>

Exemplos de temas:

// Tema Verde
<ChatWidget
  theme={{
    primaryColor: '#10b981',
    primaryColorHover: '#059669',
    primaryColorLight: 'rgba(16, 185, 129, 0.9)'
  }}
/>

// Tema Roxo
<ChatWidget
  theme={{
    primaryColor: '#8b5cf6',
    primaryColorHover: '#7c3aed',
    primaryColorLight: 'rgba(139, 92, 246, 0.9)'
  }}
/>

// Tema usando cores da sua marca
<ChatWidget
  theme={{
    primaryColor: '#ff6b35',
    primaryColorHover: '#ff5722',
    primaryColorLight: 'rgba(255, 107, 53, 0.9)'
  }}
/>

As cores serão aplicadas em:

  • Botão flutuante do chat
  • Header do widget
  • Bolhas de mensagens enviadas
  • Botão de enviar
  • Ícones e destaques

ChatMessages

Apenas a área de mensagens.

import { ChatMessages } from '@leve.ai/chat/web'

<ChatMessages />

ChatInput

Apenas o input de envio.

import { ChatInput } from '@leve.ai/chat/web'

<ChatInput />

ChatRoomsList

Apenas a lista de salas.

import { ChatRoomsList } from '@leve.ai/chat/web'

<ChatRoomsList />

React Native Components

Mesmos componentes, porém adaptados para React Native:

import {
  ChatWidget,
  ChatMessages,
  ChatInput,
  ChatRoomsList
} from '@leve.ai/chat/native'

🔧 TypeScript

Todos os tipos são exportados do /shared:

import type {
  Message,
  ChatRoom,
  User,
  MessageType,
  ConnectionStatus,
  ChatState,
  ChatContextType,
  ChatTheme,
  ChatWidgetProps
} from '@leve.ai/chat/shared'

Tipo ChatTheme:

interface ChatTheme {
  primaryColor?: string
  primaryColorHover?: string
  primaryColorLight?: string
}

🎯 Casos de Uso

Chat em Página de Pedidos

import { useOrderRooms } from '@leve.ai/chat/shared'

function OrdersPage() {
  const { data: orders } = useOrders()

  const {
    openOrderChat,
    getAllOrdersUnreadCount
  } = useOrderRooms({
    orderIds: orders?.map(o => o.id) || [],
    enabled: !!orders
  })

  const unreadByOrder = getAllOrdersUnreadCount()

  return (
    <div>
      {orders?.map(order => (
        <div key={order.id}>
          <h3>{order.id}</h3>
          <button onClick={() => openOrderChat(order.id)}>
            Chat {unreadByOrder[order.id] > 0 && `(${unreadByOrder[order.id]})`}
          </button>
        </div>
      ))}
    </div>
  )
}

Botão de Chat no Header

import { useChatWidget } from '@leve.ai/chat/shared'

function Header() {
  const { showWidget, unreadCount, hasUnreadMessages } = useChatWidget()

  return (
    <header>
      <button onClick={showWidget} className="relative">
        <MessageCircle />
        {hasUnreadMessages && (
          <span className="absolute -top-1 -right-1 bg-red-500 text-white rounded-full px-1.5 py-0.5 text-xs">
            {unreadCount}
          </span>
        )}
      </button>
    </header>
  )
}

UI Totalmente Customizado

import { useChat } from '@leve.ai/chat/shared'

function MyCustomChat() {
  const { messages, sendMessage, currentRoom } = useChat()

  return (
    <div className="my-custom-chat">
      <div className="messages">
        {messages.map(msg => (
          <div key={msg.id} className="message">
            <span>{msg.senderName}:</span>
            <span>{msg.content}</span>
          </div>
        ))}
      </div>
      <input
        onKeyPress={(e) => {
          if (e.key === 'Enter') {
            sendMessage(e.currentTarget.value)
            e.currentTarget.value = ''
          }
        }}
      />
    </div>
  )
}

📦 Estrutura de Imports

@leve.ai/chat
├── /web          → Componentes Web (TailwindCSS)
├── /native       → Componentes React Native (StyleSheet)
└── /shared       → Hooks, Context, Types (compartilhados)

Tree-shaking: Apenas o código importado será incluído no bundle final.

⚙️ Configuração

🎨 Estilos e CSS

O chat usa Tailwind CSS com prefixo lv- e isolamento de estilos para evitar conflitos com seu projeto.

Todas as classes são prefixadas automaticamente:

  • flexlv-flex
  • bg-primarylv-bg-primary
  • text-whitelv-text-white

Problemas com estilos? Veja o guia completo:

Web (TailwindCSS)

Se estiver usando TailwindCSS no seu projeto, você pode:

Opção 1: Ignorar o pacote no seu Tailwind (recomendado)

module.exports = {
  content: [
    "./src/**/*.{js,ts,jsx,tsx}",
    "!./node_modules/@leve.ai/**/*", // ← Ignora o pacote
  ],
}

Opção 2: Incluir o pacote (não recomendado)

module.exports = {
  content: [
    "./src/**/*.{js,ts,jsx,tsx}",
    "./node_modules/@leve.ai/chat/dist/web/**/*.{js,mjs}"
  ],
}

React Native (Ícones)

Instale os ícones para React Native:

npm install lucide-react-native

🔗 Peer Dependencies

  • react: ^18.0.0 || ^19.0.0
  • react-dom: ^18.0.0 || ^19.0.0 (Web only)
  • react-native: >=0.70.0 (Native only)
  • @leve.ai/socket-client: ^1.0.0

📄 Licença

MIT © Leve.ai

🔧 Desenvolvimento

Para desenvolver e testar a biblioteca localmente, veja o Guia de Desenvolvimento.

Quick Start:

# Link para testes locais
npm run link:bun  # ou link:yarn / link:npm

# Build com watch mode
npm run build:watch

# Usar helper script
./dev-link.sh link bun

🤝 Contribuindo

Contribuições são bem-vindas! Por favor, abra uma issue ou PR.

📮 Suporte

  • 📧 Email: [email protected]
  • 📖 Docs: https://docs.leve.ai
  • 🐛 Issues: https://github.com/leveai/chat/issues