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 🙏

© 2026 – Pkg Stats / Ryan Hefner

chat-widget-universal

v1.2.0

Published

Widget de chat universel compatible avec React, Angular, Vue et Svelte

Readme

Chat Widget Universal

Un widget de chat moderne, fluide et responsive, compatible avec React, Angular, Vue, Svelte et tout framework JavaScript moderne. Construit avec TypeScript et TailwindCSS.

🚀 Installation

npm install chat-widget-universal

📦 Structure du Package

chat-widget-universal/
├── dist/
│   ├── index.js          # Build CommonJS
│   ├── index.esm.js      # Build ES Module
│   ├── index.d.ts        # Types TypeScript
│   └── styles.css        # Styles TailwindCSS compilés
├── src/
│   ├── components/
│   │   └── ChatWidget.ts          # Classe principale du widget
│   ├── styles/           # Styles source TailwindCSS
│   ├── types/            # Types TypeScript
│   └── index.ts          # Point d'entrée
└── examples/             # Exemples d'intégration

✨ Fonctionnalités

  • 💬 Interface de chat moderne avec design élégant et responsive
  • 🎨 Personnalisation complète des couleurs, logos et styles
  • 🖼️ Upload d'images avec prévisualisation et barre de progression
  • 🎤 Reconnaissance vocale intégrée (Web Speech API)
  • 📱 Responsive : s'adapte automatiquement aux écrans mobiles
  • 🧩 Architecture modulaire et extensible
  • Performances : léger et rapide
  • 🌐 Universal : compatible avec tous les frameworks modernes

🎯 Utilisation Rapide

Exemple Basique

import { initChatWidget } from 'chat-widget-universal';
import 'chat-widget-universal/dist/styles.css';

const widget = initChatWidget({
  apiUrl: 'https://api.example.com/chat',
  welcomeMessage: 'Bonjour ! Comment puis-je vous aider ?',
  position: 'bottom-right',
});

Avec Callbacks Personnalisés

import { initChatWidget, ChatMessage } from 'chat-widget-universal';

const widget = initChatWidget({
  welcomeMessage: 'Bienvenue !',
  callbacks: {
    onSendMessage: async (message: string) => {
      // Votre logique personnalisée
      const response = await fetch('/api/chat', {
        method: 'POST',
        body: JSON.stringify({ message }),
      });
      const data = await response.json();
      
      return {
        id: `msg-${Date.now()}`,
        type: 'text',
        content: data.response,
        sender: 'bot',
        timestamp: new Date(),
      };
    },
    onReceiveMessage: (message: ChatMessage) => {
      console.log('Message reçu:', message);
    },
  },
});

⚙️ Configuration

Interface ChatWidgetConfig

interface ChatWidgetConfig {
  // Identifiant unique (optionnel)
  id?: string;
  
  // Position du widget
  position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
  
  // URL de l'API du chatbot
  apiUrl?: string;
  
  // Headers HTTP personnalisés
  apiHeaders?: Record<string, string>;
  
  // Méthode HTTP (GET, POST, etc.)
  apiMethod?: 'GET' | 'POST' | 'PUT' | 'PATCH';
  
  // Message d'accueil
  welcomeMessage?: string | ChatMessage;
  
  // Configuration des couleurs
  colors?: {
    primary?: string;        // Couleur principale
    secondary?: string;      // Couleur secondaire
    background?: string;     // Couleur de fond
    text?: string;          // Couleur du texte
    inputBackground?: string;
    inputText?: string;
    userMessageBg?: string;
    botMessageBg?: string;
  };
  
  // Configuration du logo
  logo?: {
    url?: string;
    alt?: string;
    width?: number;
    height?: number;
  };
  
  // Configuration du comportement
  behavior?: {
    responseDelay?: number;              // Délai de réponse (ms)
    showTypingIndicator?: boolean;       // Afficher l'indicateur de frappe
    typingIndicatorDuration?: number;     // Durée de l'indicateur (ms)
    enableQuickReplies?: boolean;        // Activer les réponses rapides
    enableSound?: boolean;               // Activer les sons
    soundUrl?: string;                   // URL du son de notification
  };
  
  // Callbacks personnalisés
  callbacks?: {
    onSendMessage?: (message: string, metadata?: any) => Promise<ChatMessage | ChatMessage[]> | ChatMessage | ChatMessage[];
    onReceiveMessage?: (message: ChatMessage) => void;
    onOpen?: () => void;
    onClose?: () => void;
    onError?: (error: Error) => void;
    onButtonClick?: (button: ButtonOption) => void;
  };
  
  // Classes CSS personnalisées
  customClasses?: {
    container?: string;
    chatWindow?: string;
    messageList?: string;
    message?: string;
    input?: string;
    button?: string;
  };
  
  // Autres options
  locale?: string;              // Langue (défaut: 'fr')
  title?: string;               // Titre du widget
  showCloseButton?: boolean;    // Afficher le bouton de fermeture
  showHeader?: boolean;         // Afficher le header
  inputPlaceholder?: string;    // Placeholder de l'input
  submitOnEnter?: boolean;       // Soumettre avec Enter
  submitOnButtonClick?: boolean; // Soumettre avec le bouton
  maxMessages?: number;         // Nombre max de messages
  autoScroll?: boolean;         // Scroll automatique
}

🎨 Personnalisation

Personnalisation des Couleurs

const widget = initChatWidget({
  colors: {
    primary: '#3b82f6',      // Bleu
    secondary: '#8b5cf6',   // Violet
    background: '#ffffff',
    text: '#1f2937',
    userMessageBg: '#3b82f6',
    botMessageBg: '#f3f4f6',
  },
});

Personnalisation du Logo

const widget = initChatWidget({
  logo: {
    url: '/assets/logo.png',
    alt: 'Mon Logo',
    width: 32,
    height: 32,
  },
});

Classes CSS Personnalisées

const widget = initChatWidget({
  customClasses: {
    container: 'my-custom-container',
    chatWindow: 'my-custom-window',
    message: 'my-custom-message',
  },
});

💬 Types de Messages

Le widget supporte plusieurs types de messages :

Message Texte

const message: ChatMessage = {
  id: 'msg-1',
  type: 'text',
  content: 'Bonjour !',
  sender: 'bot',
  timestamp: new Date(),
};

Message avec Image

Le widget supporte l'upload d'images avec prévisualisation :

const message: ChatMessage = {
  id: 'msg-2',
  type: 'image',
  content: 'Voici l\'image que je souhaite analyser :',
  sender: 'user',
  timestamp: new Date(),
  metadata: {
    imageUrl: 'https://example.com/image.jpg',
    fileName: 'image.jpg',
    fileSize: 1024000,
    fileType: 'image/jpeg',
  },
};

Fonctionnalités d'upload :

  • Sélection d'image via le bouton dédié
  • Prévisualisation avant envoi
  • Barre de progression simulée
  • Support de tous les formats d'image
  • Affichage dans les bulles de messages

Message avec Boutons

const message: ChatMessage = {
  id: 'msg-3',
  type: 'button',
  content: 'Choisissez une option :',
  sender: 'bot',
  timestamp: new Date(),
  metadata: {
    buttons: [
      {
        id: 'btn-1',
        label: 'Option 1',
        value: 'option1',
        action: 'postback',
      },
      {
        id: 'btn-2',
        label: 'Visiter le site',
        value: '',
        action: 'url',
        url: 'https://example.com',
      },
    ],
  },
};

Message Carte

const message: ChatMessage = {
  id: 'msg-4',
  type: 'card',
  content: '',
  sender: 'bot',
  timestamp: new Date(),
  metadata: {
    card: {
      title: 'Titre de la carte',
      description: 'Description de la carte',
      imageUrl: 'https://example.com/image.jpg',
      buttons: [
        {
          id: 'card-btn-1',
          label: 'En savoir plus',
          value: 'more',
          action: 'postback',
        },
      ],
    },
  },
};

Message Audio (Reconnaissance Vocale)

Le widget supporte la reconnaissance vocale via l'API Web Speech :

// La reconnaissance vocale est automatiquement disponible
// L'utilisateur peut cliquer sur le bouton microphone pour dicter
// Le texte est automatiquement transcrit dans le champ de saisie

Fonctionnalités vocales :

  • 🎤 Activation/désactivation du microphone
  • ⏱️ Indicateur d'enregistrement avec minuteur
  • 🗣️ Transcription automatique en temps réel
  • 🌍 Support multilingue (configurable via locale)
  • ⚠️ Gestion des erreurs et permissions

🔌 Intégration par Framework

React

import { useEffect } from 'react';
import { initChatWidget } from 'chat-widget-universal';
import 'chat-widget-universal/dist/styles.css';

function App() {
  useEffect(() => {
    const widget = initChatWidget({
      apiUrl: 'https://api.example.com/chat',
      welcomeMessage: 'Bonjour !',
    });

    return () => {
      widget.destroy();
    };
  }, []);

  return <div>Mon application</div>;
}

Angular

import { Component, OnInit, OnDestroy } from '@angular/core';
import { initChatWidget, ChatWidget } from 'chat-widget-universal';
import 'chat-widget-universal/dist/styles.css';

@Component({
  selector: 'app-root',
  template: '<router-outlet></router-outlet>'
})
export class AppComponent implements OnInit, OnDestroy {
  private widget: ChatWidget | null = null;

  ngOnInit() {
    this.widget = initChatWidget({
      apiUrl: 'https://api.example.com/chat',
      welcomeMessage: 'Bonjour !',
      position: 'bottom-right',
      colors: {
        primary: '#4f46e5',
      },
    });
  }

  ngOnDestroy() {
    this.widget?.destroy();
  }
}

📖 Guide complet : Consultez examples/angular-integration-guide.md pour plus de détails et d'exemples.

Vue 3

<script setup lang="ts">
import { onMounted, onUnmounted } from 'vue';
import { initChatWidget, ChatWidget } from 'chat-widget-universal';
import 'chat-widget-universal/dist/styles.css';

let widget: ChatWidget | null = null;

onMounted(() => {
  widget = initChatWidget({
    apiUrl: 'https://api.example.com/chat',
    welcomeMessage: 'Bonjour !',
  });
});

onUnmounted(() => {
  widget?.destroy();
});
</script>

Svelte

<script lang="ts">
  import { onMount, onDestroy } from 'svelte';
  import { initChatWidget, ChatWidget } from 'chat-widget-universal';
  import 'chat-widget-universal/dist/styles.css';

  let widget: ChatWidget | null = null;

  onMount(() => {
    widget = initChatWidget({
      apiUrl: 'https://api.example.com/chat',
      welcomeMessage: 'Bonjour !',
    });
  });

  onDestroy(() => {
    widget?.destroy();
  });
</script>

HTML Pur

<!DOCTYPE html>
<html>
<head>
  <link rel="stylesheet" href="node_modules/chat-widget-universal/dist/styles.css">
</head>
<body>
  <script type="module">
    import { initChatWidget } from './node_modules/chat-widget-universal/dist/index.esm.js';
    
    initChatWidget({
      apiUrl: 'https://api.example.com/chat',
      welcomeMessage: 'Bonjour !',
    });
  </script>
</body>
</html>

🎛️ API

Fonctions Principales

initChatWidget(config: ChatWidgetConfig): ChatWidget

Initialise et injecte le widget de chat dans le DOM.

Retourne : Instance du widget de chat

getChatWidget(): ChatWidget | null

Obtient l'instance actuelle du widget.

Retourne : Instance du widget ou null si non initialisé

destroyChatWidget(): void

Détruit l'instance actuelle du widget.

Méthodes de l'instance ChatWidget

// Ouvrir le widget
widget.open();

// Fermer le widget
widget.close();

// Toggle l'état du widget
widget.toggle();

// Ajouter un message manuellement
widget.addMessage(message: ChatMessage);

// Détruire le widget
widget.destroy();

🔗 Callbacks Disponibles

onSendMessage

Appelé lors de l'envoi d'un message. Vous pouvez retourner une réponse directement ou utiliser une URL d'API.

callbacks: {
  onSendMessage: async (message: string, metadata?: any) => {
    // Votre logique
    return chatMessage; // ou [chatMessage1, chatMessage2]
  },
}

onReceiveMessage

Appelé lors de la réception d'un message du bot.

callbacks: {
  onReceiveMessage: (message: ChatMessage) => {
    console.log('Message reçu:', message);
  },
}

onOpen / onClose

Appelés lors de l'ouverture/fermeture du widget.

callbacks: {
  onOpen: () => {
    console.log('Widget ouvert');
  },
  onClose: () => {
    console.log('Widget fermé');
  },
}

onError

Appelé en cas d'erreur.

callbacks: {
  onError: (error: Error) => {
    console.error('Erreur:', error);
  },
}

onButtonClick

Appelé lors du clic sur un bouton.

callbacks: {
  onButtonClick: (button: ButtonOption) => {
    console.log('Bouton cliqué:', button);
  },
}

📡 Format de l'API

Si vous utilisez apiUrl, le widget envoie des requêtes HTTP avec le format suivant :

Requête POST (par défaut)

{
  "message": "Message de l'utilisateur",
  "timestamp": "2024-01-01T12:00:00.000Z"
}

Réponse Attendue

Format simple :

{
  "id": "msg-1",
  "type": "text",
  "content": "Réponse du bot",
  "sender": "bot",
  "timestamp": "2024-01-01T12:00:00.000Z"
}

Format avec boutons :

{
  "id": "msg-1",
  "type": "button",
  "content": "Choisissez une option :",
  "sender": "bot",
  "timestamp": "2024-01-01T12:00:00.000Z",
  "metadata": {
    "buttons": [
      {
        "id": "btn-1",
        "label": "Option 1",
        "value": "option1",
        "action": "postback"
      }
    ]
  }
}

Format multiple messages :

[
  {
    "id": "msg-1",
    "type": "text",
    "content": "Premier message",
    "sender": "bot",
    "timestamp": "2024-01-01T12:00:00.000Z"
  },
  {
    "id": "msg-2",
    "type": "text",
    "content": "Deuxième message",
    "sender": "bot",
    "timestamp": "2024-01-01T12:00:00.000Z"
  }
]

🎨 Styles et Thèmes

Le widget utilise TailwindCSS pour le style. Vous pouvez :

  1. Utiliser les variables CSS pour personnaliser les couleurs
  2. Surcharger les classes via customClasses
  3. Importer les styles : import 'chat-widget-universal/dist/styles.css'

Personnalisation

Vous pouvez personnaliser les styles de plusieurs façons :

  1. Via la configuration : Utilisez l'objet colors dans la config
  2. Variables CSS : Les composants respectent les variables CSS personnalisées
  3. Classes personnalisées : Utilisez customClasses pour ajouter vos classes

Variables CSS Disponibles

--chat-primary-color: #4f46e5;
--chat-secondary-color: #8b5cf6;
--chat-bg-color: #ffffff;
--chat-text-color: #1f2937;
--chat-input-bg-color: #f9fafb;

📱 Responsive

Le widget est entièrement responsive et s'adapte automatiquement aux écrans mobiles :

  • 📱 Sur mobile : Le widget prend toute la largeur disponible (moins les marges)
  • 💻 Sur desktop : Taille fixe de 380px de largeur
  • 🎯 Adaptation automatique : Les messages et l'interface s'ajustent selon la taille d'écran
  • 📐 Hauteur flexible : S'adapte à la hauteur de la fenêtre du navigateur

🔒 Sécurité

  • 🔐 Pas de stockage local : Le widget ne stocke aucune donnée localement
  • 🔒 HTTPS recommandé : Toutes les communications avec l'API doivent utiliser HTTPS
  • 🔑 Authentification : Les headers personnalisés peuvent être utilisés pour l'authentification
  • 🎤 Permissions vocales : La reconnaissance vocale nécessite l'autorisation de l'utilisateur
  • 🖼️ Upload sécurisé : Les images sont traitées côté client avant envoi

🐛 Dépannage

Le widget ne s'affiche pas

  1. Vérifiez que vous avez importé les styles : import 'chat-widget-universal/dist/styles.css'
  2. Vérifiez que le DOM est prêt avant d'appeler initChatWidget
  3. Vérifiez la console pour les erreurs

Les messages ne s'affichent pas

  1. Vérifiez le format de la réponse de votre API
  2. Vérifiez les callbacks onSendMessage et onReceiveMessage
  3. Vérifiez la console pour les erreurs

Les styles ne s'appliquent pas

  1. Assurez-vous d'importer les styles CSS : import 'chat-widget-universal/dist/styles.css'
  2. Vérifiez que TailwindCSS n'est pas en conflit avec vos styles
  3. Utilisez la configuration colors pour personnaliser les couleurs
  4. Utilisez customClasses pour surcharger les styles

La reconnaissance vocale ne fonctionne pas

  1. Vérifiez que votre navigateur supporte l'API Web Speech (Chrome, Edge, Safari)
  2. Assurez-vous que l'utilisateur a autorisé l'accès au microphone
  3. Vérifiez que la langue est correctement configurée via locale
  4. En cas d'erreur, un message d'alerte s'affichera automatiquement

📄 Licence

MIT

🤝 Contribution

Les contributions sont les bienvenues ! N'hésitez pas à ouvrir une issue ou une pull request.

📚 Exemples Complets

Consultez le dossier examples/ pour des exemples d'intégration complets pour chaque framework.

🔗 Liens Utiles