# @linktr.ee/messaging-react

React messaging components built on `@linktr.ee/messaging-core` for web applications.

## Features

- **Web-optimized**: Uses Tailwind CSS and web APIs for responsive design
- **Component-based**: Modular components that can be used individually or together
- **Stream Chat integration**: Built on Stream Chat React for reliable messaging
- **TypeScript**: Full type safety throughout

## Styling

Import the stylesheet once, and add this package to your Tailwind `content` so the components' utility classes are generated:

```ts
// app entry
import '@linktr.ee/messaging-react/styles.css'
```

```js
// tailwind.config.js
module.exports = {
  content: [
    './src/**/*.{ts,tsx}',
    './node_modules/@linktr.ee/messaging-react/dist/**/*.{js,cjs}',
  ],
}
```

The shipped `styles.css` carries only what Tailwind can't express (Stream DOM overrides, `::backdrop`/`@starting-style` dialog transitions, bubble-tail masks). Component chrome — including the media/PDF lightbox — is Tailwind on our JSX, so it renders only when your Tailwind build scans this package. Skipping the `content` entry leaves those components unstyled.

## Components

### MessagingShell

Renders a single direct conversation between the connected user and a
specific participant. For inbox-style surfaces that show many conversations,
compose `<ChannelList>` and `<ChannelView>` directly.

```tsx
import { MessagingShell, MessagingProvider } from '@linktr.ee/messaging-react'

;<MessagingProvider user={user} serviceConfig={config} apiKey={apiKey}>
  <MessagingShell
    initialParticipantFilter={otherAccountUuid}
    initialParticipantData={{
      id: otherAccountUuid,
      name: otherAccount.displayName,
    }}
    onChannelSelect={(channel) => trackChannelOpened(channel.id)}
  />
</MessagingProvider>
```

### Composing your own shell

For inbox surfaces, compose `<ChannelList>` and `<ChannelView>` directly:

```tsx
import { ChannelList, ChannelView } from '@linktr.ee/messaging-react'

;<div className="flex h-full">
  <div className="w-80 border-r">
    <ChannelList
      filters={{ type: 'messaging', members: { $in: [userId] } }}
      onChannelSelect={setSelectedChannel}
      selectedChannel={selectedChannel}
    />
  </div>
  <div className="flex-1">
    {selectedChannel ? <ChannelView channel={selectedChannel} /> : null}
  </div>
</div>
```

### Exports

Top-level exports from `@linktr.ee/messaging-react`:

- **Components**: `MessagingShell`, `ChannelList`, `ChannelView`, `Avatar`, `ActionButton`, `LinkAttachment`, `LockedAttachment`, `MessageAttachment`, `FaqList`, `FaqListItem`, `ChannelEmptyState`
- **Providers**: `MessagingProvider`, `CustomMessageProvider`
- **Hooks**: `useMessaging`, `useCustomMessage`
- **Utils**: `formatRelativeTime`, `getMessageDisplayText`, `normalizeLanguageCode`, `resolveParticipantDisplayName`, `isUuidLike`
- **Types**: `MessagingShellProps`, `ChannelListProps`, `ChannelViewProps`, `MessagingProviderProps`, `MessagingCapabilities`, `Participant`, plus per-attachment types

`MessagingCapabilities` currently only carries `showDeleteConversation`.
Pass it on `<MessagingProvider>` or `<MessagingShell>` to suppress the
"Delete conversation" action inside the channel info dialog.

## Architecture Benefits

- **Portability**: Works across different host environments (federated MFEs and standalone Next.js apps both consume the same components)
- **Consistency**: Maintains Linktree design system
- **Performance**: Web-optimized with lazy loading and pagination
- **Maintainability**: Clean separation between UI and business logic
