Skip to content

Commit

Permalink
fix(emoji-mart): simplify EmojiPicker & emojiSearchIndex (#2117)
Browse files Browse the repository at this point in the history
Fixes: #2116
Fixes: #2094

BREAKING CHANGE: `EmojiPicker` & `EmojiIndex` signatures changed, `EmojiIndex` has been renamed to `emojiSearchIndex`, both `EmojiPicker` & `emojiSearchIndex` are now optional, see [release guide](https://github.com/GetStream/stream-chat-react/blob/v11.0.0/docusaurus/docs/React/release-guides/upgrade-to-v11.mdx) for more information
BREAKING CHANGE: `useImageFlagEmojisOnWindow` flag now requires extra style sheet import, see [release guide](https://github.com/GetStream/stream-chat-react/blob/v11.0.0/docusaurus/docs/React/release-guides/upgrade-to-v11.mdx) for more information
  • Loading branch information
arnautov-anton committed Nov 27, 2023
1 parent 14bef23 commit a6e0a87
Show file tree
Hide file tree
Showing 61 changed files with 811 additions and 998 deletions.
14 changes: 13 additions & 1 deletion docusaurus/docs/React/basics/getting-started.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,14 @@ const { client } = useChatContext();
The [`Channel`](../components/core-components/channel.mdx) component is a React Context provider that wraps all of the logic, functionality, and UI for an individual chat channel.
It provides five separate contexts to its children:

:::caution
`EmojiContext` has been removed in version `11.0.0`, see related release guides (["Reactions 11.0.0"](../release-guides/reactions-v11.mdx), ["EmojiPicker 11.0.0"](../release-guides/emoji-picker-v11.mdx) and ["emojiSearchIndex 11.0.0"](../release-guides/emoji-search-index-v11.mdx)) to adjust your integration to this new change.
:::

- [`ChannelStateContext`](../components/contexts/channel-state-context.mdx) - stateful data (ex: `messages` or `members`)
- [`ChannelActionContext`](../components/contexts/channel-action-context.mdx) - action handlers (ex: `sendMessage` or `openThread`)
- [`ComponentContext`](../components/contexts/component-context.mdx) - custom component UI overrides (ex: `Avatar` or `Message`)
- [`EmojiContext`](../components/contexts/emoji-context.mdx) - emoji UI components and data (ex: `EmojiPicker` or `emojiConfig`)
- [`EmojiContext`](../components/contexts/emoji-context.mdx) - emoji UI components and data (ex: `EmojiPicker` or `emojiConfig`) - removed in `11.0.0`
- [`TypingContext`](../components/contexts/typing-context.mdx) - object of currently typing users (i.e., `typing`)

### ChannelList
Expand Down Expand Up @@ -172,6 +176,14 @@ The [`MessageInput`](../components/message-input-components/message-input.mdx) c

The [`Thread`](../components/core-components/thread.mdx) component renders a list of replies tied to a single parent message in a channel's main message list. A `Thread` maintains its own state and renders its own `MessageList` and `MessageInput` components.

### Emojis (picker & autocomplete)

The SDK is equipped with features designed to facilitate seamless integration, enabling developers to effortlessly incorporate emoji picker and emoji autocomplete (built on top of [`emoji-mart`](https://github.com/missive/emoji-mart)) functionalities for a comprehensive chat experience.

Starting from version `11.0.0`, these features are entirely optional, requiring integrators to opt-in manually. The decision was made in conjunction with enhanced architecture, aiming to reduce the overall size of the final bundles of our integrators.

Make sure to read ["EmojiPicker 11.0.0"](../release-guides/emoji-picker-v11.mdx) and ["emojiSearchIndex 11.0.0"](../release-guides/emoji-search-index-v11.mdx) release guides for more information.

## Summary

In addition to the above referenced UI components, client instantiation, and user connection, you need little other code to get a fully functioning chat application up and running. See below for an example of the complete code.
Expand Down
4 changes: 4 additions & 0 deletions docusaurus/docs/React/components/contexts/emoji-context.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ sidebar_position: 5
title: EmojiContext
---

:::caution
`EmojiContext` has been removed in version `11.0.0`, see related release guides (["Reactions 11.0.0"](../release-guides/reactions-v11.mdx), ["EmojiPicker 11.0.0"](../release-guides/emoji-picker-v11.mdx) and ["emojiSearchIndex 11.0.0"](../release-guides/emoji-search-index-v11.mdx)) to adjust your integration to this new change.
:::

The `EmojiContext` is established by the `Channel` component and exposes the `useEmojiContext` hook. This context holds
the UI components and stateful data necessary to render emoji selector functionality.

Expand Down
103 changes: 57 additions & 46 deletions docusaurus/docs/React/components/core-components/channel.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -296,45 +296,54 @@ Custom UI component to override default edit message input.
| --------- | ---------------------------------------------------------------------------------- |
| component | <GHComponentLink text='EditMessageForm' path='/MessageInput/EditMessageForm.tsx'/> |

### Emoji
### Emoji (removed in `11.0.0`)

Custom UI component to override default `NimbleEmoji` from `emoji-mart`.

| Type |
| --------- |
| component |

### emojiData
### emojiData (removed in `11.0.0`)

Custom prop to override default `facebook.json` emoji data set from `emoji-mart`.

| Type |
| ------ |
| object |

### EmojiIcon
### EmojiIcon (removed in `11.0.0`)

Custom UI component for emoji button in input.

| Type | Default |
| --------- | ----------------------------------------------------------------------- |
| component | <GHComponentLink text='EmojiIconSmall' path='/MessageInput/icons.tsx'/> |

### EmojiIndex
### EmojiIndex (removed in `11.0.0`)

Custom UI component to override default `NimbleEmojiIndex` from `emoji-mart`.
Custom search mechanism class to override default `NimbleEmojiIndex` class from `emoji-mart`.

| Type |
| --------- |
| component |
| Type | Default |
| ----- | ----------------------------------------------------------------------------------------------------------------- |
| class | [NimbleEmojiIndex](https://github.com/missive/emoji-mart/blob/v3.0.1/src/utils/emoji-index/nimble-emoji-index.js) |

### EmojiPicker
### emojiSearchIndex (available since `11.0.0`)

Custom UI component to override default `NimblePicker` from `emoji-mart`.
Custom search mechanism instance or object to enable emoji autocomplete. See ["emojiSearchIndex 11.0.0"](../../release-guides/emoji-search-index-v11.mdx) release guide for more information.

| Type |
| --------- |
| component |
| Type | Default |
| ------ | --------- |
| object | undefined |

### EmojiPicker (changed in `11.0.0`)

Custom UI component to override default `NimblePicker` from `emoji-mart`. Markup structure changed in `11.0.0`, see ["EmojiPicker 11.0.0"](../../release-guides/emoji-picker-v11.mdx) release guide for more information.

| Version | Type | Default |
| ------- | --------- | -------------------------------------------------------------------------------------------------------- |
| >=4.0.0 | component | [NimblePicker](https://github.com/missive/emoji-mart/blob/v3.0.1/src/components/picker/nimble-picker.js) |
| ^11.0.0 | component | undefined |

### EmptyPlaceholder

Expand Down Expand Up @@ -414,48 +423,50 @@ A custom function to provide size configuration for image attachments
Allows to prevent triggering the `channel.watch()` (triggers channel query HTTP request) call when mounting the `Channel` component (the default behavior) with uninitialized (`channel.initialized`) `Channel` instance. That means that no channel data from the back-end will be received neither channel WS events will be delivered to the client. Preventing to initialize the channel on mount allows us to postpone the channel creation in the Stream's DB to a later point in time, for example, when a first message is sent:

```typescript jsx
import {useCallback} from "react";
import { useCallback } from 'react';
import {
getChannel,
MessageInput as StreamMessageInput,
MessageInputProps, MessageToSend,
MessageInputProps,
MessageToSend,
useChannelActionContext,
useChatContext
} from "stream-chat-react";
import {Message, SendMessageOptions} from "stream-chat";
useChatContext,
} from 'stream-chat-react';
import { Message, SendMessageOptions } from 'stream-chat';

import {useChannelInitContext} from "../../context/ChannelInitProvider";
import type { MyStreamChatGenerics } from "../../types";
import { useChannelInitContext } from '../../context/ChannelInitProvider';
import type { MyStreamChatGenerics } from '../../types';

export const MessageInput = (props: MessageInputProps) => {
const {client} = useChatContext();
const {sendMessage} = useChannelActionContext();
const { setInitializedChannelOnMount} = useChannelInitContext();

const submitHandler: MessageInputProps['overrideSubmitHandler'] = useCallback(async (
message: MessageToSend<MyStreamChatGenerics>,
channelCid: string,
customMessageData?: Partial<Message<MyStreamChatGenerics>>,
options?: SendMessageOptions,
) => {
const [channelType, channelId] = channelCid.split(":");
const channel = client.channel(channelType, channelId);
if (!channel.initialized) {
await getChannel({channel, client});
setInitializedChannelOnMount(true);
}

await sendMessage(message, customMessageData, options);
}, [client, sendMessage, setInitializedChannelOnMount]);

return (
<StreamMessageInput {...props} overrideSubmitHandler={submitHandler} />
const { client } = useChatContext();
const { sendMessage } = useChannelActionContext();
const { setInitializedChannelOnMount } = useChannelInitContext();

const submitHandler: MessageInputProps['overrideSubmitHandler'] = useCallback(
async (
message: MessageToSend<MyStreamChatGenerics>,
channelCid: string,
customMessageData?: Partial<Message<MyStreamChatGenerics>>,
options?: SendMessageOptions,
) => {
const [channelType, channelId] = channelCid.split(':');
const channel = client.channel(channelType, channelId);
if (!channel.initialized) {
await getChannel({ channel, client });
setInitializedChannelOnMount(true);
}

await sendMessage(message, customMessageData, options);
},
[client, sendMessage, setInitializedChannelOnMount],
);

return <StreamMessageInput {...props} overrideSubmitHandler={submitHandler} />;
};
```

| Type | Default |
|---------|---------|
| ------- | ------- |
| boolean | true |

### Input
Expand Down Expand Up @@ -662,9 +673,9 @@ Custom UI component for send button.

You can turn on/off thumbnail generation for video attachments

| Type |
| --------- |
| `boolean` |
| Type |
| ------- |
| boolean |

### skipMessageDataMemoization

Expand Down
8 changes: 6 additions & 2 deletions docusaurus/docs/React/components/core-components/chat.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ const i18nInstance = new Streami18n({
});

<Chat client={client} i18nInstance={i18nInstance}>
{// children of Chat component}
</Chat>
{/* children of Chat component */}
</Chat>;
```

| Type |
Expand Down Expand Up @@ -123,6 +123,10 @@ Windows 10 does not support country flag emojis out of the box. It chooses to re
Stream Chat can override this behavior by loading a custom web font that will render images instead (PNGs or SVGs depending
on the platform). Set this prop to true if you want to use these custom emojis for Windows users.

:::caution
If you're moving from older versions to `11.0.0` then make sure to import related stylesheet from `stream-chat-react/css/v2/emoji-replacement.css` as it has been removed from our main stylesheet to reduce final bundle size for integrators who do not wish to use this feature.
:::

| Type | Default |
| ------- | ------- |
| boolean | false |
21 changes: 10 additions & 11 deletions docusaurus/docs/React/guides/channel-list-infinite-scroll.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,19 @@ import { ChannelList, InfiniteScroll } from 'stream-chat-react';
If you would like to adjust the configuration parameters like `threshold`, `reverse` (`PaginatorProps`) or `useCapture`, etc. (`InfiniteScrollProps`), you can create a wrapper component where these props can be set:

```tsx
import {
ChannelList,
InfiniteScroll,
InfiniteScrollProps
} from 'stream-chat-react';

import { ChannelList, InfiniteScroll, InfiniteScrollProps } from 'stream-chat-react';

const Paginator = (props: InfiniteScrollProps) => <InfiniteScroll {...props} threshold={50} />;

...
<ChannelList filters={filters} sort={sort} options={options}
Paginator={Paginator}
showChannelSearch
/>
// ...

<ChannelList
filters={filters}
sort={sort}
options={options}
Paginator={Paginator}
showChannelSearch
/>;
```

Especially the `threshold` prop may need to be set as the default is 250px. That may be too soon to load more channels.
Expand Down
19 changes: 8 additions & 11 deletions docusaurus/docs/React/guides/customization/emoji-picker.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,15 @@ title: Emoji Picker

import CustomEmojiPicker from '../../assets/CustomEmojiPicker.png';

In this example, we will demonstrate how to create a custom Emoji Picker component that can be used in the `MessageInput`.
This component will replace the default [`EmojiPicker`](https://github.com/GetStream/stream-chat-react/blob/master/src/components/MessageInput/EmojiPicker.tsx)
with only breakfast food emojis.
:::caution
Note that this guide is for versions lower than `11.0.0`, the new API has slightly changed. See the ["EmojiPicker 11.0.0"](../../release-guides/emoji-picker-v11.mdx) release guide to help you transition smoothly to the new API.
:::

In this example, we will demonstrate how to create a custom Emoji Picker component that can be used in the `MessageInput`. This component will replace the default [`EmojiPicker`](https://github.com/GetStream/stream-chat-react/blob/master/src/components/MessageInput/EmojiPicker.tsx) with only breakfast food emojis.

## Choose Your Emojis

The default `EmojiPicker` renders individual emoji objects using the [`NimbleEmoji`](https://github.com/missive/emoji-mart/blob/master/src/components/emoji/nimble-emoji.js)
component from [emoji-mart](https://www.npmjs.com/package/emoji-mart). Our custom set of emojis will need to follow the same `NimbleEmoji` props.
`NimbleEmoji` accepts an `emoji` prop, which pertains to either an object mapping of the emoji data or simply the ID (for IDs already existing
in `emoji-mart`). The object mapping of the `emoji` prop has the following type:
The default `EmojiPicker` renders individual emoji objects using the [`NimbleEmoji`](https://github.com/missive/emoji-mart/blob/v3.0.1/src/components/emoji/nimble-emoji.js) component from [emoji-mart](https://www.npmjs.com/package/emoji-mart). Our custom set of emojis will need to follow the same `NimbleEmoji` props. `NimbleEmoji` accepts an `emoji` prop, which pertains to either an object mapping of the emoji data or simply the ID (for IDs already existing in `emoji-mart`). The object mapping of the `emoji` prop has the following type:

```tsx
export interface BaseEmoji {
Expand All @@ -29,8 +28,7 @@ export interface BaseEmoji {
}
```

In this example we will use only the ID and select existing emojis. For a more detailed example of how to construct these emoji objects, please see the
[Reactions Selector and List](../theming/reactions.mdx) section. Below is the array of breakfast emojis we will use:
In this example we will use only the ID and select existing emojis. For a more detailed example of how to construct these emoji objects, please see the [Reactions Selector and List](../theming/reactions.mdx) section. Below is the array of breakfast emojis we will use:

```tsx
const customEmojis = ['fried_egg', 'croissant', 'bacon', 'waffle', 'pancakes', 'doughnut'];
Expand All @@ -43,8 +41,7 @@ loaded into the component library.

## Create the Custom Component

To construct our component, we will utilize the `EmojiContext` to get our `emojiConfig` data. This config object contains the `emojiData` we need for the
`data` prop on the `Emoji` component. Using the `onSelectEmoji` method from the `MessageInputContext`, we can add the onClick functionality to our custom picker.
To construct our component, we will utilize the `EmojiContext` to get our `emojiConfig` data. This config object contains the `emojiData` we need for the `data` prop on the `Emoji` component. Using the `onSelectEmoji` method from the `MessageInputContext`, we can add the onClick functionality to our custom picker.

:::note
The `Emoji` component needs to be wrapped in React's `Suspense` component because it is lazy loaded.
Expand Down
84 changes: 84 additions & 0 deletions docusaurus/docs/React/release-guides/emoji-picker-v11.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
---
id: emoji-picker-v11
sidebar_position: 3
title: EmojiPicker 11.0.0
keywords: [migration guide, upgrade, emoji picker, breaking changes, v11]
---

import GHComponentLink from '../_docusaurus-components/GHComponentLink';

## Dropping support for built-in `EmojiPicker`

By default - our SDK would ship with `emoji-mart` dependency on top of which our `EmojiPicker` component is built. And since the SDK is using `emoji-mart` for this component - it was also reused for reactions (`ReactionsList` and `ReactionSelector`) and suggestion list (`MessageInput`). This solution proved to be very uncomfortable to work with when it came to replacing either of the mentioned components (or disabling them completely) and the final applications using our SDK would still bundle certain `emoji-mart` parts which weren't needed (or seemingly "disabled") resulting in sub-optimal load times. Maintaining such architecture became a burden so we're switching things a bit.

## Changes to the default component composition (architecture)

SDK's `EmojiPicker` component now comes as two-part "bundle" - a button and an actual picker element. The component now holds its own `open` state which is handled by clicking the button (or anywhere else to close it).

## Switching to opt-in mechanism (BREAKING CHANGE)

We made `emoji-mart` package in our SDK completely optional which means that `EmojiPicker` component is now disabled by default.

### Reinstate the `EmojiPicker` component

To reinstate the previous behavior you'll have to add `emoji-mart` to your packages and make sure the packages come with versions that fit our peer-dependency requirements:

```bash
yarn add emoji-mart @emoji-mart/data @emoji-mart/react
```

Import `EmojiPicker` component from the `stream-chat-react` package:

```tsx
import { Channel } from 'stream-chat-react';
import { EmojiPicker } from 'stream-chat-react/emojis';

// and apply it to the Channel (component context)

const WrappedChannel = ({ children }) => {
return <Channel EmojiPicker={EmojiPicker}>{children}</Channel>;
};
```

### Build your custom `EmojiPicker` (with example)

If `emoji-mart` is too heavy for your use-case and you'd like to build your own you can certainly do so, here's a very simple `EmojiPicker` example built using `emoji-picker-react` package:

```tsx
import EmojiPicker from 'emoji-picker-react';
import { useMessageInputContext } from 'stream-chat-react';

export const CustomEmojiPicker = () => {
const [open, setOpen] = useState(false);

const { insertText, textareaRef } = useMessageInputContext();

return (
<>
<button onClick={() => setOpen((isOpen) => !isOpen)}>Open EmojiPicker</button>

{open && (
<EmojiPicker
onEmojiClick={(emoji, event) => {
insertText(emoji.native);
textareaRef.current?.focus(); // returns focus back to the message input element
}}
/>
)}
</>
);
};

// and pass it down to the `Channel` component
```

You can make the component slightly better using [`FloatingUI`](https://floating-ui.com/) by wrapping the actual picker element to make it float perfectly positioned above the button. See the source of the <GHComponentLink text="EmojiPicker" branch="feat/emoji-picker-delete" as="code" path="/Emojis/EmojiPicker.tsx" /> component which comes with the SDK for inspiration.

## Old `emoji-mart` (v3.0.1)

Even though it's not explicitly provided by our SDK anymore, it's still possible for our integrators to use older version of the `emoji-mart` - specifically version `3.0.1` on top of which our old components were built. We don't recommend using old version of the `emoji-mart` but if you really need to, follow the [`3.0.1` documentation](https://github.com/missive/emoji-mart/tree/v3.0.1#picker) in combination with the previous guide to build your own `EmojiPicker` component with the old `emoji-mart` API. Beware though, if you wish to use slightly modified `emoji-mart` CSS previously supplied by our SDK by default in the main `index.css` file, you'll now have to explicitly import it:

```tsx
import 'stream-chat-react/css/v2/index.css';
import 'stream-chat-react/css/v2/emoji-mart.css';
```
Loading

0 comments on commit a6e0a87

Please sign in to comment.