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

@aiwanna-team/message-list

v0.1.1

Published

一个基于 React + TypeScript + Virtuoso 的高性能消息列表组件,专为聊天应用和实时通讯场景设计。

Readme

@aiwanna-team/message-list

一个基于 React + TypeScript + Virtuoso 的高性能消息列表组件,专为聊天应用和实时通讯场景设计。

✨ 功能特性

  • 🚀 高性能虚拟滚动 - 基于 Virtuoso 引擎,支持大量消息流畅渲染
  • 💬 智能消息气泡 - 自动分组显示,支持连续消息的视觉优化
  • 📱 响应式设计 - 完美适配移动端和桌面端
  • 时间戳显示 - 自动格式化消息时间
  • 🔄 上拉加载历史 - 支持异步加载历史消息,游标分页
  • 🎨 自定义样式 - 基于 TailwindCSS,易于定制
  • 📝 消息更新 - 支持实时更新消息内容(AI 流式回复场景)
  • 🔧 TypeScript 支持 - 完整的类型定义

📦 安装

npm install @aiwanna-team/message-list

依赖要求

确保你的项目已安装以下依赖:

npm install react react-dom tailwindcss @tailwindcss/vite

最低版本要求:

  • Node.js >= 20.0.0
  • React >= 19.1.0
  • TailwindCSS >= 4.1.8

🚀 快速开始

设置步骤

  1. 安装组件库

    npm install @aiwanna-team/message-list
  2. 配置 TailwindCSS 源文件检测

    在你的主 CSS 文件(如 src/app.css)中添加:

    @import "tailwindcss";
    @source "../node_modules/@aiwanna-team/message-list";
  3. 开始使用组件

基础使用

import React, { useRef } from 'react'
import MessageList, { 
  type MessageListMethods, 
  type Message 
} from '@aiwanna-team/message-list'
import '@aiwanna-team/message-list/css'

function ChatApp() {
  const messageListRef = useRef<MessageListMethods>(null)

  const initialMessages: Message[] = [
    {
      key: 'msg-1',
      text: '你好!欢迎使用消息列表组件',
      user: 'other',
      timestamp: new Date(),
    },
    {
      key: 'msg-2',
      text: '这个组件很棒!',
      user: 'me',
      timestamp: new Date(),
    }
  ]

  const handleSendMessage = () => {
    messageListRef.current?.sendMessage('新消息内容')
  }

  return (
    <div className="w-full max-w-2xl mx-auto">
      <MessageList
        ref={messageListRef}
        height="500px"
        initialMessages={initialMessages}
      />
      <button 
        onClick={handleSendMessage}
        className="mt-4 px-4 py-2 bg-blue-500 text-white rounded"
      >
        发送消息
      </button>
    </div>
  )
}

配置 TailwindCSS

⚠️ 重要配置:由于该组件使用了 TailwindCSS 样式,你需要在项目的 CSS 文件中注册组件库的源文件,否则 TailwindCSS 无法检测到组件中使用的类名,导致样式缺失。

在你的主 CSS 文件中添加:

@import "tailwindcss";
@source "../node_modules/@aiwanna-team/message-list";

这样 TailwindCSS 就能扫描组件库中的样式类并生成对应的 CSS。

示例项目结构:

your-project/
├── src/
│   ├── app.css          # 在这里添加 @source 指令
│   └── main.tsx
└── node_modules/
    └── @aiwanna-team/
        └── message-list/

了解更多关于源文件检测的信息,请参考 TailwindCSS 官方文档

📚 API 文档

MessageList 组件属性

| 属性 | 类型 | 默认值 | 说明 | |------|------|--------|------| | height | string \| number | "500px" | 消息列表容器高度 | | className | string | "" | 自定义 CSS 类名 | | style | React.CSSProperties | - | 自定义样式 | | initialMessages | Message[] | [] | 初始消息列表 | | onLoadHistory | LoadHistoryFunction | - | 历史消息加载回调 | | historyLoadLimit | number | 20 | 每次加载历史消息数量 | | loadThreshold | number | 100 | 触发加载的滚动阈值(px) | | autoHideScrollbar | boolean | true | 是否自动隐藏滚动条 | | licenseKey | string | "" | Virtuoso 许可证密钥 |

MessageListMethods 实例方法

interface MessageListMethods {
  /** 发送消息,返回消息key */
  sendMessage: (text: string) => string
  /** 接收消息,返回消息key */
  receiveMessage: (text: string) => string
  /** 更新消息内容 */
  updateMessage: (key: string, newText: string) => void
  /** 获取所有消息 */
  getAllMessages: () => Message[]
  /** 清空消息列表 */
  clearMessages: () => void
  /** 重设消息列表 */
  resetMessages: (messages: Message[]) => void
}

Message 数据结构

interface Message {
  /** 消息唯一标识 */
  key: string
  /** 消息文本内容 */
  text: string
  /** 消息发送者 */
  user: "me" | "other"
  /** 消息时间戳 */
  timestamp?: Date
}

LoadHistoryFunction 回调类型

type LoadHistoryFunction = (
  beforeMessageKey?: string,
  limit?: number
) => Promise<Message[]>

🔄 历史消息加载

基础配置

import { useCallback } from 'react'

function ChatApp() {
  // 历史消息加载函数
  const handleLoadHistory = useCallback(async (beforeMessageKey, limit = 20) => {
    try {
      // 调用你的 API
      const response = await fetch(`/api/messages?before=${beforeMessageKey}&limit=${limit}`)
      const data = await response.json()
      
      // 返回消息数组
      return data.messages.map(msg => ({
        key: msg.id,
        text: msg.content,
        user: msg.sender === 'currentUser' ? 'me' : 'other',
        timestamp: new Date(msg.createdAt),
      }))
    } catch (error) {
      console.error('加载历史消息失败:', error)
      return [] // 返回空数组表示加载完成
    }
  }, [])

  return (
    <MessageList
      onLoadHistory={handleLoadHistory}
      historyLoadLimit={20}
      loadThreshold={100}
    />
  )
}

游标分页说明

  • beforeMessageKey: 游标位置,加载此消息之前的历史记录
  • limit: 每次加载的消息数量
  • 返回空数组 [] 表示没有更多历史消息

🤖 AI 聊天集成

流式回复示例

function AIChatApp() {
  const messageListRef = useRef<MessageListMethods>(null)

  const handleAIChat = async (question: string) => {
    // 发送用户问题
    messageListRef.current?.sendMessage(question)
    
    // 创建 AI 回复占位符
    const botMessageKey = messageListRef.current?.receiveMessage('正在思考...')
    
    try {
      // 模拟流式回复
      const responses = [
        '让我想想...',
        '让我想想...这是一个很好的问题',
        '让我想想...这是一个很好的问题,我来为你详细解答。'
      ]
      
      for (let i = 0; i < responses.length; i++) {
        await new Promise(resolve => setTimeout(resolve, 500))
        messageListRef.current?.updateMessage(botMessageKey!, responses[i])
      }
    } catch (error) {
      messageListRef.current?.updateMessage(botMessageKey!, '抱歉,出现了错误')
    }
  }

  return (
    <div>
      <MessageList ref={messageListRef} />
      <button onClick={() => handleAIChat('你好,你是谁?')}>
        测试 AI 回复
      </button>
    </div>
  )
}

🎨 自定义样式

基础样式定制

<MessageList
  className="border-2 border-blue-200 shadow-lg"
  style={{
    borderRadius: '16px',
    background: 'linear-gradient(to bottom, #f8fafc, #ffffff)'
  }}
/>

高级样式定制(待开发)

通过 CSS 变量覆盖默认样式:

.message-list-container {
  --message-bg-me: #3b82f6;
  --message-bg-other: #f3f4f6;
  --message-text-me: #ffffff;
  --message-text-other: #1f2937;
}

📖 使用示例

聊天室应用

import { useState, useRef, useCallback } from 'react'
import MessageList, { type MessageListMethods, type Message } from '@aiwanna-team/message-list'

function ChatRoom() {
  const [inputValue, setInputValue] = useState('')
  const messageListRef = useRef<MessageListMethods>(null)
  
  const handleSend = () => {
    if (inputValue.trim()) {
      messageListRef.current?.sendMessage(inputValue)
      setInputValue('')
    }
  }
  
  const handleLoadHistory = useCallback(async (beforeKey, limit) => {
    // 实现你的历史消息加载逻辑
    const messages = await loadHistoryFromAPI(beforeKey, limit)
    return messages
  }, [])

  return (
    <div className="flex flex-col h-screen max-w-2xl mx-auto">
      <div className="flex-1 p-4">
        <MessageList
          ref={messageListRef}
          height="100%"
          onLoadHistory={handleLoadHistory}
        />
      </div>
      
      <div className="p-4 border-t flex gap-2">
        <input
          value={inputValue}
          onChange={(e) => setInputValue(e.target.value)}
          onKeyPress={(e) => e.key === 'Enter' && handleSend()}
          className="flex-1 px-3 py-2 border rounded-lg"
          placeholder="输入消息..."
        />
        <button
          onClick={handleSend}
          className="px-4 py-2 bg-blue-500 text-white rounded-lg"
        >
          发送
        </button>
      </div>
    </div>
  )
}

🧪 开发和测试

运行 Storybook

# 克隆仓库
git clone <repository-url>
cd message-list

# 安装依赖
npm install

# 启动 Storybook
npm run storybook

可用的演示

  • Default - 基础使用演示
  • WithInitialMessages - 初始消息展示
  • Interactive - 交互式功能演示
  • HistoryLoading - 历史消息加载演示
  • Performance - 性能压力测试
  • CustomStyle - 自定义样式演示

⚡ 性能优化

最佳实践

  1. 合理设置历史加载数量
<MessageList
  historyLoadLimit={30}  // 根据网络状况调整
  loadThreshold={150}    // 调整触发距离
/>
  1. 使用 useCallback 优化回调
const handleLoadHistory = useCallback(async (beforeKey, limit) => {
  // 实现逻辑
}, [/* 最小依赖 */])
  1. 避免频繁的消息更新
// 批量更新而不是逐条更新
const batchUpdate = (updates) => {
  updates.forEach(({ key, text }) => {
    messageListRef.current?.updateMessage(key, text)
  })
}

🔧 故障排除

常见问题

Q: 样式不显示或错乱? A: 最常见的原因是没有在 CSS 中添加 @source 指令。请确保:

  1. 在主 CSS 文件中添加了 @source "../node_modules/@aiwanna-team/message-list";
  2. 项目使用的是 TailwindCSS 4.0+
  3. 检查控制台是否有 TailwindCSS 相关的错误信息

Q: 历史消息加载不触发? A: 检查 onLoadHistory 回调是否正确设置,确保有足够的初始消息支持滚动

Q: 消息更新不生效? A: 确保使用正确的消息 key,检查 updateMessage 调用

Q: 性能问题? A: 调整 historyLoadLimit 和虚拟滚动配置,避免一次性加载过多消息

📄 许可证

MIT License

🤝 贡献

欢迎提交 Issue 和 Pull Request!


官方文档: 查看 Storybook 演示 GitHub: aiwanna-team/message-list