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

@fidurcode/chat

v1.0.0

Published

An Angular library providing a ready-made Messenger-style chat widget — a floating FAB button, a conversation list panel, and chat windows docked to a bottom bar.

Downloads

1,412

Readme

@fidurcode/chat

An Angular library providing a ready-made Messenger-style chat widget — a floating FAB button, a conversation list panel, and chat windows docked to a bottom bar.

The library handles only the visual and UX layer. All business logic (WebSocket, conversation list, messages, typing events) is provided externally by implementing ChatContract.


Requirements

  • Angular ^21.2.0
  • Angular Material ^21.2.0

Installation

npm install @fidurcode/chat

Quick start

1. Implement ChatContract

Create a service that implements the ChatContract interface:

import { Injectable, signal } from '@angular/core';
import { ChatContract, ChatConversation, ChatMessage } from '@fidurcode/chat';

@Injectable({ providedIn: 'root' })
export class MyChatService implements ChatContract {
  readonly conversations = signal<ChatConversation[]>([]);
  readonly unreadCount = signal(0);

  connect(userId: string | number): void {
    // open WebSocket connection
    // when an incoming "typing" event arrives from the server, set isTyping: true
    // on the matching conversation in this.conversations
  }

  disconnect(): void {
    // close connection
  }

  getMessages(conversationId: string) {
    return signal<ChatMessage[]>([]);
  }

  sendMessage(conversationId: string, content: string): void {
    // send message over WebSocket
  }

  markConversationAsRead(conversationId: string): void {
    // mark conversation as read
  }

  notifyTyping(conversationId: string): void {
    // send "typing" event to the server for this conversation
    // e.g.: this.socket.emit('typing', { conversationId })
  }

  notifyStopTyping(conversationId: string): void {
    // send "stop_typing" event to the server for this conversation
    // e.g.: this.socket.emit('stop_typing', { conversationId })
  }
}

2. Provide the service and add the widget

In your module or providers configuration:

import { CHAT_SERVICE } from '@fidurcode/chat';
import { MyChatService } from './my-chat.service';

providers: [
  { provide: CHAT_SERVICE, useExisting: MyChatService }
]

In your template:

<fidurcode-chat-button [config]="chatConfig" />
import { ChatConfig } from '@fidurcode/chat';

chatConfig: ChatConfig = {
  currentUserId: 'user-123',
};

3. Import the module

import { ChatModule } from '@fidurcode/chat';

@NgModule({
  imports: [ChatModule],
})

Configuration (ChatConfig)

| Field | Type | Default | Description | |-------|------|---------|-------------| | currentUserId | string / number | — | Required. ID of the logged-in user | | position | 'bottom-right' / 'bottom-left' | 'bottom-right' | Widget position | | bottom | number | 20 | Distance from bottom edge (px) | | side | number | 20 | Distance from side edge (px) | | maxOpenWindows | number | 3 | Maximum number of simultaneously open windows | | buttonIcon | string | 'chat' | Material Icons icon name for the FAB | | labels | ChatLabels | — | Override text labels |

Labels (labels)

labels: {
  title?: string;              // default: 'Wiadomości'
  searchPlaceholder?: string;  // default: 'Szukaj'
  inputPlaceholder?: string;   // default: 'Aa'
  emptyConversations?: string; // default: 'Brak rozmów'
  emptyMessages?: string;      // default: 'Napisz pierwszą wiadomość'
  online?: string;             // default: 'Aktywny/a'
}

Data interfaces

ChatConversation

interface ChatConversation {
  id: string;
  name: string;
  avatarUrl?: string;
  lastMessage?: string;
  lastMessageAt?: string; // ISO 8601
  unreadCount: number;
  isOnline?: boolean;
  isTyping?: boolean;     // when true, shows an animated ⋯ typing bubble in the chat window
  participants?: ChatParticipant[];
}

ChatMessage

interface ChatMessage {
  id: string;
  conversationId: string;
  senderId: string | number;
  content: string;
  sentAt: string; // ISO 8601
  status?: 'sending' | 'sent' | 'delivered' | 'read';
}

ChatContract

interface ChatContract {
  conversations: Signal<ChatConversation[]>;
  unreadCount: Signal<number>;
  connect(userId: string | number): void;
  disconnect(): void;
  getMessages(conversationId: string): Signal<ChatMessage[]>;
  sendMessage(conversationId: string, content: string): void;
  markConversationAsRead(conversationId: string): void;
  notifyTyping(conversationId: string): void;
  notifyStopTyping(conversationId: string): void;
}

Typing indicator

The library has a full typing indicator flow. Here is how it works end-to-end:

What the library does automatically

  1. While the user types in a chat window, ChatWindowComponent emits a (typing) output after a 300 ms debounce.
  2. After 1500 ms of inactivity (or immediately on send), it emits (stopTyping).
  3. When conversation.isTyping === true, the chat window renders an animated bubble with three bouncing dots at the bottom of the message list.

What the host app must do

Step 1 — wire up the outputs in whichever component renders fidurcode-chat-window:

<fidurcode-chat-window
  [conversation]="conv"
  [messages]="messages"
  [config]="chatConfig"
  (typing)="chatUIService.notifyTyping($event.conversationId)"
  (stopTyping)="chatUIService.notifyStopTyping($event.conversationId)"
  (messageSent)="chatUIService.sendMessage($event.conversationId, $event.content)"
  (minimize)="chatUIService.toggleMinimize(conv.id)"
  (close)="chatUIService.closeConversation(conv.id)"
/>

Step 2 — implement notifyTyping / notifyStopTyping in your ChatContract service to send the event to the server (e.g., via WebSocket or HTTP).

Step 3 — handle incoming typing events from the server. When person B receives a typing notification from person A, update person A's conversation in the conversations signal:

// inside connect() — handling incoming WebSocket messages
socket.on('typing', ({ conversationId }) => {
  this.conversations.update(list =>
    list.map(c => c.id === conversationId ? { ...c, isTyping: true } : c)
  );
});

socket.on('stop_typing', ({ conversationId }) => {
  this.conversations.update(list =>
    list.map(c => c.id === conversationId ? { ...c, isTyping: false } : c)
  );
});

Features

FAB button

  • Round button anchored to a corner of the viewport (position: fixed)
  • Animated unread count badge (color: mat-sys-primary)
  • Color driven by CSS variables or the app's Material Design theme

Conversation panel

  • List of conversations with avatars and initials as fallback
  • Real-time search with filtering
  • Green online indicator with animated pulse
  • Unread conversations shown in bold with a counter badge
  • Relative timestamps (now, 5m, 3h, DD/MM)

Chat windows

  • Messenger-style — windows dock to the bottom bar, up to maxOpenWindows at once
  • Message grouping — consecutive messages from the same sender share flattened corners and tighter spacing; avatar appears only on the last message in a group
  • Typing indicator — animated dots when isTyping = true on a conversation
  • Badge on minimized window — unread count visible without expanding
  • Message statuses: schedule (sending), done (sent), done_all (delivered / read)
  • Auto-scroll to the latest message
  • Send on Enter or the send button (disabled when input is empty)

Keyboard shortcuts

| Shortcut | Action | |----------|--------| | Escape | Close the conversation panel |


Theming — CSS Custom Properties

The widget inherits colors from the app's theme via Material Design tokens. Override any aspect with CSS custom properties:

fidurcode-chat-button {
  /* Panel and window backgrounds */
  --fidurcode-chat-bg: var(--mat-sys-surface);
  --fidurcode-chat-color: var(--mat-sys-on-surface);

  /* FAB button */
  --fidurcode-chat-fab-bg: var(--mat-sys-primary);
  --fidurcode-chat-fab-color: var(--mat-sys-on-primary);

  /* Unread badge on the FAB */
  --fidurcode-chat-fab-badge-bg: var(--mat-sys-primary);
  --fidurcode-chat-fab-badge-color: var(--mat-sys-on-primary);

  /* Avatars */
  --fidurcode-chat-avatar-bg: var(--mat-sys-primary);
  --fidurcode-chat-avatar-color: var(--mat-sys-on-primary);

  /* Unread badges in the panel */
  --fidurcode-chat-badge-bg: var(--mat-sys-primary);
  --fidurcode-chat-badge-color: var(--mat-sys-on-primary);

  /* Message bubbles */
  --fidurcode-chat-bubble-other-bg: var(--mat-sys-tertiary);
  --fidurcode-chat-bubble-other-color: var(--mat-sys-on-tertiary);
  --fidurcode-chat-bubble-own-bg: var(--mat-sys-primary);
  --fidurcode-chat-bubble-own-color: var(--mat-sys-on-primary);

  /* Online indicator */
  --fidurcode-chat-online-color: #31a24c;
  --fidurcode-chat-online-ring: var(--fidurcode-chat-bg);

  /* Dimensions (optional) */
  --fidurcode-chat-panel-width: 320px;
  --fidurcode-chat-panel-max-height: 520px;
  --fidurcode-chat-window-width: 300px;
  --fidurcode-chat-window-body-height: 360px;
}

Building

ng build chat

Build artifacts are placed in dist/chat/.