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

@nuvira/chat-components

v0.1.10

Published

Chat UI for React (MUI): components and theme; dual entry for Next.js App Router — root is a Client bundle, @nuvira/chat-components/server for RSC-safe utilities and types

Readme

@nuvira/chat-components

React chat UI for Nuvira: MUI-based theming, message renderers, conversation list (ChatList, ChatListItem, ContactBadgeGroup), CRM sidebar (ChatSidebar), and full thread shell (ChatWindow, header, messages, input).

Install

npm install @nuvira/chat-components

Peer dependencies

The package expects your app to provide compatible versions of React, MUI, and Emotion (install these in your application; they are not bundled):

  • react and react-dom (>= 18)
  • @mui/material and @mui/icons-material (>= 5)
  • @emotion/react and @emotion/styled (>= 11)

Runtime dependencies shipped with the package: lodash, date-fns.

Usage

Wrap your app (or subtree) with MUI’s ThemeProvider and CssBaseline, using createChatTheme for defaults or overrides:

import { ThemeProvider, CssBaseline } from "@mui/material";
import {
  createChatTheme,
  TextMessage,
  type TextMessageProps,
} from "@nuvira/chat-components";

const theme = createChatTheme({
  palette: { primary: { main: "#1976d2" } },
});

export function App() {
  return (
    <ThemeProvider theme={theme}>
      <CssBaseline />
      <TextMessage message="Hello" intent="general_inquiry" />
    </ThemeProvider>
  );
}

Public API

  • Server / RSC: @nuvira/chat-components/server — types, mergeChatThreadAlerts, createChatTheme, pure helpers (pickIntegration, …), and other non-UI exports you can run in Server Components (see Server Components below). Fetch-based Nuvira defaults (createNuviraChatIntegration, nuviraDefault*) stay on the root entry. UI and client hooks stay on the root.
  • Theme: createChatTheme, ChatThemeOptions
  • Message components: TextMessage, ImageMessage, AudioMessage, VideoMessage, DocumentMessage, and their *Props types
  • Conversation list: ChatList, ChatListItem, ChatListProps, ChatListItemProps, ChatListItemData
  • Contact badges: ContactBadgeGroup, ContactBadgeGroupProps (status, funnel, and stage chips in one row)
  • Layout: CollapsibleEdgePanel, CollapsibleEdgePanelProps
  • Agent / thread chrome: ChatAgentSwitch, ChatAiCover, ChatMessage, ChatMessagesContainer, ChatInput, ChatWindowHeader, ChatWindow, ChatThreadAlerts, and their *Props types (ChatInputMediaFile for attachments)
  • Thread alerts (typed): ChatThreadAlert, ChatThreadAlertSeverity, mergeChatThreadAlerts, MergeChatThreadAlertsInput, reserved id constants (CHAT_THREAD_ALERT_ID_LAST_MESSAGE_ERROR, CHAT_THREAD_ALERT_ID_REACHABILITY_WINDOW), CHAT_THREAD_ALERT_REACHABILITY_MESSAGE
  • AI summary: AISummary, AISummaryProps
  • Funnel & stage: FunnelStageSelector, FunnelSelector, StageSelector, and their *Props types
  • CRM sidebar (accordion sections): ChatSidebar (canonical name; ConsolidatedChatActions is a deprecated alias), plus ChatContactStatus, StatusChangeDisplay, ContactStatusHistoryList, ContactStatusHistoryButton, ContactInfoEditor, ChatContactNotes, and their prop types
  • Types & constants: MessageType, Contact, ContactMessage, ContactNotes, Workspace, CustomFunnel, CustomStage, ContactStatusHistory, ContactStatus, MediaState, MediaFile, ChatSidebarSectionId, ChatSidebarSectionConfig, ChatSidebarCustomSection, ChatSidebarProps, and CHAT_SIDEBAR_* constants
  • Integration (typed callbacks): ChatIntegrationAdapter, createNuviraChatIntegration, payload types (SaveContactInput, SendChatMessageInput, …), and Nuvira default implementations (nuviraDefaultSaveContact, nuviraDefaultSendChatMessage, …). Helpers pickIntegration and pickOnIntegrationError are mainly for advanced composition. mergeOnIntegrationError remains as a deprecated alias for pickOnIntegrationError (it picks section-over-root; it does not merge handlers).
  • Legacy integration helpers: ContactStatusHistoryListItem, UseTimelineStreamOptions, useTimelineStream, useIsMobile, uploadMediaFileWithUrls, CONTACT_UPDATED_BROADCAST_MESSAGE_TYPE. fetchContactStatusHistoryDefault is deprecated; use nuviraDefaultLoadContactStatusHistory instead (same implementation).

ChatWindow accepts optional integration, onSendMessage, onUpdateTalkingToAgent, plus useTimelineStream, useIsMobile, uploadMediaFileWithUrls, and contactUpdatedBroadcastType for realtime, layout, and uploads. It also accepts alerts (ChatThreadAlert[]), showReachabilityWindow, onThreadAlertDismissed, and components.chatThreadAlerts for the thread alert strip (see Thread alerts below).

SSR / Next.js (App Router)

  • CollapsibleEdgePanel: The width animation honors prefers-reduced-motion through CSS in sx, not useMediaQuery, so the server render and the first client paint stay aligned for that concern (no extra matchMedia divergence in React output).
  • ChatWindow and viewport layout: Responsive branching (for example split inbox on md+ vs stacked mobile) is your app’s responsibility. Pass useIsMobile (or equivalent) in an SSR-safe way—for example MUI’s useMediaQuery with noSsr and an explicit defaultMatches so server HTML matches the initial client render, or a stable default until client-only logic runs. See MUI’s useMediaQuery and server-side rendering.

Server Components (React / Next.js App Router)

The root export (@nuvira/chat-components) is built as a Client Component bundle: the published dist/index.mjs / dist/index.js start with "use client". Import ChatWindow, ChatList, hooks, and the rest of the UI from a file that begins with "use client" (or from another client component).

Use the @nuvira/chat-components/server subpath in Server Components for anything that must not pull the client graph:

  • mergeChatThreadAlerts, alert types and id constants
  • Domain types (Contact, ChatThreadAlert, ChatListItemData, sidebar types, …) and sidebar section constants
  • createChatTheme / ChatThemeOptions (theme object only; wrap with MUI ThemeProvider in a client layout)
  • pickIntegration, pickOnIntegrationError / mergeOnIntegrationError (pure; no fetch)
  • uploadMediaFileWithUrls (stub — no network), CONTACT_UPDATED_BROADCAST_MESSAGE_TYPE
  • Type-only props: ChatListAvatarComponentProps, ContactBadgeGroupComponents, ChatMessageUseMediaUrl, ChatAiCoverProps, ContactStatusHistoryListItem, and integration payload types

Root entry only (client-oriented): createNuviraChatIntegration, nuviraDefault* helpers, and deprecated fetchContactStatusHistoryDefault use fetch("/api/...") with relative URLs. They are for browser execution; in Node / RSC, relative fetch is invalid — build your adapter with absolute URLs or call these only from client code.

Not on the server entry: useTimelineStream, useIsMobile, and every React component.

// app/thread/alerts.ts — Server Component module
import {
  mergeChatThreadAlerts,
  type ChatThreadAlert,
} from "@nuvira/chat-components/server";

Thread alerts

Thread alerts are typed values rendered in a strip below ChatWindowHeader and above ChatMessagesContainer. Use them for standardized warnings, errors, and info (severity maps to MUI Alert).

Shape (ChatThreadAlert):

| Field | Type | Purpose | | --- | --- | --- | | id | string | Stable key for React lists, deduplication, and replacing built-ins | | severity | "error" \| "warning" \| "info" \| "success" | Visual level | | message | string | Main body text | | title | string (optional) | Optional title above the body | | dismissible | boolean (optional) | When true, shows a close control; dismissal is stored inside ChatThreadAlerts (no parent state). If that id later disappears from alerts, the dismissal clears for that id so it can show again |

Dismissal: ChatThreadAlerts keeps a set of dismissed ids. Optional onAlertDismissed(id) on ChatThreadAlerts, or onThreadAlertDismissed on ChatWindow, runs at most once per id each time that id newly enters the dismissed set (after React commits state)—for example analytics. Redundant close actions do not invoke the callback again. Custom components.chatThreadAlerts.Alert receives onDismiss when dismissible is true — call it from your close control and do not forward dismissible / onDismiss to DOM nodes.

Merging (mergeChatThreadAlerts): ChatWindow merges alerts with built-ins from contact and flags:

  1. Last message error — If contact.lastMessageErrorReason is set, a warning with id CHAT_THREAD_ALERT_ID_LAST_MESSAGE_ERROR (nuvira:last-message-error) is included unless you pass your own alert with that id (e.g. localized copy).
  2. Reachability — If showReachabilityWindow is true, a warning with id CHAT_THREAD_ALERT_ID_REACHABILITY_WINDOW (nuvira:reachability-window) and message CHAT_THREAD_ALERT_REACHABILITY_MESSAGE is included unless you pass an alert with that id.
  3. Additional app alerts — Remaining entries from alerts are appended in order. For duplicate id values inside alerts, the last occurrence wins. Alerts whose id was already emitted from steps 1–2 are skipped.

Migration (ChatWindowHeader): The showAlert prop was removed from ChatWindowHeader. Use ChatWindow with showReachabilityWindow and/or typed alerts instead (see CHANGELOG.md).

You can call mergeChatThreadAlerts yourself when building custom layouts; ChatWindow uses it internally.

Example:

import { ChatWindow, type ChatThreadAlert } from "@nuvira/chat-components";

const extraAlerts: ChatThreadAlert[] = [
  {
    id: "billing-hold",
    severity: "info",
    title: "Billing",
    message: "Invoice pending review.",
    dismissible: true
  }
];

<ChatWindow
  {...windowProps}
  alerts={extraAlerts}
  showReachabilityWindow
  onThreadAlertDismissed={(id) => {
    /* optional: telemetry */
  }}
/>;

i18n: Set showReachabilityWindow={false} and pass an alert with id: CHAT_THREAD_ALERT_ID_REACHABILITY_WINDOW and your translated message, or pass the same id with localized text to override the default string.

Customization: ChatWindow supports components.chatThreadAlerts.Alert — a component receiving ChatThreadAlert fields plus sx and optional onDismiss (same pattern as other components maps). You can also render ChatThreadAlerts standalone with your own alerts array and onAlertDismissed.

Thread vs CRM: On ChatWindow, onSendMessage and onUpdateTalkingToAgent are resolved in order: window prop → integration → Nuvira default. That resolution applies to the thread/header (messages, agent toggle). The CRM sidebar receives the same integration for mutations and loaders (saveContact, onGenerateSummary, funnel/stage, status history, etc.). The sidebar does not get separate onSendMessage / onUpdateTalkingToAgent props; include those on ChatIntegrationAdapter only if a sidebar-related code path should call them.

ChatIntegrationAdapter and Nuvira defaults

Pass a single integration object to ChatSidebar or ChatWindow to override how the CRM sidebar and thread talk to your backend. createNuviraChatIntegration() returns an adapter wired to the same Nuvira fetch routes the library used internally before (you can still override individual fields).

  • Per-section overrides: ChatSidebar supports sectionConfig[sectionId].integration — each field there wins over the root integration for that section only.
  • Per-component props (e.g. saveContact on ContactInfoEditor, onGenerateSummary on AISummary) override both root and section adapter values when set.

Set onIntegrationError on the adapter (or section override) to receive mutation/load failures in one place instead of relying on alert or console-only behavior.

ContactInfoEditor persists via saveContact (default: nuviraDefaultSaveContactPUT /api/v1/contact/info). Storybook and tests should pass a no-op or mock saveContact when the API is unavailable.

UI components maps (stub substitution)

Optional components props let you swap MUI/stub primitives without forking:

  • ChatList: itemComponents → forwarded to each ChatListItem (Avatar, nested badgeGroup chips).
  • ChatListItem / ChatWindowHeader: components.Avatar (see ChatListAvatarComponentProps), header also components.Loading, components.badgeGroup.
  • ContactBadgeGroup: StatusChip, FunnelDisplay, StageDisplay (ContactBadgeGroupComponents).
  • ChatInput: TextField (defaults to NvTextField).
  • ChatMessage: useMediaUrl hook (same signature as the package default; must follow rules of hooks).
  • ChatMessagesContainer: components.AiCover, components.useMediaUrl for child messages.
  • ChatWindow: components.chatThreadAlerts.Alert → forwarded to ChatThreadAlerts (ChatThreadAlertRenderProps).
  • ChatAiCover: components.Loading.
  • AISummary: components.Loading on the generate button.
  • StatusChangeDisplay: ContactStatusChip, CustomStageChip.
  • ChatContactNotes: NoteCard, NoteForm, Modal.

Stubs and app integration

Several components still default to Nuvira-branded stubs under src/stubs/ when you do not pass components. They ship with the package for quick demos.

Status history: ContactStatusHistoryList / ContactStatusHistoryButton accept optional loadHistory; default is nuviraDefaultLoadContactStatusHistory. The same loader is ChatIntegrationAdapter.loadContactStatusHistory. (fetchContactStatusHistoryDefault is deprecated but still exported.)

Not published: ChatWindowSC (server/prisma demo) remains internal to this repo only.

Conversation list and badges

These components are presentational: your app owns fetching conversations, selection state, and routing.

ChatListItemData

Type for each row. It extends contact-like fields (id, name, status, customFunnelId, customStageId, lastMessageErrored, lastMessageErrorReason) with optional list fields:

| Field | Purpose | | --- | --- | | avatarUrl | Image URL for the avatar; initials fallback when absent | | subtitle | Last message preview (single line, ellipsis) | | updatedAt | Shown as relative time (today / yesterday / date) | | unreadCount | Badge on the avatar when greater than 0 |

ChatList

Scrollable MUI List of ChatListItem rows.

  • itemsChatListItemData[]
  • selectedId – highlights the matching row
  • onSelect(id) – called when a row is activated
  • emptyState – custom node when items is empty (default copy: “No conversations”)
  • sx – root styles
  • itemComponents – optional components for each ChatListItem (avatar / badge chips)

ChatListItem

One conversation row: ListItemButton, avatar (with optional unread badge), name, optional subtitle/time, ContactBadgeGroup, and optional error icon when lastMessageErrored / lastMessageErrorReason is set.

  • itemChatListItemData
  • selected, onClick, slotBadges (extra chips after the default badges), sx

ContactBadgeGroup

Single row of chips: contact status, then funnel and stage when IDs are present. Use slotEnd for extra chips (e.g. channel or “VIP”).

Example: list + selection

import {
  ChatList,
  type ChatListItemData,
} from "@nuvira/chat-components";

const items: ChatListItemData[] = [
  {
    id: "c1",
    name: "Ada",
    status: "LEAD_NEW",
    subtitle: "See you tomorrow",
    updatedAt: new Date(),
    unreadCount: 2,
  },
];

export function Inbox() {
  const [selectedId, setSelectedId] = useState<string | null>(null);
  return (
    <ChatList
      items={items}
      selectedId={selectedId}
      onSelect={setSelectedId}
      sx={{ maxHeight: 400 }}
    />
  );
}

Storybook and internal layout demos

Run npm run storybook to see:

  • Chat list / Chat list item stories
  • Chat list with ChatWindow – composite layout (list + ChatWindow, collapsible panels, sidebarPosition, etc.)

Story demos may import from @/ paths in this repo; published consumers should import from @nuvira/chat-components per the list above (src/index.ts).

Development

npm install
npm run storybook

Quality checks:

npm run check
npm run build

Publishing (maintainers)

Publishing is manual. Before the first (or any) release:

  1. Ensure main is green (npm run check, npm run build).
  2. Bump version in package.json as appropriate.
  3. Inspect the tarball: npm pack --dry-run
  4. Publish: npm publish (scoped public access is set in publishConfig).

prepublishOnly runs npm run build so the published package always includes a fresh dist/.

Pull requests: If you change package.json exports, the root vs @nuvira/chat-components/server split, or the "use client" build banner, say so in the PR title or description (not only a component name like ChatWindow) so reviewers and release notes match the packaging impact.

License

MIT. See LICENSE.