stream-chat-react 13.9.0 → 13.10.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.
Files changed (55) hide show
  1. package/dist/components/ChannelPreview/hooks/useMessageDeliveryStatus.js +8 -3
  2. package/dist/components/Chat/hooks/useChat.js +1 -1
  3. package/dist/components/Dialog/ButtonWithSubmenu.d.ts +2 -2
  4. package/dist/components/Dialog/ButtonWithSubmenu.js +6 -6
  5. package/dist/components/Dialog/DialogAnchor.d.ts +5 -11
  6. package/dist/components/Dialog/DialogAnchor.js +22 -26
  7. package/dist/components/Dialog/DialogPortal.d.ts +2 -1
  8. package/dist/components/Dialog/DialogPortal.js +23 -7
  9. package/dist/components/Dialog/hooks/index.d.ts +1 -0
  10. package/dist/components/Dialog/hooks/useDialog.d.ts +4 -0
  11. package/dist/components/Dialog/hooks/useDialog.js +9 -1
  12. package/dist/components/Dialog/hooks/usePopoverPosition.d.ts +68 -0
  13. package/dist/components/Dialog/hooks/usePopoverPosition.js +54 -0
  14. package/dist/components/Form/Dropdown.d.ts +2 -2
  15. package/dist/components/Message/MessageRepliesCountButton.js +3 -1
  16. package/dist/components/Message/renderText/remarkPlugins/index.d.ts +1 -0
  17. package/dist/components/Message/renderText/remarkPlugins/index.js +1 -0
  18. package/dist/components/Message/renderText/remarkPlugins/keepLineBreaksPlugin.d.ts +10 -2
  19. package/dist/components/Message/renderText/remarkPlugins/keepLineBreaksPlugin.js +46 -26
  20. package/dist/components/Message/renderText/remarkPlugins/remarkIgnoreMarkdown.d.ts +8 -0
  21. package/dist/components/Message/renderText/remarkPlugins/remarkIgnoreMarkdown.js +11 -0
  22. package/dist/components/MessageActions/MessageActions.js +4 -4
  23. package/dist/components/MessageInput/AttachmentSelector.d.ts +1 -1
  24. package/dist/components/MessageInput/AttachmentSelector.js +9 -4
  25. package/dist/components/MessageList/hooks/useLastDeliveredData.js +5 -2
  26. package/dist/components/Modal/GlobalModal.js +2 -2
  27. package/dist/components/Reactions/ReactionSelectorWithButton.js +4 -4
  28. package/dist/components/Tooltip/Tooltip.d.ts +2 -2
  29. package/dist/components/Tooltip/Tooltip.js +11 -12
  30. package/dist/context/DialogManagerContext.d.ts +1 -0
  31. package/dist/context/DialogManagerContext.js +1 -0
  32. package/dist/css/v2/index.css +1 -1
  33. package/dist/css/v2/index.layout.css +1 -1
  34. package/dist/experimental/MessageActions/MessageActions.js +5 -5
  35. package/dist/experimental/index.browser.cjs +307 -238
  36. package/dist/experimental/index.browser.cjs.map +4 -4
  37. package/dist/experimental/index.node.cjs +307 -238
  38. package/dist/experimental/index.node.cjs.map +4 -4
  39. package/dist/index.browser.cjs +1415 -1307
  40. package/dist/index.browser.cjs.map +4 -4
  41. package/dist/index.node.cjs +1418 -1307
  42. package/dist/index.node.cjs.map +4 -4
  43. package/dist/plugins/Emojis/EmojiPicker.d.ts +9 -4
  44. package/dist/plugins/Emojis/EmojiPicker.js +10 -5
  45. package/dist/plugins/Emojis/index.browser.cjs +89 -29
  46. package/dist/plugins/Emojis/index.browser.cjs.map +4 -4
  47. package/dist/plugins/Emojis/index.node.cjs +89 -29
  48. package/dist/plugins/Emojis/index.node.cjs.map +4 -4
  49. package/dist/scss/v2/Message/Message-layout.scss +4 -0
  50. package/dist/scss/v2/MessageActionsBox/MessageActionsBox-layout.scss +1 -0
  51. package/package.json +7 -8
  52. package/dist/components/MessageActions/hooks/index.d.ts +0 -1
  53. package/dist/components/MessageActions/hooks/index.js +0 -1
  54. package/dist/components/MessageActions/hooks/useMessageActionsBoxPopper.d.ts +0 -18
  55. package/dist/components/MessageActions/hooks/useMessageActionsBoxPopper.js +0 -31
@@ -2,7 +2,7 @@ import React, { useCallback, useEffect, useRef, useState } from 'react';
2
2
  import { UploadIcon as DefaultUploadIcon } from './icons';
3
3
  import { useAttachmentManagerState } from './hooks/useAttachmentManagerState';
4
4
  import { CHANNEL_CONTAINER_ID } from '../Channel/constants';
5
- import { DialogAnchor, useDialog, useDialogIsOpen } from '../Dialog';
5
+ import { DialogAnchor, useDialogIsOpen, useDialogOnNearestManager } from '../Dialog';
6
6
  import { DialogMenuButton } from '../Dialog/DialogMenu';
7
7
  import { Modal as DefaultModal } from '../Modal';
8
8
  import { ShareLocationDialog as DefaultLocationDialog } from '../Location';
@@ -16,6 +16,7 @@ import clsx from 'clsx';
16
16
  import { useMessageComposer } from './hooks';
17
17
  export const SimpleAttachmentSelector = () => {
18
18
  const { AttachmentSelectorInitiationButtonContents, FileUploadIcon = DefaultUploadIcon, } = useComponentContext();
19
+ const { channelCapabilities } = useChannelStateContext();
19
20
  const inputRef = useRef(null);
20
21
  const [labelElement, setLabelElement] = useState(null);
21
22
  const id = useStableId();
@@ -33,6 +34,8 @@ export const SimpleAttachmentSelector = () => {
33
34
  labelElement.removeEventListener('keyup', handleKeyUp);
34
35
  };
35
36
  }, [labelElement]);
37
+ if (!channelCapabilities['upload-file'])
38
+ return null;
36
39
  return (React.createElement("div", { className: 'str-chat__file-input-container', "data-testid": 'file-upload-button' },
37
40
  React.createElement(UploadFileInput, { id: id, ref: inputRef }),
38
41
  React.createElement("label", { className: 'str-chat__file-input-label', htmlFor: id, ref: setLabelElement, tabIndex: 0 }, AttachmentSelectorInitiationButtonContents ? (React.createElement(AttachmentSelectorInitiationButtonContents, null)) : (React.createElement(FileUploadIcon, null)))));
@@ -119,8 +122,10 @@ export const AttachmentSelector = ({ attachmentSelectorActionSet = defaultAttach
119
122
  const messageComposer = useMessageComposer();
120
123
  const actions = useAttachmentSelectorActionsFiltered(attachmentSelectorActionSet);
121
124
  const menuDialogId = `attachment-actions-menu${messageComposer.threadId ? '-thread' : ''}`;
122
- const menuDialog = useDialog({ id: menuDialogId });
123
- const menuDialogIsOpen = useDialogIsOpen(menuDialogId);
125
+ const { dialog: menuDialog, dialogManager } = useDialogOnNearestManager({
126
+ id: menuDialogId,
127
+ });
128
+ const menuDialogIsOpen = useDialogIsOpen(menuDialogId, dialogManager?.id);
124
129
  const [modalContentAction, setModalContentActionAction] = useState();
125
130
  const openModal = useCallback((actionType) => {
126
131
  const action = actions.find((a) => a.type === actionType);
@@ -143,7 +148,7 @@ export const AttachmentSelector = ({ attachmentSelectorActionSet = defaultAttach
143
148
  channelCapabilities['upload-file'] && React.createElement(UploadFileInput, { ref: setFileInput }),
144
149
  React.createElement("button", { "aria-expanded": menuDialogIsOpen, "aria-haspopup": 'true', "aria-label": t('aria/Open Attachment Selector'), className: 'str-chat__attachment-selector__menu-button', "data-testid": 'invoke-attachment-selector-button', onClick: () => menuDialog?.toggle(), ref: menuButtonRef },
145
150
  React.createElement(AttachmentSelectorMenuInitButtonIcon, null)),
146
- React.createElement(DialogAnchor, { id: menuDialogId, placement: 'top-start', referenceElement: menuButtonRef.current, tabIndex: -1, trapFocus: true },
151
+ React.createElement(DialogAnchor, { dialogManagerId: dialogManager?.id, id: menuDialogId, placement: 'top-start', referenceElement: menuButtonRef.current, tabIndex: -1, trapFocus: true },
147
152
  React.createElement("div", { className: 'str-chat__attachment-selector-actions-menu str-chat__dialog-menu', "data-testid": 'attachment-selector-actions-menu' }, actions.map(({ ActionButton, type }) => (React.createElement(ActionButton, { closeMenu: menuDialog.close, key: `attachment-selector-item-${type}`, openModalForAction: openModal }))))),
148
153
  React.createElement(Portal, { getPortalDestination: getModalPortalDestination ?? getDefaultPortalDestination, isOpen: modalIsOpen },
149
154
  React.createElement(Modal, { className: clsx({
@@ -1,7 +1,7 @@
1
- import { useMemo } from 'react';
1
+ import { useCallback, useEffect, useState } from 'react';
2
2
  export const useLastDeliveredData = (props) => {
3
3
  const { channel, messages, returnAllReadData } = props;
4
- return useMemo(() => returnAllReadData
4
+ const calculate = useCallback(() => returnAllReadData
5
5
  ? messages.reduce((acc, msg) => {
6
6
  acc[msg.id] = channel.messageReceiptsTracker.deliveredForMessage({
7
7
  msgId: msg.id,
@@ -10,4 +10,7 @@ export const useLastDeliveredData = (props) => {
10
10
  return acc;
11
11
  }, {})
12
12
  : channel.messageReceiptsTracker.groupUsersByLastDeliveredMessage(), [channel, messages, returnAllReadData]);
13
+ const [deliveredTo, setDeliveredTo] = useState(calculate);
14
+ useEffect(() => channel.on('message.delivered', () => setDeliveredTo(calculate)).unsubscribe, [channel, calculate]);
15
+ return deliveredTo;
13
16
  };
@@ -3,7 +3,7 @@ import { useCallback } from 'react';
3
3
  import React, { useEffect, useRef } from 'react';
4
4
  import { FocusScope } from '@react-aria/focus';
5
5
  import { CloseIconRound } from './icons';
6
- import { useTranslationContext } from '../../context';
6
+ import { modalDialogManagerId, useTranslationContext } from '../../context';
7
7
  import { DialogPortalEntry, modalDialogId, useModalDialog, useModalDialogIsOpen, } from '../Dialog';
8
8
  export const GlobalModal = ({ children, className, onClose, onCloseAttempt, open, }) => {
9
9
  const { t } = useTranslationContext('Modal');
@@ -48,7 +48,7 @@ export const GlobalModal = ({ children, className, onClose, onCloseAttempt, open
48
48
  }, [dialog, open]);
49
49
  if (!open || !isOpen)
50
50
  return null;
51
- return (React.createElement(DialogPortalEntry, { dialogId: modalDialogId },
51
+ return (React.createElement(DialogPortalEntry, { dialogId: modalDialogId, dialogManagerId: modalDialogManagerId },
52
52
  React.createElement("div", { className: clsx('str-chat str-chat__modal str-chat-react__modal str-chat__modal--open', className), onClick: handleClick },
53
53
  React.createElement(FocusScope, { autoFocus: true, contain: true },
54
54
  React.createElement("button", { className: 'str-chat__modal__close-button', ref: closeButtonRef, title: t('Close'), type: 'button' },
@@ -1,6 +1,6 @@
1
1
  import React, { useRef } from 'react';
2
2
  import { ReactionSelector as DefaultReactionSelector } from './ReactionSelector';
3
- import { DialogAnchor, useDialog, useDialogIsOpen } from '../Dialog';
3
+ import { DialogAnchor, useDialogIsOpen, useDialogOnNearestManager } from '../Dialog';
4
4
  import { useComponentContext, useMessageContext, useTranslationContext, } from '../../context';
5
5
  /**
6
6
  * Internal convenience component - not to be exported. It just groups the button and the dialog anchor and thus prevents
@@ -13,10 +13,10 @@ export const ReactionSelectorWithButton = ({ ReactionIcon, }) => {
13
13
  const buttonRef = useRef(null);
14
14
  const dialogIdNamespace = threadList ? '-thread-' : '';
15
15
  const dialogId = `reaction-selector${dialogIdNamespace}--${message.id}`;
16
- const dialog = useDialog({ id: dialogId });
17
- const dialogIsOpen = useDialogIsOpen(dialogId);
16
+ const { dialog, dialogManager } = useDialogOnNearestManager({ id: dialogId });
17
+ const dialogIsOpen = useDialogIsOpen(dialogId, dialogManager?.id);
18
18
  return (React.createElement(React.Fragment, null,
19
- React.createElement(DialogAnchor, { id: dialogId, placement: isMyMessage() ? 'top-end' : 'top-start', referenceElement: buttonRef.current, trapFocus: true },
19
+ React.createElement(DialogAnchor, { dialogManagerId: dialogManager?.id, id: dialogId, placement: isMyMessage() ? 'top-end' : 'top-start', referenceElement: buttonRef.current, trapFocus: true },
20
20
  React.createElement(ReactionSelector, null)),
21
21
  React.createElement("button", { "aria-expanded": dialogIsOpen, "aria-label": t('aria/Open Reaction Selector'), className: 'str-chat__message-reactions-button', "data-testid": 'message-reaction-action', onClick: () => dialog?.toggle(), ref: buttonRef },
22
22
  React.createElement(ReactionIcon, { className: 'str-chat__message-action-icon' }))));
@@ -1,6 +1,6 @@
1
1
  import type { ComponentProps } from 'react';
2
2
  import React from 'react';
3
- import type { PopperProps } from 'react-popper';
3
+ import type { PopperLikePlacement } from '../Dialog';
4
4
  export declare const Tooltip: ({ children, ...rest }: ComponentProps<'div'>) => React.JSX.Element;
5
5
  export type PopperTooltipProps<T extends HTMLElement> = React.PropsWithChildren<{
6
6
  /** Reference element to which the tooltip should attach to */
@@ -8,7 +8,7 @@ export type PopperTooltipProps<T extends HTMLElement> = React.PropsWithChildren<
8
8
  /** Popper's modifier (offset) property - [xAxis offset, yAxis offset], default [0, 10] */
9
9
  offset?: [number, number];
10
10
  /** Popper's placement property defining default position of the tooltip, default 'top' */
11
- placement?: PopperProps<unknown>['placement'];
11
+ placement?: PopperLikePlacement;
12
12
  /** Tells component whether to render its contents */
13
13
  visible?: boolean;
14
14
  }>;
@@ -1,20 +1,19 @@
1
- import React, { useState } from 'react';
2
- import { usePopper } from 'react-popper';
1
+ import React, { useEffect, useState } from 'react';
2
+ import { usePopoverPosition } from '../Dialog/hooks/usePopoverPosition';
3
3
  export const Tooltip = ({ children, ...rest }) => (React.createElement("div", { className: 'str-chat__tooltip', ...rest }, children));
4
4
  export const PopperTooltip = ({ children, offset = [0, 10], placement = 'top', referenceElement, visible = false, }) => {
5
5
  const [popperElement, setPopperElement] = useState(null);
6
- const { attributes, styles } = usePopper(referenceElement, popperElement, {
7
- modifiers: [
8
- {
9
- name: 'offset',
10
- options: {
11
- offset,
12
- },
13
- },
14
- ],
6
+ const { placement: resolvedPlacement, refs, strategy, x, y, } = usePopoverPosition({
7
+ offset,
15
8
  placement,
16
9
  });
10
+ useEffect(() => {
11
+ refs.setReference(referenceElement);
12
+ }, [referenceElement, refs]);
13
+ useEffect(() => {
14
+ refs.setFloating(popperElement);
15
+ }, [popperElement, refs]);
17
16
  if (!visible)
18
17
  return null;
19
- return (React.createElement("div", { className: 'str-chat__tooltip', ref: setPopperElement, style: styles.popper, ...attributes.popper }, children));
18
+ return (React.createElement("div", { className: 'str-chat__tooltip', "data-placement": resolvedPlacement, ref: setPopperElement, style: { left: x ?? 0, position: strategy, top: y ?? 0 } }, children));
20
19
  };
@@ -25,4 +25,5 @@ export declare const useDialogManager: ({ dialogId, dialogManagerId, }?: UseDial
25
25
  export declare const modalDialogManagerId: "modal-dialog-manager";
26
26
  export declare const ModalDialogManagerProvider: ({ children }: PropsWithChildrenOnly) => React.JSX.Element;
27
27
  export declare const useModalDialogManager: () => DialogManager | undefined;
28
+ export declare const useNearestDialogManagerContext: () => DialogManagerProviderContextValue | undefined;
28
29
  export {};
@@ -121,3 +121,4 @@ export const useDialogManager = ({ dialogId, dialogManagerId, } = {}) => {
121
121
  export const modalDialogManagerId = 'modal-dialog-manager';
122
122
  export const ModalDialogManagerProvider = ({ children }) => (React.createElement(DialogManagerProvider, { id: modalDialogManagerId }, children));
123
123
  export const useModalDialogManager = () => useMemo(() => getDialogManager(modalDialogManagerId), []);
124
+ export const useNearestDialogManagerContext = () => useContext(DialogManagerProviderContext);