Skip to content

Commit 0c1b9ac

Browse files
committed
feat: replace SuggestionItem prop with suggestionItemComponents prop for SuggestionList
1 parent 7e5f19b commit 0c1b9ac

File tree

5 files changed

+49
-33
lines changed

5 files changed

+49
-33
lines changed

src/components/MessageInput/__tests__/EditMessageForm.test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -926,7 +926,7 @@ describe(`EditMessageForm`, () => {
926926
const CustomStateSetter = () => {
927927
const composer = useMessageComposerMock();
928928
useEffect(() => {
929-
composer.customDataManager.setData(customMessageData);
929+
composer.customDataManager.setMessageData(customMessageData);
930930
}, [composer]);
931931
};
932932
const { container, submit } = await renderComponent({
@@ -954,7 +954,7 @@ describe(`EditMessageForm`, () => {
954954
const CustomStateSetter = () => {
955955
const composer = useMessageComposerMock();
956956
useEffect(() => {
957-
composer.customDataManager.setData(customMessageData);
957+
composer.customDataManager.setMessageData(customMessageData);
958958
}, [composer]);
959959
};
960960
const { container, submit } = await renderComponent({

src/components/MessageInput/__tests__/MessageInput.test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -794,7 +794,7 @@ describe(`MessageInputFlat`, () => {
794794
const customMessageData = { customX: 'customX' };
795795
const CustomStateSetter = null;
796796

797-
customChannel.messageComposer.customDataManager.setData(customMessageData);
797+
customChannel.messageComposer.customDataManager.setMessageData(customMessageData);
798798
const { container, submit } = await renderComponent({
799799
customChannel,
800800
customClient,
@@ -823,7 +823,7 @@ describe(`MessageInputFlat`, () => {
823823
const overrideMock = jest.fn().mockImplementation(() => Promise.resolve());
824824
const { customChannel, customClient } = await setup();
825825
const customMessageData = { customX: 'customX' };
826-
customChannel.messageComposer.customDataManager.setData(customMessageData);
826+
customChannel.messageComposer.customDataManager.setMessageData(customMessageData);
827827
const { container, submit } = await renderComponent({
828828
customChannel,
829829
customClient,

src/components/TextareaComposer/SuggestionList/CommandItem.tsx

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,9 @@
11
import type { PropsWithChildren } from 'react';
22
import React from 'react';
3+
import type { CommandResponse } from 'stream-chat';
34

45
export type CommandItemProps = {
5-
entity: {
6-
/** Arguments of command */
7-
args?: string;
8-
/** Description of command */
9-
description?: string;
10-
/** Name of the command */
11-
name?: string;
12-
};
6+
entity: CommandResponse;
137
};
148

159
export const CommandItem = (props: PropsWithChildren<CommandItemProps>) => {

src/components/TextareaComposer/SuggestionList/SuggestionList.tsx

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import clsx from 'clsx';
22
import React, { useEffect, useState } from 'react';
3+
import type { CommandItemProps } from './CommandItem';
34
import { CommandItem } from './CommandItem';
5+
import type { EmoticonItemProps } from './EmoticonItem';
46
import { EmoticonItem } from './EmoticonItem';
7+
import type { SuggestionListItemComponentProps } from './SuggestionListItem';
58
import { SuggestionListItem as DefaultSuggestionListItem } from './SuggestionListItem';
69
import { UserItem } from './UserItem';
710
import { useComponentContext } from '../../../context/ComponentContext';
@@ -13,10 +16,15 @@ import type {
1316
TextComposerState,
1417
TextComposerSuggestion,
1518
} from 'stream-chat';
16-
import type { SuggestionItemProps } from './SuggestionListItem';
19+
import type { UserItemProps } from './UserItem';
20+
21+
type SuggestionTrigger = '/' | ':' | '@' | string;
1722

1823
export type SuggestionListProps = Partial<{
19-
SuggestionItem: React.ComponentType<SuggestionItemProps>;
24+
suggestionItemComponents: Record<
25+
SuggestionTrigger,
26+
React.ComponentType<SuggestionListItemComponentProps>
27+
>;
2028
className?: string;
2129
closeOnClickOutside?: boolean;
2230
containerClassName?: string;
@@ -34,18 +42,28 @@ const searchSourceStateSelector = (
3442
items: nextValue.items ?? [],
3543
});
3644

37-
export const defaultComponents = {
38-
'/': CommandItem,
39-
':': EmoticonItem,
40-
'@': UserItem,
41-
};
45+
export const defaultComponents: Record<
46+
SuggestionTrigger,
47+
React.ComponentType<SuggestionListItemComponentProps>
48+
> = {
49+
'/': (props: SuggestionListItemComponentProps) => (
50+
<CommandItem entity={props.entity as CommandItemProps['entity']} />
51+
),
52+
':': (props: SuggestionListItemComponentProps) => (
53+
<EmoticonItem entity={props.entity as EmoticonItemProps['entity']} />
54+
),
55+
'@': (props: SuggestionListItemComponentProps) => (
56+
<UserItem entity={props.entity as UserItemProps['entity']} />
57+
),
58+
} as const;
4259

4360
export const SuggestionList = ({
4461
className,
4562
closeOnClickOutside = true,
4663
containerClassName,
4764
focusedItemIndex,
4865
setFocusedItemIndex,
66+
suggestionItemComponents = defaultComponents,
4967
}: SuggestionListProps) => {
5068
const { AutocompleteSuggestionItem = DefaultSuggestionListItem } =
5169
useComponentContext();
@@ -56,8 +74,9 @@ export const SuggestionList = ({
5674
useStateStore(suggestions?.searchSource.state, searchSourceStateSelector) ?? {};
5775
const [container, setContainer] = useState<HTMLDivElement | null>(null);
5876

59-
// @ts-expect-error component type mismatch
60-
const component = suggestions?.trigger && defaultComponents[suggestions?.trigger];
77+
const component = suggestions?.trigger
78+
? suggestionItemComponents[suggestions?.trigger]
79+
: undefined;
6180

6281
useEffect(() => {
6382
if (!closeOnClickOutside || !suggestions || !container) return;

src/components/TextareaComposer/SuggestionList/SuggestionListItem.tsx

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,24 @@
11
import clsx from 'clsx';
22
import type { Ref } from 'react';
3-
import { useLayoutEffect } from 'react';
4-
import React, { useCallback, useRef } from 'react';
3+
import React, { useCallback, useLayoutEffect, useRef } from 'react';
54
import { useMessageComposer } from '../../MessageInput';
6-
import type { CommandResponse, TextComposerSuggestion, UserResponse } from 'stream-chat';
7-
import type { EmojiSearchIndexResult } from '../../MessageInput';
5+
import type { TextComposerSuggestion } from 'stream-chat';
6+
import type { UserItemProps } from './UserItem';
7+
import type { CommandItemProps } from './CommandItem';
8+
import type { EmoticonItemProps } from './EmoticonItem';
89

9-
export type SuggestionCommand = CommandResponse;
10-
export type SuggestionUser = UserResponse;
11-
export type SuggestionEmoji = EmojiSearchIndexResult;
12-
export type SuggestionItem = SuggestionUser | SuggestionCommand | SuggestionEmoji;
10+
export type DefaultSuggestionListItemEntity =
11+
| UserItemProps['entity']
12+
| CommandItemProps['entity']
13+
| EmoticonItemProps['entity'];
14+
15+
export type SuggestionListItemComponentProps = {
16+
entity: DefaultSuggestionListItemEntity | unknown;
17+
focused: boolean;
18+
};
1319

1420
export type SuggestionItemProps = {
15-
component: React.ComponentType<{
16-
entity: SuggestionItem;
17-
focused: boolean;
18-
}>;
21+
component: React.ComponentType<SuggestionListItemComponentProps>;
1922
item: TextComposerSuggestion;
2023
focused: boolean;
2124
className?: string;

0 commit comments

Comments
 (0)