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

chat-wrapper

v1.0.19

Published

A package wrapper around the React chat library, used to integrate chat into Vue and Angular apps.

Readme

A package wrapper around the React chat library, used to integrate chat into Vue and Angular apps.

Install

npm install chat-wrapper --save

After installing the wrapper, all the necessary packages for the chat will be automatically installed. Also, to integrate store chat into the application, you need to install reduxjs/toolkit:

npm install @reduxjs/toolkit  --save

Imports

Import the components and constants from the package into the file:

import { ChatConnector, ChatListConnector, LS_TOKEN_KEY, chatStore, ChatRootState } from "chat-wrapper";

Important

After logging the user into your app, you should set the access token in the local storage of the browser for the chat components:

localStorage.setItem(LS_TOKEN_KEY, 'access_token');

After calling the function to refresh a token from your app, the new received token must be installed in local storage of the browser under the key LS_TOKEN_KEY and returned from the function.


ChatConnector Component

import { ChatConnector } from "chat-wrapper";

  <ChatConnector
    opponent_id="opponent_id"
    user_id="user_id"
    user_locale="locale"
    isOnlyChat={true}
    cbHandleCloseChat={cbCloseChat}
    handleRefreshToken={cbRefreshToken}
    classHeader="customCSSClass"
    classMessages="customCSSClass"
  />
Chat props

| prop | default | type | description | | :----------------- | :------ | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------ | | opponent_id | none | string | User opponent ID | | user_id | none | string | User id got from the access token by decoding | | user_locale | ru/en | string | Chat interface language. The browser language is set by default | | isOnlyChat | none | boolean | true value is set when only the chat close functionality is used. false allows more chat functionality | | cbHandleCloseChat | none | function | A callback function that is called when the user clicks the close chat button | | handleRefreshToken | none | function | An asynchronous callback function that is called if the chat API call returns an error. Takes an axios error as an argument. Should return the new user token | | classHeader | " " | string | Adds a custom style class for the Chat header | | classMessages | " " | string | Adds a custom style class for the box with messages |


ChatListConnector Component

import { ChatListConnector } from "chat-wrapper";

  <ChatListConnector
    user_id="user_id"
    user_locale="locale"
    isOnlyChatList={true}
    cbHandleCloseChatList={handleCloseList}
    handleRefreshToken={handleRefreshToken}
    classList="customCSSClass"
    cbHandleOpenChat={handleOpenChat}
  />
ChatListConnector props

| prop | default | type | description | | :-------------------- | :------ | :------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | user_id | none | string | User id got from the access token by decoding | | user_locale | ru/en | string | ChatList interface language. The browser language is set by default. | | isOnlyChatList | none | boolean | true value is set when only the chat list close functionality is used. false allows more chat list functionality. | | cbHandleCloseChatList | none | function | A callback function that is called when the user clicks the close chat button. | | cbHandleOpenChat | none | function | A callback function that is called when the user clicks on a specific chat in the list. Takes an object as a function argument: {chat_id:string; opponent_id:string} | | handleRefreshToken | none | function | An asynchronous callback function that is called if the chat API call returns an error. Takes an axios error as an argument. Should return the new user token. | | classList | " " | string | Adds a custom style class for the ChatList wrapper |


Integration into Vue project

Setting up configuration files

To integrate the React library into the project, you should configure vite to work with react and Vue:

npm install @vitejs/plugin-react

In the vite.config.ts file, add a condition for processing files for React:

//vite.config.ts
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import react from "@vitejs/plugin-react";

export default defineConfig({
  plugins: [vue(), react()],
});

Connecting redux store

A store redux plugin is being created to connect chat to the store project:

//storePlugin.ts
import { App, reactive } from "vue";
import { EnhancedStore } from "@reduxjs/toolkit";
import { ChatRootState } from "chat-wrapper"; //type for store chat

export const storeKey = Symbol("Redux-Store");

export const createRedux = (store: EnhancedStore) => {
  const rootStore = reactive<{ state: ChatRootState }>({
    state: store.getState(),
  });
  const plugin = {
    install: (app: App) => {
      app.provide<{ state: ChatRootState }>(storeKey, rootStore);

      store.subscribe(() => {
        rootStore.state = store.getState();
      });
    },
  };
  return plugin;
};

In the main.ts file of the app, the chat store and plugin are imported, then connected to the app for use:

//main.ts
import { createApp } from "vue";
import App from "./App.vue";
import { createRedux } from "./storePlugin";
import { chatStore } from "chat-wrapper";

const app = createApp(App);
app.use(createRedux(chatStore)); // Connect the plugin from Redux Store in the app
app.mount("#app");

Using Connectors

A component is created into which the chat connector from the wrapper package will be imported:

//ChatComponent.vue
<template>
  <div id="app"></div>
</template>

<script lang="ts">
import { onBeforeUnmount, onMounted } from "vue";

import { LS_TOKEN_KEY, ChatConnector} from "chat-wrapper";

export default {
  name: "ChatComponent",
  setup() {
    let reactComponent: InstanceType<typeof ChatConnector> | null = null;

    onMounted(() => {
      const appElement = document.getElementById("app") as HTMLElement;

      reactComponent = new ChatConnector(appElement);

      localStorage.setItem(LS_TOKEN_KEY, 'access_token');

      reactComponent.render({
        opponent_id: "opponent_id",
        cbHandleCloseChat: () => {},
        handleRefreshToken: () => {},
        user_locale: "user_locale",
        isOnlyChat: true,
        user_id: "user_id",
      });
    });

    onBeforeUnmount(() => {
      if (reactComponent) {
        reactComponent.unmount();
      }
    });

    return {};
  },
};
</script>

And for the chat list connector the example would look like this:

//ChatListComponent.vue
<template>
  <div id="app"></div>
</template>

<script lang="ts">
import { onBeforeUnmount, onMounted } from "vue";

import { LS_TOKEN_KEY, ChatListConnector } from "chat-wrapper";

export default {
  name: "ChatListComponent",
  setup() {
    let reactComponent: InstanceType<typeof ChatListConnector> | null = null;

    onMounted(() => {
      const appElement = document.getElementById("app") as HTMLElement;

      reactComponent = new ChatListConnector(appElement);

      localStorage.setItem(LS_TOKEN_KEY, 'access_token');

      reactComponent.render({
        cbHandleOpenChat: () => {},
        cbHandleCloseChatList: () => {},
        handleRefreshToken: () => {},
        user_locale: "user_locale",
        isOnlyChatList: true,
        user_id: "user_id",
      });
    });

    onBeforeUnmount(() => {
      if (reactComponent) {
        reactComponent.unmount();
      }
    });

    return {};
  },
};
</script>

In the App.vue project file you need to import the chat files:

//App.vue
<template>
  <div>
    <ChatComponent />
  </div>
</template>

<script>
import ChatComponent from "./components/ChatComponent.vue";
import ChatListComponent from "./components/ChatListComponent.vue";

export default {
  name: "App",
  components: {
    ChatComponent, ChatListComponent
  },
};
</script>

Integration into Angular project

Setting up configuration files

In order to be able to create files with the .tsx extension, you need to make changes to the tsconfig.json file:

//tsconfig.json
{
  "compilerOptions": {
    ...
    "jsx": "react"
  },
  "angularCompilerOptions": {
    ...
  }
}

Connecting redux store

You should import the chat store and connect it to the project; to do this, you should create the file src/redux-store.service.ts

//src/redux-store.service.ts
import { Injectable } from '@angular/core';
import { chatStore } from 'chat-wrapper';

@Injectable({
  providedIn: 'root',
})
export class ReduxStoreService {
  getStore() {
    return chatStore;
  }
}

Using Connectors

Create a component file into which you will import the chat connectors:

//ChatWrapper.tsx
import {
  AfterViewInit,
  Component,
  ElementRef,
  EventEmitter,
  Input,
  OnChanges,
  OnDestroy,
  Output,
  SimpleChanges,
  ViewChild,
  ViewEncapsulation,
} from "@angular/core";
import { LS_TOKEN_KEY, ChatConnector } from "chat-wrapper";
import { createRoot } from "react-dom/client";

const containerElementRef = "customReactComponentContainer";

@Component({
  selector: "chat-wrapper",
  template: `<div #${containerElementRef}></div>`,
  encapsulation: ViewEncapsulation.None,
})
export class ChatWrapper implements OnChanges, OnDestroy, AfterViewInit {
  @ViewChild(containerElementRef, { static: true }) containerRef!: ElementRef;

  @Output() public componentClick = new EventEmitter<void>();

  @Input() opponentId: string = "opponent_id";
  @Input() userId: string = "user_id";
  @Input() userLocale: string = "user_locale";
  @Input() isOnlyChat: boolean = true;

  private root: ReturnType<typeof createRoot> = {} as ReturnType<
    typeof createRoot
  >;

  private chatConnector!: InstanceType<typeof ChatConnector>;

  ngOnChanges(changes: SimpleChanges): void {
    if (this.chatConnector) {
      this.render();
    }
  }

  ngAfterViewInit() {
    this.chatConnector = new ChatConnector(this.containerRef.nativeElement);
    this.render();
  }

  ngOnDestroy() {
    if (this.chatConnector) {
      this.chatConnector.unmount();
    }
  }

  private render() {
    localStorage.setItem(LS_TOKEN_KEY, 'access_token');

    this.chatConnector.render({
      opponent_id: this.opponentId,
      user_id: this.userId,
      user_locale: this.userLocale,
      isOnlyChat: this.isOnlyChat,
      cbHandleCloseChat: () => {
        this.componentClick.emit();
      },
      handleRefreshToken: () => {},
    });
  }
}

Then you should import the chat wrapper component into the app files:

// app/app.component.ts
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { ChatWrapper } from '../ChatWrapper';

@Component({
  selector: 'app-root',
  imports: [RouterOutlet, ChatWrapper],
  templateUrl: './app.component.html',
  styleUrl: './app.component.css',
})
export class AppComponent {
  ...
}
// app/app.component.html
<chat-wrapper></chat-wrapper>
<router-outlet />