npm package: @fengxie/vue-im
Description: A beautiful and modern Vue 3 IM (Instant Messaging) UI library built with Tailwind CSS.
Author: fengxie
Latest version: 0.2.2

# @fengxie/vue-im

A beautiful and modern Vue 3 IM (Instant Messaging) UI library built with Tailwind CSS.

This library provides a set of highly customizable, responsive, and ready-to-use chat components for building messaging web applications in Vue 3.

## Features

- 💅 **Modern Design**: Premium UI with glassmorphism, responsive layouts, and Tailwind CSS.
- 🧩 **Modular Components**: Includes `IMLayout`, `Sidebar`, `ChatArea`, and `RightPanel`.
- 🌐 **i18n Support**: Auto-translation UI toggles and layout considerations for multi-language.
- 📦 **TypeScript**: Fully typed props and events for seamless developer experience.

## Installation

You can install the library via npm, pnpm, or yarn:

```bash
npm install @fengxie/vue-im
# or
pnpm install @fengxie/vue-im
# or
yarn add @fengxie/vue-im
```

### Peer Dependencies
Make sure you have `vue` and `tailwindcss` installed in your project:

```bash
npm install vue tailwindcss
```

You must also import `vue-im`'s styles, or simply let Tailwind CSS scan your `node_modules`. If you use Tailwind CSS v4, make sure to add `vue-im` to your content paths or ignore if not required by v4's new auto-scanning, but if you need the direct css:

In your `main.ts` or `App.vue`:
```ts
import '@fengxie/vue-im/dist/style.css';
```

## Quick Start / Usage

Here is a complete example of how to build a full IM layout using `@fengxie/vue-im`:

```vue
<script setup lang="ts">
import { ref } from 'vue';
import { IMLayout, Sidebar, ChatArea, RightPanel } from '@fengxie/vue-im';
import type { Account, Contact, Message, AppLanguage } from '@fengxie/vue-im';

// ---- State ----
const accounts = ref<Account[]>([/* your accounts */]);
const contacts = ref<Contact[]>([/* your contacts */]);
const activeAccount = ref<Account>(accounts.value[0]);
const activeContact = ref<Contact>(contacts.value[0]);
const messages = ref<Message[]>([]);
const lang = ref<AppLanguage>('zh');

const aiAutoReply = ref(false);
const autoTranslateReceive = ref(false);
const autoTranslateSend = ref(false);

const searchQuery = ref('');
const activeFilter = ref('all');

// Pagination state
const hasMore = ref(true);
const isLoadingMore = ref(false);

// ---- Sidebar Events ----
const handleContactSelect = (contact: Contact) => {
  activeContact.value = contact;
  // Fetch messages for this contact from API...
};

// ---- ChatArea Events ----
const handleSendMessage = (payload: { text: string; replyTo?: Message }) => {
  const newMsg: Message = {
    id: Date.now().toString(),
    senderId: 'me',
    text: payload.text,
    timestamp: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),
    type: 'text'
  };
  messages.value = [...messages.value, newMsg];
  // Call your API to persist the message...
};

const handleRecallMessage = (id: string) => {
  messages.value = messages.value.filter(m => m.id !== id);
  // Call your API to recall...
};

const handleUploadImage = (file: File) => {
  // Upload the file via your API...
};

const handleUploadFile = (file: File) => {
  // Upload the file via your API...
};

const handleLoadMore = () => {
  isLoadingMore.value = true;
  // Fetch older messages from your API, then prepend:
  // messages.value = [...olderMessages, ...messages.value];
  // hasMore.value = response.hasMore;
  // isLoadingMore.value = false;
};

// ---- RightPanel Events ----
const handleSendOrderCard = (order: any) => { /* send order card */ };
const handleActionClick = (action: string) => { /* handle biz action */ };
const handleSendProductMedia = (product: any) => { /* handle product send */ };
</script>

<template>
  <IMLayout>
    <template #sidebar>
      <Sidebar 
        :accounts="accounts"
        :activeAccount="activeAccount"
        :contacts="contacts"
        :activeContact="activeContact"
        v-model:searchQuery="searchQuery"
        v-model:activeFilter="activeFilter"
        @accountSelect="acc => activeAccount = acc"
        @contactSelect="handleContactSelect"
      />
    </template>
    
    <template #chatArea>
      <ChatArea 
        :contact="activeContact"
        :messages="messages"
        :hasMore="hasMore"
        :isLoadingMore="isLoadingMore"
        v-model:aiAutoReply="aiAutoReply"
        v-model:autoTranslateReceive="autoTranslateReceive"
        v-model:autoTranslateSend="autoTranslateSend"
        v-model:lang="lang"
        @loadMore="handleLoadMore"
        @sendMessage="handleSendMessage"
        @recallMessage="handleRecallMessage"
        @uploadImage="handleUploadImage"
        @uploadFile="handleUploadFile"
      />
    </template>
    
    <template #rightPanel>
      <RightPanel 
        :lang="lang"
        :contact="activeContact"
        :orderInfo="yourOrderData"
        :products="yourProductsList"
        @sendOrderCard="handleSendOrderCard"
        @actionClick="handleActionClick"
        @sendProductMedia="handleSendProductMedia"
      />
    </template>
  </IMLayout>
</template>
```

## Available Components

### `IMLayout`
The base wrapper component that provides the CSS Grid layout for the traditional IM interface. Provides three named slots: `#sidebar`, `#chatArea`, `#rightPanel`.

### `Sidebar`
Displays the active user account, search bar, and the contacts list.
- **Props**:
  - `accounts`: List of available user accounts.
  - `activeAccount`: Currently selected account.
  - `contacts`: Array of contacts.
  - `activeContact`: The currently selected contact for chat.
  - `searchQuery` (v-model): Search input text.
  - `activeFilter` (v-model): Active contact filter tab.
- **Events**: 
  - `@accountSelect(account)`
  - `@contactSelect(contact)`
  - `@update:searchQuery(query)`
  - `@update:activeFilter(filter)`

### `ChatArea`
The main message window where the conversation happens. Includes built-in support for reverse infinite scrolling (loading historical messages).
- **Props**:
  - `contact`: The current active `Contact`.
  - `messages`: An array of `Message` objects to render.
  - `aiAutoReply`, `autoTranslateReceive`, `autoTranslateSend`: Control various chat functionalities.
  - `lang`: Current language interface toggle (supports `zh`, `en`, etc.).
  - `hasMore` (optional): Boolean indicating if there are more historical messages to load.
  - `isLoadingMore` (optional): Boolean indicating if historical messages are currently being fetched.
- **Events**:
  - `@loadMore`: Emitted when the user scrolls to the top of the chat area.
  - `@sendMessage({ text, replyTo })`: Emitted when the user sends a message.
  - `@recallMessage(id)`: Emitted when a message is recalled.
  - `@uploadImage(file)` & `@uploadFile(file)`: Emitted on file selection.

### `RightPanel`
Extra pane for contact details, quick actions, and order/product information context.
- **Props**:
  - `contact`: The currently active `Contact`.
  - `orderInfo`: Object containing contextual order information.
  - `products`: Object for recommended products list.
- **Events**:
  - `@sendOrderCard(orderInfo)`
  - `@actionClick(actionType)`: Emitted with string 'contract', 'payment', 'logistics', 'coupon'.
  - `@sendProductMedia(product)`

---

## Publishing Workflow (For Maintainers)

If you are a maintainer of this library, here is the complete flow to publish updates to NPM:

1. **Build the Library**
   Run the build script to generate the `/dist` artifacts (ES and UMD formats, plus Type Definitions).
   ```bash
   pnpm run build
   ```
2. **Login to NPM**
   If you aren't already authenticated on your machine, log in.
   ```bash
   npm login
   # You will be prompted for your username, password, and OTP.
   ```
3. **Publish**
   Once logged in and built, publish the package.
   *(Make sure you have incremented the `version` in `package.json` for subsequent updates)*
   ```bash
   npm publish --access public
   ```
   *(Note: you can use `npm publish --dry-run` to preview what files will be included before actually publishing)*