stream-chat-react 13.1.1 → 13.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -136,7 +136,7 @@ const UnMemoizedChannelList = (props) => {
136
136
  [`${baseClass}--open`]: navOpen,
137
137
  });
138
138
  const showChannelList = (!searchActive && !searchIsActive) || additionalChannelSearchProps?.popupResults;
139
- return (React.createElement(ChannelListContextProvider, { value: { channels, setChannels } },
139
+ return (React.createElement(ChannelListContextProvider, { value: { channels, hasNextPage, loadNextPage, setChannels } },
140
140
  React.createElement("div", { className: className, ref: channelListRef },
141
141
  showChannelSearch &&
142
142
  (Search ? (React.createElement(Search, { directMessagingChannelType: additionalChannelSearchProps?.channelType, disabled: additionalChannelSearchProps?.disabled, exitSearchOnInputBlur: additionalChannelSearchProps?.clearSearchOnClickOutside, placeholder: additionalChannelSearchProps?.placeholder })) : (React.createElement(ChannelSearch, { onSearch: onSearch, onSearchExit: onSearchExit, setChannels: setChannels, ...additionalChannelSearchProps }))),
@@ -12,7 +12,7 @@ export type CustomQueryChannelsFn = (params: CustomQueryChannelParams) => Promis
12
12
  export declare const usePaginatedChannels: (client: StreamChat, filters: ChannelFilters, sort: ChannelSort, options: ChannelOptions, activeChannelHandler: (channels: Array<Channel>, setChannels: React.Dispatch<React.SetStateAction<Array<Channel>>>) => void, recoveryThrottleIntervalMs?: number, customQueryChannels?: CustomQueryChannelsFn) => {
13
13
  channels: Channel[];
14
14
  hasNextPage: boolean;
15
- loadNextPage: () => void;
15
+ loadNextPage: () => Promise<void>;
16
16
  setChannels: import("react").Dispatch<import("react").SetStateAction<Channel[]>>;
17
17
  };
18
18
  export {};
@@ -72,9 +72,7 @@ export const usePaginatedChannels = (client, filters, sort, options, activeChann
72
72
  lastRecoveryTimestamp.current = now;
73
73
  queryChannels('reload');
74
74
  }, [error, queryChannels, recoveryThrottleInterval]);
75
- const loadNextPage = () => {
76
- queryChannels();
77
- };
75
+ const loadNextPage = () => queryChannels();
78
76
  useEffect(() => {
79
77
  if (client.recoverStateOnReconnect)
80
78
  return;
@@ -24,7 +24,7 @@ export const useChat = ({ client, defaultLanguage = 'en', i18nInstance, initialN
24
24
  useEffect(() => {
25
25
  if (!client)
26
26
  return;
27
- const version = "13.1.1";
27
+ const version = "13.2.0";
28
28
  const userAgent = client.getUserAgent();
29
29
  if (!userAgent.includes('stream-chat-react')) {
30
30
  // result looks like: 'stream-chat-react-2.3.2-stream-chat-javascript-client-browser-2.2.2'
@@ -42,4 +42,4 @@ export type InfiniteScrollProps = PaginatorProps & {
42
42
  * In general, the infinite scroll controller should not aim for checking the loading state and whether there is more data to load.
43
43
  * That should be controlled by the loading function.
44
44
  */
45
- export declare const InfiniteScroll: (props: PropsWithChildren<InfiniteScrollProps>) => React.ReactElement<any, string | React.JSXElementConstructor<any>>;
45
+ export declare const InfiniteScroll: (props: PropsWithChildren<InfiniteScrollProps>) => React.JSX.Element;
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useRef } from 'react';
1
+ import React, { useEffect, useRef, useState } from 'react';
2
2
  import { deprecationAndReplacementWarning } from '../../utils/deprecationWarning';
3
3
  import { DEFAULT_LOAD_PAGE_SCROLL_THRESHOLD } from '../../constants/limits';
4
4
  /**
@@ -21,17 +21,17 @@ const mousewheelListener = (event) => {
21
21
  * That should be controlled by the loading function.
22
22
  */
23
23
  export const InfiniteScroll = (props) => {
24
- const { children, element = 'div', hasMore, hasMoreNewer, hasNextPage, hasPreviousPage, head, initialLoad = true, isLoading, listenToScroll, loader, loadMore, loadMoreNewer, loadNextPage, loadPreviousPage, threshold = DEFAULT_LOAD_PAGE_SCROLL_THRESHOLD, useCapture = false, ...elementProps } = props;
24
+ const { children, element: Component = 'div', hasMore, hasMoreNewer, hasNextPage, hasPreviousPage, head, initialLoad = true, isLoading, listenToScroll, loader, loadMore, loadMoreNewer, loadNextPage, loadPreviousPage, threshold = DEFAULT_LOAD_PAGE_SCROLL_THRESHOLD, useCapture = false, ...elementProps } = props;
25
25
  const loadNextPageFn = loadNextPage || loadMoreNewer;
26
26
  const loadPreviousPageFn = loadPreviousPage || loadMore;
27
27
  const hasNextPageFlag = hasNextPage || hasMoreNewer;
28
28
  const hasPreviousPageFlag = hasPreviousPage || hasMore;
29
- const scrollComponent = useRef(undefined);
29
+ const [scrollComponent, setScrollComponent] = useState(null);
30
30
  const previousOffset = useRef(undefined);
31
31
  const previousReverseOffset = useRef(undefined);
32
32
  const scrollListenerRef = useRef(undefined);
33
33
  scrollListenerRef.current = () => {
34
- const element = scrollComponent.current;
34
+ const element = scrollComponent;
35
35
  if (!element || element.offsetParent === null) {
36
36
  return;
37
37
  }
@@ -71,7 +71,7 @@ export const InfiniteScroll = (props) => {
71
71
  // eslint-disable-next-line react-hooks/exhaustive-deps
72
72
  }, []);
73
73
  useEffect(() => {
74
- const scrollElement = scrollComponent.current?.parentNode;
74
+ const scrollElement = scrollComponent?.parentNode;
75
75
  if (!scrollElement)
76
76
  return;
77
77
  const scrollListener = () => scrollListenerRef.current?.();
@@ -82,27 +82,18 @@ export const InfiniteScroll = (props) => {
82
82
  scrollElement.removeEventListener('scroll', scrollListener, useCapture);
83
83
  scrollElement.removeEventListener('resize', scrollListener, useCapture);
84
84
  };
85
- }, [initialLoad, useCapture]);
85
+ }, [initialLoad, scrollComponent, useCapture]);
86
86
  useEffect(() => {
87
- const scrollElement = scrollComponent.current?.parentNode;
88
- if (scrollElement) {
89
- scrollElement.addEventListener('wheel', mousewheelListener, { passive: false });
90
- }
87
+ const scrollElement = scrollComponent?.parentNode;
88
+ if (!scrollElement)
89
+ return;
90
+ scrollElement.addEventListener('wheel', mousewheelListener, { passive: false });
91
91
  return () => {
92
- if (scrollElement) {
93
- scrollElement.removeEventListener('wheel', mousewheelListener, useCapture);
94
- }
92
+ scrollElement.removeEventListener('wheel', mousewheelListener, useCapture);
95
93
  };
96
- }, [useCapture]);
97
- const attributes = {
98
- ...elementProps,
99
- ref: (element) => {
100
- scrollComponent.current = element;
101
- },
102
- };
103
- const childrenArray = [loader, children];
104
- if (head) {
105
- childrenArray.unshift(head);
106
- }
107
- return React.createElement(element, attributes, childrenArray);
94
+ }, [scrollComponent, useCapture]);
95
+ return (React.createElement(Component, { ...elementProps, ref: setScrollComponent },
96
+ head,
97
+ loader,
98
+ children));
108
99
  };
@@ -1,12 +1,11 @@
1
1
  import React, { useCallback, useMemo } from 'react';
2
- import { useActionHandler, useDeleteHandler, useUserRole } from './hooks';
2
+ import { useDeleteHandler, useUserRole } from './hooks';
3
3
  import { MessageDeleted as DefaultMessageDeleted } from './MessageDeleted';
4
4
  import { MessageTimestamp } from './MessageTimestamp';
5
5
  import { getMessageActions } from './utils';
6
6
  import { Avatar } from '../Avatar';
7
7
  import { Gallery } from '../Gallery';
8
8
  import { MessageActions } from '../MessageActions';
9
- import { MML } from '../MML';
10
9
  import { useChatContext } from '../../context/ChatContext';
11
10
  import { useComponentContext } from '../../context/ComponentContext';
12
11
  import { useMessageContext } from '../../context/MessageContext';
@@ -32,7 +31,6 @@ const UnMemoizedFixedHeightMessage = (props) => {
32
31
  const { userLanguage } = useTranslationContext('FixedHeightMessage');
33
32
  const groupedByUser = propGroupedByUser !== undefined ? propGroupedByUser : contextGroupedByUser;
34
33
  const message = propMessage || contextMessage;
35
- const handleAction = useActionHandler(message);
36
34
  const handleDelete = useDeleteHandler(message);
37
35
  const role = useUserRole(message);
38
36
  const messageTextToRender = message?.i18n?.[`${userLanguage}_text`] ||
@@ -52,7 +50,6 @@ const UnMemoizedFixedHeightMessage = (props) => {
52
50
  images && React.createElement(Gallery, { images: images }),
53
51
  React.createElement("div", { className: 'str-chat__virtual-message__text', "data-testid": 'msg-text' },
54
52
  renderedText,
55
- message.mml && (React.createElement(MML, { actionHandler: handleAction, align: 'left', source: message.mml })),
56
53
  React.createElement("div", { className: 'str-chat__virtual-message__data' },
57
54
  React.createElement(MessageActions, { customWrapperClass: 'str-chat__virtual-message__actions', getMessageActions: messageActionsHandler, handleDelete: handleDelete, message: message, mine: () => role.isMyMessage }),
58
55
  React.createElement("span", { className: 'str-chat__virtual-message__date' },
@@ -18,7 +18,6 @@ import { areMessageUIPropsEqual, isMessageBlocked, isMessageBounced, isMessageEd
18
18
  import { Avatar as DefaultAvatar } from '../Avatar';
19
19
  import { Attachment as DefaultAttachment } from '../Attachment';
20
20
  import { EditMessageModal } from '../MessageInput';
21
- import { MML } from '../MML';
22
21
  import { Poll } from '../Poll';
23
22
  import { ReactionsList as DefaultReactionList } from '../Reactions';
24
23
  import { MessageBounceModal } from '../MessageBounce/MessageBounceModal';
@@ -95,7 +94,6 @@ const MessageSimpleWithContext = (props) => {
95
94
  poll && React.createElement(Poll, { poll: poll }),
96
95
  message.attachments?.length && !message.quoted_message ? (React.createElement(Attachment, { actionHandler: handleAction, attachments: message.attachments })) : null,
97
96
  isAIGenerated ? (React.createElement(StreamedMessageText, { message: message, renderText: renderText })) : (React.createElement(MessageText, { message: message, renderText: renderText })),
98
- message.mml && (React.createElement(MML, { actionHandler: handleAction, align: isMyMessage() ? 'right' : 'left', source: message.mml })),
99
97
  React.createElement(MessageErrorIcon, null))),
100
98
  showReplyCountButton && (React.createElement(MessageRepliesCountButton, { onClick: handleOpenThread, reply_count: message.reply_count })),
101
99
  showIsReplyInChannel && React.createElement(MessageIsThreadReplyInChannelButtonIndicator, null),
@@ -1,6 +1,4 @@
1
- import debounce from 'lodash.debounce';
2
1
  import clsx from 'clsx';
3
- import { useMemo } from 'react';
4
2
  import React, { useCallback, useEffect, useRef, useState } from 'react';
5
3
  import Textarea from 'react-textarea-autosize';
6
4
  import { useMessageComposer } from '../MessageInput';
@@ -129,13 +127,13 @@ export const TextareaComposer = ({ className, closeSuggestionsOnClickOutside, co
129
127
  textComposer.closeSuggestions();
130
128
  }
131
129
  }, [onScroll, textComposer]);
132
- const setSelectionDebounced = useMemo(() => debounce((e) => {
130
+ const setSelectionDebounced = useCallback((e) => {
133
131
  onSelect?.(e);
134
132
  textComposer.setSelection({
135
133
  end: e.target.selectionEnd,
136
134
  start: e.target.selectionStart,
137
135
  });
138
- }, 100, { leading: false, trailing: true }), [onSelect, textComposer]);
136
+ }, [onSelect, textComposer]);
139
137
  useEffect(() => {
140
138
  // FIXME: find the real reason for cursor being set to the end on each change
141
139
  // This is a workaround to prevent the cursor from jumping
@@ -20,7 +20,6 @@ export * from './MessageActions';
20
20
  export type { MessageBouncePromptProps } from './MessageBounce';
21
21
  export * from './MessageInput';
22
22
  export * from './MessageList';
23
- export * from './MML';
24
23
  export * from './Modal';
25
24
  export * from './Notifications';
26
25
  export * from './Poll';
@@ -19,7 +19,6 @@ export * from './Message';
19
19
  export * from './MessageActions';
20
20
  export * from './MessageInput';
21
21
  export * from './MessageList';
22
- export * from './MML';
23
22
  export * from './Modal';
24
23
  export * from './Notifications';
25
24
  export * from './Poll';
@@ -7,6 +7,14 @@ export type ChannelListContextValue = {
7
7
  * Channels query is executed by default only by ChannelList component in the SDK.
8
8
  */
9
9
  channels: Channel[];
10
+ /**
11
+ * Indicator for channel pagination to determine whether more items can be loaded
12
+ */
13
+ hasNextPage: boolean;
14
+ /**
15
+ * Pagination function to load more channels
16
+ */
17
+ loadNextPage(): Promise<void>;
10
18
  /**
11
19
  * Sets the list of Channel objects to be rendered by ChannelList component.
12
20
  */