stream-chat-react 14.0.0-beta.2 → 14.0.0-beta.3
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.
- package/dist/{WithAudioPlayback-myzUS2m6.js → cjs/WithAudioPlayback.4a84360f.js} +4 -9
- package/dist/cjs/WithAudioPlayback.4a84360f.js.map +1 -0
- package/dist/{audioProcessing-BbOs2wMd.js → cjs/audioProcessing.56e5db9d.js} +1 -1
- package/dist/cjs/audioProcessing.56e5db9d.js.map +1 -0
- package/dist/cjs/emojis.js +1 -1
- package/dist/cjs/index.js +620 -225
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/mp3-encoder.js +1 -1
- package/dist/css/index.css +181 -26
- package/dist/css/index.css.map +1 -1
- package/dist/{WithAudioPlayback-C1hfFIcu.mjs → es/WithAudioPlayback.a3d5a2fc.mjs} +14 -19
- package/dist/es/WithAudioPlayback.a3d5a2fc.mjs.map +1 -0
- package/dist/{audioProcessing-ByEVSjGG.mjs → es/audioProcessing.21cb49e1.mjs} +1 -1
- package/dist/es/audioProcessing.21cb49e1.mjs.map +1 -0
- package/dist/es/emojis.mjs +1 -1
- package/dist/es/index.mjs +632 -237
- package/dist/es/index.mjs.map +1 -1
- package/dist/es/mp3-encoder.mjs +1 -1
- package/dist/types/components/Attachment/Giphy.d.ts.map +1 -1
- package/dist/types/components/Attachment/VoiceRecording.d.ts.map +1 -1
- package/dist/types/components/AudioPlayback/AudioPlayer.d.ts.map +1 -1
- package/dist/types/components/BaseImage/toBaseImageDescriptors.d.ts +1 -1
- package/dist/types/components/BaseImage/toBaseImageDescriptors.d.ts.map +1 -1
- package/dist/types/components/ChannelList/hooks/useMobileNavigation.d.ts.map +1 -1
- package/dist/types/components/ChannelListItem/ChannelListItemActionButtons.d.ts +3 -1
- package/dist/types/components/ChannelListItem/ChannelListItemActionButtons.d.ts.map +1 -1
- package/dist/types/components/ChannelListItem/ChannelListItemActionButtons.defaults.d.ts +6 -3
- package/dist/types/components/ChannelListItem/ChannelListItemActionButtons.defaults.d.ts.map +1 -1
- package/dist/types/components/Chat/hooks/useSplitActionSet.d.ts +5 -0
- package/dist/types/components/Chat/hooks/useSplitActionSet.d.ts.map +1 -1
- package/dist/types/components/Dialog/components/ContextMenu.d.ts +119 -3
- package/dist/types/components/Dialog/components/ContextMenu.d.ts.map +1 -1
- package/dist/types/components/Dialog/hooks/useDialog.d.ts +1 -1
- package/dist/types/components/Dialog/hooks/useDialog.d.ts.map +1 -1
- package/dist/types/components/Dialog/service/DialogAnchor.d.ts +14 -1
- package/dist/types/components/Dialog/service/DialogAnchor.d.ts.map +1 -1
- package/dist/types/components/Dialog/service/DialogManager.d.ts +14 -3
- package/dist/types/components/Dialog/service/DialogManager.d.ts.map +1 -1
- package/dist/types/components/Dialog/service/DialogPortal.d.ts.map +1 -1
- package/dist/types/components/Gallery/GalleryContext.d.ts +1 -1
- package/dist/types/components/Gallery/GalleryContext.d.ts.map +1 -1
- package/dist/types/components/MessageActions/MessageActions.d.ts +14 -3
- package/dist/types/components/MessageActions/MessageActions.d.ts.map +1 -1
- package/dist/types/components/MessageActions/MessageActions.defaults.d.ts +1 -1
- package/dist/types/components/MessageActions/MessageActions.defaults.d.ts.map +1 -1
- package/dist/types/components/MessageActions/QuickMessageActionButton.d.ts.map +1 -1
- package/dist/types/components/MessageActions/hooks/useBaseMessageActionSetFilter.d.ts.map +1 -1
- package/dist/types/components/MessageComposer/AttachmentSelector/AttachmentSelector.d.ts.map +1 -1
- package/dist/types/components/MessageList/hooks/MessageList/useScrollLocationLogic.d.ts +18 -0
- package/dist/types/components/MessageList/hooks/MessageList/useScrollLocationLogic.d.ts.map +1 -1
- package/dist/types/components/Poll/PollActions/PollResults/PollOptionWithVotes.d.ts.map +1 -1
- package/dist/types/components/Reactions/MessageReactions.d.ts.map +1 -1
- package/dist/types/components/Reactions/MessageReactionsDetail.d.ts +1 -0
- package/dist/types/components/Reactions/MessageReactionsDetail.d.ts.map +1 -1
- package/dist/types/components/Reactions/ReactionSelector.d.ts +1 -1
- package/dist/types/components/Reactions/ReactionSelector.d.ts.map +1 -1
- package/dist/types/components/TextareaComposer/SuggestionList/SuggestionList.d.ts.map +1 -1
- package/dist/types/components/TextareaComposer/TextareaComposer.d.ts.map +1 -1
- package/dist/types/context/ChannelListContext.d.ts +1 -1
- package/dist/types/context/ChannelListContext.d.ts.map +1 -1
- package/dist/types/context/ComponentContext.d.ts +5 -1
- package/dist/types/context/ComponentContext.d.ts.map +1 -1
- package/dist/types/context/DialogManagerContext.d.ts +11 -7
- package/dist/types/context/DialogManagerContext.d.ts.map +1 -1
- package/package.json +3 -1
- package/dist/WithAudioPlayback-C1hfFIcu.mjs.map +0 -1
- package/dist/WithAudioPlayback-myzUS2m6.js.map +0 -1
- package/dist/audioProcessing-BbOs2wMd.js.map +0 -1
- package/dist/audioProcessing-ByEVSjGG.mjs.map +0 -1
package/dist/es/index.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
2
2
|
import clsx from "clsx";
|
|
3
3
|
import { nanoid } from "nanoid";
|
|
4
|
-
import React, { useState, useEffect, useCallback, useLayoutEffect, useMemo, useContext, createContext, useRef, forwardRef,
|
|
5
|
-
import { u as useHandleFileChangeWrapper, d as dataTransferItemsToFiles, r as renderAudio, t as toAudioBuffer, c as createFileFromBlobs, g as getExtensionFromMimeType, a as getRecordedMediaTypeFromMimeType } from "
|
|
6
|
-
import { u as useStateStore, a as useMessageComposerController, i as isMessageBounced, b as useChannelActionContext, C as ComponentContext, c as useTranslationContext, d as useChannelStateContext, e as useChatContext, f as isNotificationForPanel, B as BaseIcon, g as Button, I as IconPause, h as IconPlaySolid, j as getDefaultExportFromCjs, k as defaultTranslatorFunction, p as predefinedFormatters, L as LocalizedFormat, l as calendar, m as IconLoadingCircle, n as isNetworkSendFailure, v as validateAndGetMessage, o as isUserMuted, q as defaultPinPermissions, r as useThreadContext, s as usePopoverPosition, t as useComponentContext, w as IconCrossMedium, x as IconPeople, y as IconExclamation, z as IconChevronRight, A as IconChevronLeft, D as IconArrowLeft, E as IconExclamationCircle, F as IconCircleBanSign, G as isMessageErrorRetryable, H as ACTIONS_NOT_WORKING_IN_THREAD, J as useNotificationTarget, K as IconArrowRightUp, M as addNotificationTargetTag, N as IconPin, O as mapToUserNameOrId, P as IconClock, Q as IconCheckmark1Small, R as IconDoubleCheckmark1Small, S as getReadByTooltipText, T as messageHasAttachments, U as messageTextHasEmojisOnly, V as isDate, W as getDateString, X as IconTranslate, Y as useMessageComposerContext, Z as useIsCooldownActive, _ as IconCrossSmall, $ as IconImages1Alt, a0 as IconChart5, a1 as IconMapPin, a2 as IconFileBend, a3 as IconChainLink, a4 as IconVideo, a5 as IconVideoSolid, a6 as IconMicrophone, a7 as IconBookmark, a8 as IconBellNotification, a9 as IconChevronDown, aa as IconPlusSmall, ab as IconCheckmark2, ac as DEFAULT_LOAD_PAGE_SCROLL_THRESHOLD, ad as IconTrophy, ae as IconDotGrid2x3, af as IconCircleMinus, ag as IconPaperPlane, ah as IconVolumeFull, ai as IconPeopleAdd, aj as IconMute, ak as IconFlag2, al as IconPeopleRemove, am as IconPaperclip, an as IconRunShortcut, ao as CHANNEL_CONTAINER_ID, ap as IconPlusLarge, aq as IconExclamationTriangle, ar as useAudioPlayer, as as IconArrowRotateClockwise, at as IconArrowDownCircle, au as IconThunder, av as IconTrashBin, aw as IconFileArrowLeftIn, ax as MessageComposerContextProvider, ay as useTypingContext, az as defaultDateTimeParser, aA as isLanguageSupported, aB as IconLayoutAlignLeft, aC as useChatViewContext, aD as MESSAGE_ACTIONS, aE as LegacyThreadContext, aF as IconArrowShareLeft, aG as IconEmojiSmile, aH as
|
|
7
|
-
import { bu, bx, dc, dd, de, df, dg, dh, bz, bC, by, bB, bD, di, bG, bH, bI, bJ, bK, bL, bM, bN, bO, bP, bQ, bR, bT, bS, bU, bV, bW, bX, bY, bZ, b_, b$, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, ca, cb, cc, cd, ce, cf, cg, ch, ci, cj, ck, cl, cm, cn, co, cp, cq, cr, cs, ct, cu, cv, cw, cx, cy, cz, cA, cB, cC, cD, cE, cF, cG, cH, cI, cJ, cK, cL, cM, cN, cO, cP, cQ, cR, cS, cT, cU, cV, cW, cX, cY, cZ, c_, dj, c$, da, db, dk, dl, dm, br, bF, bE, bs, bt, d0, d1, d7, d8, d4, d5, dn, d6, dp, d3, d2, bq, bA, bv, bw, d9 } from "
|
|
4
|
+
import React, { useState, useEffect, useCallback, useLayoutEffect, useMemo, useContext, createContext, useRef, forwardRef, createElement, Component, Fragment as Fragment$1 } from "react";
|
|
5
|
+
import { u as useHandleFileChangeWrapper, d as dataTransferItemsToFiles, r as renderAudio, t as toAudioBuffer, c as createFileFromBlobs, g as getExtensionFromMimeType, a as getRecordedMediaTypeFromMimeType } from "./audioProcessing.21cb49e1.mjs";
|
|
6
|
+
import { u as useStateStore, a as useMessageComposerController, i as isMessageBounced, b as useChannelActionContext, C as ComponentContext, c as useTranslationContext, d as useChannelStateContext, e as useChatContext, f as isNotificationForPanel, B as BaseIcon, g as Button, I as IconPause, h as IconPlaySolid, j as getDefaultExportFromCjs, k as defaultTranslatorFunction, p as predefinedFormatters, L as LocalizedFormat, l as calendar, m as IconLoadingCircle, n as isNetworkSendFailure, v as validateAndGetMessage, o as isUserMuted, q as defaultPinPermissions, r as useThreadContext, s as usePopoverPosition, t as useComponentContext, w as IconCrossMedium, x as IconPeople, y as IconExclamation, z as IconChevronRight, A as IconChevronLeft, D as IconArrowLeft, E as IconExclamationCircle, F as IconCircleBanSign, G as isMessageErrorRetryable, H as ACTIONS_NOT_WORKING_IN_THREAD, J as useNotificationTarget, K as IconArrowRightUp, M as addNotificationTargetTag, N as IconPin, O as mapToUserNameOrId, P as IconClock, Q as IconCheckmark1Small, R as IconDoubleCheckmark1Small, S as getReadByTooltipText, T as messageHasAttachments, U as messageTextHasEmojisOnly, V as isDate, W as getDateString, X as IconTranslate, Y as useMessageComposerContext, Z as useIsCooldownActive, _ as IconCrossSmall, $ as IconImages1Alt, a0 as IconChart5, a1 as IconMapPin, a2 as IconFileBend, a3 as IconChainLink, a4 as IconVideo, a5 as IconVideoSolid, a6 as IconMicrophone, a7 as IconBookmark, a8 as IconBellNotification, a9 as IconChevronDown, aa as IconPlusSmall, ab as IconCheckmark2, ac as DEFAULT_LOAD_PAGE_SCROLL_THRESHOLD, ad as IconTrophy, ae as IconDotGrid2x3, af as IconCircleMinus, ag as IconPaperPlane, ah as IconVolumeFull, ai as IconPeopleAdd, aj as IconMute, ak as IconFlag2, al as IconPeopleRemove, am as IconPaperclip, an as IconRunShortcut, ao as CHANNEL_CONTAINER_ID, ap as IconPlusLarge, aq as IconExclamationTriangle, ar as useAudioPlayer, as as IconArrowRotateClockwise, at as IconArrowDownCircle, au as IconThunder, av as IconTrashBin, aw as IconFileArrowLeftIn, ax as MessageComposerContextProvider, ay as useTypingContext, az as defaultDateTimeParser, aA as isLanguageSupported, aB as IconLayoutAlignLeft, aC as useChatViewContext, aD as MESSAGE_ACTIONS, aE as LegacyThreadContext, aF as IconArrowShareLeft, aG as IconEmojiSmile, aH as IconDotGrid1x3Horizontal, aI as IconPeopleAdded, aJ as IconBookmarkRemove, aK as IconBellOff, aL as IconBubbleWideNotificationChatMessage, aM as IconEditBig, aN as IconSquareBehindSquare2_Copy, aO as IconUnpin, aP as IconCloseQuote2, aQ as IconBubbleText6ChatMessage, aR as areMessageUIPropsEqual, aS as isDateSeparatorMessage, aT as isMessageBlocked, aU as messageHasSingleAttachment, aV as messageHasGiphyAttachment, aW as messageHasReactions, aX as isMessageEdited, aY as countEmojis, aZ as areMessagePropsEqual, a_ as getMessageActions, a$ as processMessages, b0 as insertIntro, b1 as getGroupStyles, b2 as getLastReceived, b3 as IconArrowUp, b4 as isIntroMessage, b5 as isLocalMessage, b6 as getIsFirstUnreadMessage, b7 as IconArrowDown, b8 as DEFAULT_NEXT_CHANNEL_PAGE_SIZE, b9 as EmptyStateIndicator, ba as getChannel, bb as IconMagnifyingGlassSearch, bc as IconCircleX, bd as useChannelListContext, be as DEFAULT_JUMP_TO_PAGE_SIZE, bf as ChannelListContextProvider, bg as IconArchive, bh as IconArrowBoxLeft, bi as IconCamera1, bj as IconExclamationCircle1, bk as ChatProvider, bl as TranslationProvider, bm as useThreadsViewContext, bn as IconBubbles, bo as IconArrowRotateRightLeftRepeatRefresh, bp as IconEyeOpen } from "./WithAudioPlayback.a3d5a2fc.mjs";
|
|
7
|
+
import { bu, bx, dc, dd, de, df, dg, dh, bz, bC, by, bB, bD, di, bG, bH, bI, bJ, bK, bL, bM, bN, bO, bP, bQ, bR, bT, bS, bU, bV, bW, bX, bY, bZ, b_, b$, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, ca, cb, cc, cd, ce, cf, cg, ch, ci, cj, ck, cl, cm, cn, co, cp, cq, cr, cs, ct, cu, cv, cw, cx, cy, cz, cA, cB, cC, cD, cE, cF, cG, cH, cI, cJ, cK, cL, cM, cN, cO, cP, cQ, cR, cS, cT, cU, cV, cW, cX, cY, cZ, c_, dj, c$, da, db, dk, dl, dm, br, bF, bE, bs, bt, d0, d1, d7, d8, d4, d5, dn, d6, dp, d3, d2, bq, bA, bv, bw, d9 } from "./WithAudioPlayback.a3d5a2fc.mjs";
|
|
8
8
|
import { StateStore, formatMessage, MessageComposer as MessageComposer$1, isGiphyAttachment, isScrapedContent, isLocalVideoAttachment, isVideoAttachment, isLocalImageAttachment, isImageAttachment, isAudioAttachment, isVoiceRecordingAttachment, isFileAttachment, isVoteAnswer, VotingVisibility, isLocalVoiceRecordingAttachment, isLocalAudioAttachment, isLocalFileAttachment, isLocalAttachment, LinkPreviewsManager, SearchController, ChannelSearchSource, UserSearchSource, MessageSearchSource, StreamChat, isSharedLocationResponse, LiveLocationManager } from "stream-chat";
|
|
9
9
|
import throttle from "lodash.throttle";
|
|
10
10
|
import * as linkify from "linkifyjs";
|
|
@@ -19,7 +19,6 @@ import { visit, SKIP } from "unist-util-visit";
|
|
|
19
19
|
import i18n from "i18next";
|
|
20
20
|
import Dayjs from "dayjs";
|
|
21
21
|
import uniqBy from "lodash.uniqby";
|
|
22
|
-
import { match, P } from "ts-pattern";
|
|
23
22
|
import { useSyncExternalStore } from "use-sync-external-store/shim";
|
|
24
23
|
import debounce from "lodash.debounce";
|
|
25
24
|
import fixWebmDuration from "fix-webm-duration";
|
|
@@ -72,10 +71,11 @@ const useAIState = (channel) => {
|
|
|
72
71
|
return { aiState };
|
|
73
72
|
};
|
|
74
73
|
class DialogManager {
|
|
75
|
-
constructor({ id } = {}) {
|
|
74
|
+
constructor({ closeOnClickOutside = true, id } = {}) {
|
|
76
75
|
this.state = new StateStore({
|
|
77
76
|
dialogsById: {}
|
|
78
77
|
});
|
|
78
|
+
this.closeOnClickOutside = closeOnClickOutside;
|
|
79
79
|
this.id = id ?? nanoid();
|
|
80
80
|
}
|
|
81
81
|
get openDialogCount() {
|
|
@@ -90,13 +90,14 @@ class DialogManager {
|
|
|
90
90
|
get(id) {
|
|
91
91
|
return this.state.getLatestValue().dialogsById[id];
|
|
92
92
|
}
|
|
93
|
-
getOrCreate({ id }) {
|
|
93
|
+
getOrCreate({ closeOnClickOutside, id }) {
|
|
94
94
|
let dialog = this.state.getLatestValue().dialogsById[id];
|
|
95
95
|
if (!dialog) {
|
|
96
96
|
dialog = {
|
|
97
97
|
close: () => {
|
|
98
98
|
this.close(id);
|
|
99
99
|
},
|
|
100
|
+
closeOnClickOutside,
|
|
100
101
|
id,
|
|
101
102
|
isOpen: false,
|
|
102
103
|
open: () => {
|
|
@@ -112,21 +113,22 @@ class DialogManager {
|
|
|
112
113
|
};
|
|
113
114
|
this.state.next((current) => ({
|
|
114
115
|
...current,
|
|
115
|
-
|
|
116
|
+
dialogsById: { ...current.dialogsById, [id]: dialog }
|
|
116
117
|
}));
|
|
117
118
|
}
|
|
118
|
-
|
|
119
|
-
|
|
119
|
+
const shouldUpdateDialogSettings = dialog.closeOnClickOutside !== closeOnClickOutside || !!dialog.removalTimeout;
|
|
120
|
+
if (shouldUpdateDialogSettings) {
|
|
121
|
+
if (dialog.removalTimeout) clearTimeout(dialog.removalTimeout);
|
|
122
|
+
dialog = {
|
|
123
|
+
...dialog,
|
|
124
|
+
closeOnClickOutside,
|
|
125
|
+
removalTimeout: void 0
|
|
126
|
+
};
|
|
120
127
|
this.state.next((current) => ({
|
|
121
128
|
...current,
|
|
122
|
-
|
|
123
|
-
dialogsById
|
|
124
|
-
|
|
125
|
-
[id]: {
|
|
126
|
-
...dialog,
|
|
127
|
-
removalTimeout: void 0
|
|
128
|
-
}
|
|
129
|
-
}
|
|
129
|
+
dialogsById: {
|
|
130
|
+
...current.dialogsById,
|
|
131
|
+
[id]: dialog
|
|
130
132
|
}
|
|
131
133
|
}));
|
|
132
134
|
}
|
|
@@ -203,7 +205,11 @@ class DialogManager {
|
|
|
203
205
|
}));
|
|
204
206
|
}
|
|
205
207
|
}
|
|
206
|
-
const useDialog = ({
|
|
208
|
+
const useDialog = ({
|
|
209
|
+
closeOnClickOutside,
|
|
210
|
+
dialogManagerId,
|
|
211
|
+
id
|
|
212
|
+
}) => {
|
|
207
213
|
const { dialogManager } = useDialogManager({ dialogManagerId });
|
|
208
214
|
useEffect(
|
|
209
215
|
() => () => {
|
|
@@ -211,7 +217,7 @@ const useDialog = ({ dialogManagerId, id }) => {
|
|
|
211
217
|
},
|
|
212
218
|
[dialogManager, id]
|
|
213
219
|
);
|
|
214
|
-
return dialogManager.getOrCreate({ id });
|
|
220
|
+
return dialogManager.getOrCreate({ closeOnClickOutside, id });
|
|
215
221
|
};
|
|
216
222
|
const useDialogOnNearestManager = ({ id }) => {
|
|
217
223
|
const { dialogManager } = useNearestDialogManagerContext() ?? {};
|
|
@@ -258,9 +264,37 @@ const Portal = ({
|
|
|
258
264
|
if (!portalDestination) return null;
|
|
259
265
|
return createPortal(children, portalDestination);
|
|
260
266
|
};
|
|
267
|
+
const shouldCloseOnOutsideClick = ({
|
|
268
|
+
dialog,
|
|
269
|
+
managerCloseOnClickOutside
|
|
270
|
+
}) => dialog.closeOnClickOutside ?? managerCloseOnClickOutside;
|
|
261
271
|
const DialogPortalDestination = () => {
|
|
262
272
|
const { dialogManager } = useNearestDialogManagerContext() ?? {};
|
|
263
273
|
const openedDialogCount = useOpenedDialogCount({ dialogManagerId: dialogManager?.id });
|
|
274
|
+
const [destinationRoot, setDestinationRoot] = useState(null);
|
|
275
|
+
useEffect(() => {
|
|
276
|
+
if (!destinationRoot || !dialogManager) return;
|
|
277
|
+
const handleDocumentClick = (event) => {
|
|
278
|
+
if (destinationRoot.contains(event.target)) return;
|
|
279
|
+
setTimeout(() => {
|
|
280
|
+
Object.values(dialogManager.state.getLatestValue().dialogsById).forEach(
|
|
281
|
+
(dialog) => {
|
|
282
|
+
if (!dialog.isOpen) return;
|
|
283
|
+
if (!shouldCloseOnOutsideClick({
|
|
284
|
+
dialog,
|
|
285
|
+
managerCloseOnClickOutside: dialogManager.closeOnClickOutside
|
|
286
|
+
}))
|
|
287
|
+
return;
|
|
288
|
+
dialogManager.close(dialog.id);
|
|
289
|
+
}
|
|
290
|
+
);
|
|
291
|
+
}, 0);
|
|
292
|
+
};
|
|
293
|
+
document.addEventListener("click", handleDocumentClick, { capture: true });
|
|
294
|
+
return () => {
|
|
295
|
+
document.removeEventListener("click", handleDocumentClick, { capture: true });
|
|
296
|
+
};
|
|
297
|
+
}, [destinationRoot, dialogManager]);
|
|
264
298
|
if (!openedDialogCount) return null;
|
|
265
299
|
return /* @__PURE__ */ jsx(
|
|
266
300
|
"div",
|
|
@@ -268,7 +302,22 @@ const DialogPortalDestination = () => {
|
|
|
268
302
|
className: "str-chat__dialog-overlay",
|
|
269
303
|
"data-str-chat__portal-id": dialogManager?.id,
|
|
270
304
|
"data-testid": "str-chat__dialog-overlay",
|
|
271
|
-
onClick: () =>
|
|
305
|
+
onClick: (event) => {
|
|
306
|
+
if (!dialogManager) return;
|
|
307
|
+
if (event.target !== event.currentTarget) return;
|
|
308
|
+
Object.values(dialogManager.state.getLatestValue().dialogsById).forEach(
|
|
309
|
+
(dialog) => {
|
|
310
|
+
if (!dialog.isOpen) return;
|
|
311
|
+
if (!shouldCloseOnOutsideClick({
|
|
312
|
+
dialog,
|
|
313
|
+
managerCloseOnClickOutside: dialogManager.closeOnClickOutside
|
|
314
|
+
}))
|
|
315
|
+
return;
|
|
316
|
+
dialogManager.close(dialog.id);
|
|
317
|
+
}
|
|
318
|
+
);
|
|
319
|
+
},
|
|
320
|
+
ref: setDestinationRoot,
|
|
272
321
|
style: {
|
|
273
322
|
"--str-chat__dialog-overlay-height": openedDialogCount > 0 ? "100%" : "0"
|
|
274
323
|
}
|
|
@@ -290,11 +339,16 @@ const DialogPortalEntry = ({
|
|
|
290
339
|
};
|
|
291
340
|
const dialogManagersRegistry = new StateStore({});
|
|
292
341
|
const getDialogManager = (id) => dialogManagersRegistry.getLatestValue()[id];
|
|
293
|
-
const getOrCreateDialogManager = (
|
|
342
|
+
const getOrCreateDialogManager = ({
|
|
343
|
+
closeOnClickOutside,
|
|
344
|
+
id
|
|
345
|
+
}) => {
|
|
294
346
|
let manager = getDialogManager(id);
|
|
295
347
|
if (!manager) {
|
|
296
|
-
manager = new DialogManager({ id });
|
|
348
|
+
manager = new DialogManager({ closeOnClickOutside, id });
|
|
297
349
|
dialogManagersRegistry.partialNext({ [id]: manager });
|
|
350
|
+
} else if (typeof closeOnClickOutside === "boolean") {
|
|
351
|
+
manager.closeOnClickOutside = closeOnClickOutside;
|
|
298
352
|
}
|
|
299
353
|
return manager;
|
|
300
354
|
};
|
|
@@ -305,20 +359,21 @@ const removeDialogManager = (id) => {
|
|
|
305
359
|
const DialogManagerProviderContext = React.createContext(void 0);
|
|
306
360
|
const DialogManagerProvider = ({
|
|
307
361
|
children,
|
|
362
|
+
closeOnClickOutside,
|
|
308
363
|
id
|
|
309
364
|
}) => {
|
|
310
365
|
const [dialogManager, setDialogManager] = useState(() => {
|
|
311
366
|
if (id) return getDialogManager(id) ?? null;
|
|
312
|
-
return new DialogManager();
|
|
367
|
+
return new DialogManager({ closeOnClickOutside });
|
|
313
368
|
});
|
|
314
369
|
useEffect(() => {
|
|
315
370
|
if (!id) return;
|
|
316
|
-
setDialogManager(getOrCreateDialogManager(id));
|
|
371
|
+
setDialogManager(getOrCreateDialogManager({ closeOnClickOutside, id }));
|
|
317
372
|
return () => {
|
|
318
373
|
removeDialogManager(id);
|
|
319
374
|
setDialogManager(null);
|
|
320
375
|
};
|
|
321
|
-
}, [id]);
|
|
376
|
+
}, [closeOnClickOutside, id]);
|
|
322
377
|
if (!dialogManager) return null;
|
|
323
378
|
return /* @__PURE__ */ jsxs(DialogManagerProviderContext.Provider, { value: { dialogManager }, children: [
|
|
324
379
|
children,
|
|
@@ -9037,6 +9092,7 @@ function useDialogAnchor({
|
|
|
9037
9092
|
setPopperElement(null);
|
|
9038
9093
|
}
|
|
9039
9094
|
return {
|
|
9095
|
+
placement: stabilisedChosenPlacement ?? chosenPlacement,
|
|
9040
9096
|
setPopperElement,
|
|
9041
9097
|
styles: {
|
|
9042
9098
|
left: x ?? 0,
|
|
@@ -9049,6 +9105,8 @@ const DialogAnchor = ({
|
|
|
9049
9105
|
allowFlip = true,
|
|
9050
9106
|
children,
|
|
9051
9107
|
className,
|
|
9108
|
+
closeOnClickOutside,
|
|
9109
|
+
closeTransitionMs = 0,
|
|
9052
9110
|
dialogManagerId,
|
|
9053
9111
|
focus = true,
|
|
9054
9112
|
id,
|
|
@@ -9061,12 +9119,44 @@ const DialogAnchor = ({
|
|
|
9061
9119
|
updatePositionOnContentResize,
|
|
9062
9120
|
...restDivProps
|
|
9063
9121
|
}) => {
|
|
9064
|
-
const dialog = useDialog({ dialogManagerId, id });
|
|
9122
|
+
const dialog = useDialog({ closeOnClickOutside, dialogManagerId, id });
|
|
9065
9123
|
const open = useDialogIsOpen(id, dialogManagerId);
|
|
9066
|
-
const
|
|
9124
|
+
const [shouldRender, setShouldRender] = useState(open);
|
|
9125
|
+
const closeTimeoutRef = useRef(null);
|
|
9126
|
+
const isClosing = !open && shouldRender;
|
|
9127
|
+
useEffect(() => {
|
|
9128
|
+
if (open) {
|
|
9129
|
+
setShouldRender(true);
|
|
9130
|
+
if (closeTimeoutRef.current) {
|
|
9131
|
+
clearTimeout(closeTimeoutRef.current);
|
|
9132
|
+
closeTimeoutRef.current = null;
|
|
9133
|
+
}
|
|
9134
|
+
return;
|
|
9135
|
+
}
|
|
9136
|
+
if (!shouldRender) return;
|
|
9137
|
+
if (!closeTransitionMs) {
|
|
9138
|
+
setShouldRender(false);
|
|
9139
|
+
return;
|
|
9140
|
+
}
|
|
9141
|
+
closeTimeoutRef.current = setTimeout(() => {
|
|
9142
|
+
setShouldRender(false);
|
|
9143
|
+
closeTimeoutRef.current = null;
|
|
9144
|
+
}, closeTransitionMs);
|
|
9145
|
+
}, [closeTransitionMs, open, shouldRender]);
|
|
9146
|
+
useEffect(
|
|
9147
|
+
() => () => {
|
|
9148
|
+
if (closeTimeoutRef.current) clearTimeout(closeTimeoutRef.current);
|
|
9149
|
+
},
|
|
9150
|
+
[]
|
|
9151
|
+
);
|
|
9152
|
+
const {
|
|
9153
|
+
placement: chosenPlacement,
|
|
9154
|
+
setPopperElement,
|
|
9155
|
+
styles
|
|
9156
|
+
} = useDialogAnchor({
|
|
9067
9157
|
allowFlip,
|
|
9068
9158
|
offset,
|
|
9069
|
-
open,
|
|
9159
|
+
open: shouldRender,
|
|
9070
9160
|
placement,
|
|
9071
9161
|
referenceElement,
|
|
9072
9162
|
updateKey,
|
|
@@ -9083,7 +9173,7 @@ const DialogAnchor = ({
|
|
|
9083
9173
|
document.removeEventListener("keyup", hideOnEscape);
|
|
9084
9174
|
};
|
|
9085
9175
|
}, [dialog, open]);
|
|
9086
|
-
if (!
|
|
9176
|
+
if (!shouldRender) {
|
|
9087
9177
|
return null;
|
|
9088
9178
|
}
|
|
9089
9179
|
return /* @__PURE__ */ jsx(DialogPortalEntry, { dialogId: id, dialogManagerId, children: /* @__PURE__ */ jsx(FocusScope, { autoFocus: focus, contain: trapFocus, restoreFocus: true, children: /* @__PURE__ */ jsx(
|
|
@@ -9091,6 +9181,8 @@ const DialogAnchor = ({
|
|
|
9091
9181
|
{
|
|
9092
9182
|
...restDivProps,
|
|
9093
9183
|
className: clsx("str-chat__dialog-contents", className),
|
|
9184
|
+
"data-str-chat-dialog-state": isClosing ? "closing" : "open",
|
|
9185
|
+
"data-str-chat-placement": chosenPlacement,
|
|
9094
9186
|
"data-testid": "str-chat__dialog-contents",
|
|
9095
9187
|
ref: setPopperElement,
|
|
9096
9188
|
style: styles,
|
|
@@ -9433,16 +9525,152 @@ const EmojiContextMenuButton = ({
|
|
|
9433
9525
|
]
|
|
9434
9526
|
}
|
|
9435
9527
|
);
|
|
9436
|
-
const
|
|
9437
|
-
|
|
9438
|
-
|
|
9439
|
-
|
|
9528
|
+
const ContextMenuButtonWithSubmenu = ({
|
|
9529
|
+
children,
|
|
9530
|
+
className,
|
|
9531
|
+
Submenu,
|
|
9532
|
+
submenuContainerProps,
|
|
9533
|
+
submenuPlacement = "right-start",
|
|
9534
|
+
submenuRollAxis = "x",
|
|
9535
|
+
...buttonProps
|
|
9440
9536
|
}) => {
|
|
9537
|
+
const { className: submenuClassName, ...submenuContainerRestProps } = submenuContainerProps ?? {};
|
|
9538
|
+
const buttonRef = useRef(null);
|
|
9539
|
+
const [dialogContainer, setDialogContainer] = useState(null);
|
|
9540
|
+
const keepSubmenuOpenFlag = useRef(false);
|
|
9541
|
+
const dialogCloseTimeout = useRef(null);
|
|
9542
|
+
const dialogId2 = useMemo(() => `submenu-${Math.random().toString(36).slice(2)}`, []);
|
|
9543
|
+
const { dialog, dialogManager } = useDialogOnNearestManager({ id: dialogId2 });
|
|
9544
|
+
const dialogIsOpen = useDialogIsOpen(dialogId2, dialogManager?.id);
|
|
9545
|
+
const {
|
|
9546
|
+
placement: chosenPlacement,
|
|
9547
|
+
setPopperElement,
|
|
9548
|
+
styles
|
|
9549
|
+
} = useDialogAnchor({
|
|
9550
|
+
open: dialogIsOpen,
|
|
9551
|
+
placement: submenuPlacement,
|
|
9552
|
+
referenceElement: buttonRef.current
|
|
9553
|
+
});
|
|
9554
|
+
const closeDialogLazily = useCallback(() => {
|
|
9555
|
+
if (dialogCloseTimeout.current) clearTimeout(dialogCloseTimeout.current);
|
|
9556
|
+
dialogCloseTimeout.current = setTimeout(() => {
|
|
9557
|
+
if (keepSubmenuOpenFlag.current) return;
|
|
9558
|
+
dialog.close();
|
|
9559
|
+
}, 100);
|
|
9560
|
+
}, [dialog]);
|
|
9561
|
+
const keepSubmenuOpen = useCallback(() => {
|
|
9562
|
+
keepSubmenuOpenFlag.current = true;
|
|
9563
|
+
}, []);
|
|
9564
|
+
const allowToCloseSubmenu = useCallback(() => {
|
|
9565
|
+
keepSubmenuOpenFlag.current = false;
|
|
9566
|
+
}, []);
|
|
9567
|
+
const closeSubmenu = useCallback(() => {
|
|
9568
|
+
allowToCloseSubmenu();
|
|
9569
|
+
closeDialogLazily();
|
|
9570
|
+
}, [allowToCloseSubmenu, closeDialogLazily]);
|
|
9571
|
+
const handleClose = useCallback(
|
|
9572
|
+
(event) => {
|
|
9573
|
+
const parentButton = buttonRef.current;
|
|
9574
|
+
if (!dialogIsOpen || !parentButton) return;
|
|
9575
|
+
event.stopPropagation();
|
|
9576
|
+
closeDialogLazily();
|
|
9577
|
+
parentButton.focus();
|
|
9578
|
+
},
|
|
9579
|
+
[closeDialogLazily, dialogIsOpen, buttonRef]
|
|
9580
|
+
);
|
|
9581
|
+
const handleFocusParentButton = () => {
|
|
9582
|
+
if (dialogIsOpen) return;
|
|
9583
|
+
dialog.open();
|
|
9584
|
+
keepSubmenuOpen();
|
|
9585
|
+
};
|
|
9586
|
+
useEffect(() => {
|
|
9587
|
+
const parentButton = buttonRef.current;
|
|
9588
|
+
if (!dialogIsOpen || !parentButton) return;
|
|
9589
|
+
const hideOnEscape = (event) => {
|
|
9590
|
+
if (event.key !== "Escape") return;
|
|
9591
|
+
handleClose(event);
|
|
9592
|
+
closeSubmenu();
|
|
9593
|
+
};
|
|
9594
|
+
document.addEventListener("keyup", hideOnEscape, { capture: true });
|
|
9595
|
+
return () => {
|
|
9596
|
+
document.removeEventListener("keyup", hideOnEscape, { capture: true });
|
|
9597
|
+
};
|
|
9598
|
+
}, [dialogIsOpen, handleClose, closeSubmenu]);
|
|
9599
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
9600
|
+
/* @__PURE__ */ jsx(
|
|
9601
|
+
BaseContextMenuButton,
|
|
9602
|
+
{
|
|
9603
|
+
"aria-selected": "false",
|
|
9604
|
+
className: clsx(className, "str_chat__button-with-submenu", {
|
|
9605
|
+
"str_chat__button-with-submenu--submenu-open": dialogIsOpen
|
|
9606
|
+
}),
|
|
9607
|
+
hasSubMenu: true,
|
|
9608
|
+
onBlur: closeSubmenu,
|
|
9609
|
+
onClick: (event) => {
|
|
9610
|
+
event.stopPropagation();
|
|
9611
|
+
dialog.toggle();
|
|
9612
|
+
},
|
|
9613
|
+
onFocus: handleFocusParentButton,
|
|
9614
|
+
onMouseEnter: handleFocusParentButton,
|
|
9615
|
+
onMouseLeave: closeSubmenu,
|
|
9616
|
+
role: "option",
|
|
9617
|
+
...buttonProps,
|
|
9618
|
+
ref: buttonRef,
|
|
9619
|
+
children
|
|
9620
|
+
}
|
|
9621
|
+
),
|
|
9622
|
+
dialogIsOpen && /* @__PURE__ */ jsx(
|
|
9623
|
+
"div",
|
|
9624
|
+
{
|
|
9625
|
+
className: clsx("str-chat__context-menu__submenu-container", submenuClassName),
|
|
9626
|
+
"data-str-chat-placement": chosenPlacement,
|
|
9627
|
+
"data-str-chat-roll-axis": submenuRollAxis,
|
|
9628
|
+
onBlur: (event) => {
|
|
9629
|
+
const isBlurredDescendant = event.relatedTarget instanceof Node && dialogContainer?.contains(event.relatedTarget);
|
|
9630
|
+
if (isBlurredDescendant) return;
|
|
9631
|
+
closeSubmenu();
|
|
9632
|
+
},
|
|
9633
|
+
onFocus: keepSubmenuOpen,
|
|
9634
|
+
onMouseEnter: keepSubmenuOpen,
|
|
9635
|
+
onMouseLeave: closeSubmenu,
|
|
9636
|
+
ref: (element) => {
|
|
9637
|
+
setPopperElement(element);
|
|
9638
|
+
setDialogContainer(element);
|
|
9639
|
+
},
|
|
9640
|
+
style: styles,
|
|
9641
|
+
tabIndex: -1,
|
|
9642
|
+
...submenuContainerRestProps,
|
|
9643
|
+
children: /* @__PURE__ */ jsx(Submenu, {})
|
|
9644
|
+
}
|
|
9645
|
+
)
|
|
9646
|
+
] });
|
|
9647
|
+
};
|
|
9648
|
+
const ContextMenuButton = (props) => {
|
|
9649
|
+
const {
|
|
9650
|
+
Submenu,
|
|
9651
|
+
submenuContainerProps,
|
|
9652
|
+
submenuPlacement,
|
|
9653
|
+
submenuRollAxis,
|
|
9654
|
+
...buttonProps
|
|
9655
|
+
} = props;
|
|
9441
9656
|
const [isFocused, setIsFocused] = useState(false);
|
|
9657
|
+
if (Submenu) {
|
|
9658
|
+
return /* @__PURE__ */ jsx(
|
|
9659
|
+
ContextMenuButtonWithSubmenu,
|
|
9660
|
+
{
|
|
9661
|
+
...buttonProps,
|
|
9662
|
+
Submenu,
|
|
9663
|
+
submenuContainerProps,
|
|
9664
|
+
submenuPlacement,
|
|
9665
|
+
submenuRollAxis
|
|
9666
|
+
}
|
|
9667
|
+
);
|
|
9668
|
+
}
|
|
9669
|
+
const { onBlur, onFocus, ...baseButtonProps } = buttonProps;
|
|
9442
9670
|
return /* @__PURE__ */ jsx(
|
|
9443
9671
|
BaseContextMenuButton,
|
|
9444
9672
|
{
|
|
9445
|
-
...
|
|
9673
|
+
...baseButtonProps,
|
|
9446
9674
|
"aria-selected": isFocused ? "true" : "false",
|
|
9447
9675
|
onBlur: (e) => {
|
|
9448
9676
|
setIsFocused(false);
|
|
@@ -9491,12 +9719,14 @@ function ContextMenuContent({
|
|
|
9491
9719
|
backLabel = "Back",
|
|
9492
9720
|
children,
|
|
9493
9721
|
className,
|
|
9722
|
+
enableAnimations = true,
|
|
9494
9723
|
Header: Header2,
|
|
9495
9724
|
items,
|
|
9496
9725
|
ItemsWrapper,
|
|
9497
9726
|
menuClassName,
|
|
9498
9727
|
onClose,
|
|
9499
9728
|
onMenuLevelChange,
|
|
9729
|
+
transitionDirection,
|
|
9500
9730
|
...props
|
|
9501
9731
|
}) {
|
|
9502
9732
|
const rootLevel = useMemo(
|
|
@@ -9509,6 +9739,7 @@ function ContextMenuContent({
|
|
|
9509
9739
|
[Header2, items, ItemsWrapper, menuClassName]
|
|
9510
9740
|
);
|
|
9511
9741
|
const [menuStack, setMenuStack] = useState(() => [rootLevel]);
|
|
9742
|
+
const [menuBodyAnimationKey, setMenuBodyAnimationKey] = useState(0);
|
|
9512
9743
|
const activeMenu = menuStack[menuStack.length - 1];
|
|
9513
9744
|
const ActiveMenuItemsWrapper = activeMenu.ItemsWrapper ?? React.Fragment;
|
|
9514
9745
|
const closeMenu = useCallback(() => {
|
|
@@ -9532,10 +9763,9 @@ function ContextMenuContent({
|
|
|
9532
9763
|
[ItemsWrapper]
|
|
9533
9764
|
);
|
|
9534
9765
|
const returnToParentMenu = useCallback(() => {
|
|
9535
|
-
|
|
9536
|
-
|
|
9537
|
-
|
|
9538
|
-
}, []);
|
|
9766
|
+
if (menuStack.length <= 1) return;
|
|
9767
|
+
setMenuStack((current) => current.slice(0, current.length - 1));
|
|
9768
|
+
}, [menuStack.length]);
|
|
9539
9769
|
useEffect(() => {
|
|
9540
9770
|
setMenuStack((current) => {
|
|
9541
9771
|
if (current.length === 1 && current[0] === rootLevel) return current;
|
|
@@ -9545,42 +9775,116 @@ function ContextMenuContent({
|
|
|
9545
9775
|
useEffect(() => {
|
|
9546
9776
|
onMenuLevelChange?.(menuStack.length);
|
|
9547
9777
|
}, [menuStack.length, onMenuLevelChange]);
|
|
9548
|
-
|
|
9549
|
-
|
|
9550
|
-
|
|
9551
|
-
|
|
9552
|
-
|
|
9553
|
-
|
|
9554
|
-
|
|
9778
|
+
useEffect(() => {
|
|
9779
|
+
if (!transitionDirection) return;
|
|
9780
|
+
setMenuBodyAnimationKey((value) => value + 1);
|
|
9781
|
+
}, [transitionDirection, menuStack.length]);
|
|
9782
|
+
return /* @__PURE__ */ jsx(ContextMenuContext.Provider, { value: { closeMenu, openSubmenu, returnToParentMenu }, children: /* @__PURE__ */ jsxs(
|
|
9783
|
+
ContextMenuRoot,
|
|
9784
|
+
{
|
|
9785
|
+
className: clsx(className, activeMenu.menuClassName),
|
|
9786
|
+
"data-str-chat-enable-animations": enableAnimations,
|
|
9787
|
+
...props,
|
|
9788
|
+
children: [
|
|
9789
|
+
activeMenu.Header ? /* @__PURE__ */ jsx(activeMenu.Header, {}) : menuStack.length > 1 ? /* @__PURE__ */ jsx(ContextMenuHeader, { children: /* @__PURE__ */ jsxs(ContextMenuBackButton, { onClick: returnToParentMenu, children: [
|
|
9790
|
+
/* @__PURE__ */ jsx(IconChevronLeft, {}),
|
|
9791
|
+
/* @__PURE__ */ jsx("span", { children: backLabel })
|
|
9792
|
+
] }) }) : null,
|
|
9793
|
+
/* @__PURE__ */ jsx(
|
|
9794
|
+
ContextMenuBody,
|
|
9795
|
+
{
|
|
9796
|
+
className: clsx({
|
|
9797
|
+
"str-chat__context-menu__body--submenu-backward": transitionDirection === "backward",
|
|
9798
|
+
"str-chat__context-menu__body--submenu-forward": transitionDirection === "forward"
|
|
9799
|
+
}),
|
|
9800
|
+
children: activeMenu.Submenu ? /* @__PURE__ */ jsx(activeMenu.Submenu, {}) : /* @__PURE__ */ jsx(ActiveMenuItemsWrapper, { children: typeof children !== "undefined" ? children : activeMenu.items?.map((Item2, index) => /* @__PURE__ */ jsx(Item2, {}, `context-menu-item-${index}`)) })
|
|
9801
|
+
},
|
|
9802
|
+
`context-menu-body-${menuStack.length}-${menuBodyAnimationKey}`
|
|
9803
|
+
)
|
|
9804
|
+
]
|
|
9805
|
+
}
|
|
9806
|
+
) });
|
|
9555
9807
|
}
|
|
9556
9808
|
const ContextMenu = (props) => {
|
|
9809
|
+
const { ContextMenuContent: ContextMenuContentComponent = ContextMenuContent } = useComponentContext();
|
|
9557
9810
|
const {
|
|
9558
9811
|
allowFlip,
|
|
9812
|
+
closeOnClickOutside,
|
|
9813
|
+
closeTransitionMs = 130,
|
|
9559
9814
|
dialogManagerId,
|
|
9560
9815
|
focus,
|
|
9561
9816
|
id,
|
|
9562
9817
|
placement,
|
|
9563
9818
|
referenceElement,
|
|
9819
|
+
submenuTransitionDurationMs,
|
|
9564
9820
|
tabIndex,
|
|
9565
9821
|
trapFocus,
|
|
9566
9822
|
...menuProps
|
|
9567
9823
|
} = props;
|
|
9824
|
+
const resolvedSubmenuTransitionDurationMs = submenuTransitionDurationMs ?? 460;
|
|
9568
9825
|
const isAnchored = id != null;
|
|
9569
9826
|
const [menuLevel, setMenuLevel] = useState(1);
|
|
9827
|
+
const [transitionDirection, setTransitionDirection] = useState(void 0);
|
|
9828
|
+
const [contentResetToken, setContentResetToken] = useState(0);
|
|
9829
|
+
const transitionTimeoutRef = useRef(null);
|
|
9830
|
+
const previousMenuLevelRef = useRef(1);
|
|
9570
9831
|
const open = useDialogIsOpen(id ?? "", dialogManagerId);
|
|
9832
|
+
const previousOpenRef = useRef(open);
|
|
9571
9833
|
useEffect(() => {
|
|
9572
|
-
if (isAnchored
|
|
9834
|
+
if (!isAnchored) return;
|
|
9835
|
+
if (previousOpenRef.current && !open) {
|
|
9836
|
+
setMenuLevel(1);
|
|
9837
|
+
setTransitionDirection(void 0);
|
|
9838
|
+
setContentResetToken((value) => value + 1);
|
|
9839
|
+
previousMenuLevelRef.current = 1;
|
|
9840
|
+
if (transitionTimeoutRef.current) {
|
|
9841
|
+
clearTimeout(transitionTimeoutRef.current);
|
|
9842
|
+
transitionTimeoutRef.current = null;
|
|
9843
|
+
}
|
|
9844
|
+
}
|
|
9845
|
+
previousOpenRef.current = open;
|
|
9573
9846
|
}, [isAnchored, open]);
|
|
9574
|
-
|
|
9575
|
-
|
|
9847
|
+
useEffect(
|
|
9848
|
+
() => () => {
|
|
9849
|
+
if (transitionTimeoutRef.current) {
|
|
9850
|
+
clearTimeout(transitionTimeoutRef.current);
|
|
9851
|
+
}
|
|
9852
|
+
},
|
|
9853
|
+
[]
|
|
9854
|
+
);
|
|
9855
|
+
const handleMenuLevelChange = useCallback(
|
|
9856
|
+
(level) => {
|
|
9857
|
+
if (isAnchored) {
|
|
9858
|
+
const previousLevel = previousMenuLevelRef.current;
|
|
9859
|
+
if (level !== previousLevel) {
|
|
9860
|
+
setTransitionDirection(level > previousLevel ? "forward" : "backward");
|
|
9861
|
+
if (transitionTimeoutRef.current) clearTimeout(transitionTimeoutRef.current);
|
|
9862
|
+
transitionTimeoutRef.current = setTimeout(() => {
|
|
9863
|
+
setTransitionDirection(void 0);
|
|
9864
|
+
transitionTimeoutRef.current = null;
|
|
9865
|
+
}, resolvedSubmenuTransitionDurationMs);
|
|
9866
|
+
}
|
|
9867
|
+
previousMenuLevelRef.current = level;
|
|
9868
|
+
setMenuLevel(level);
|
|
9869
|
+
return;
|
|
9870
|
+
}
|
|
9871
|
+
menuProps.onMenuLevelChange?.(level);
|
|
9872
|
+
},
|
|
9873
|
+
[isAnchored, menuProps, resolvedSubmenuTransitionDurationMs]
|
|
9874
|
+
);
|
|
9875
|
+
const content = /* @__PURE__ */ createElement(
|
|
9876
|
+
ContextMenuContentComponent,
|
|
9576
9877
|
{
|
|
9577
9878
|
...menuProps,
|
|
9578
|
-
|
|
9879
|
+
key: `context-menu-content-${contentResetToken}`,
|
|
9880
|
+
onMenuLevelChange: handleMenuLevelChange,
|
|
9881
|
+
transitionDirection
|
|
9579
9882
|
}
|
|
9580
9883
|
);
|
|
9581
9884
|
if (isAnchored) {
|
|
9582
9885
|
const {
|
|
9583
9886
|
backLabel: _b,
|
|
9887
|
+
enableAnimations: _ea,
|
|
9584
9888
|
Header: _h,
|
|
9585
9889
|
items: _i,
|
|
9586
9890
|
ItemsWrapper: _w,
|
|
@@ -9593,6 +9897,8 @@ const ContextMenu = (props) => {
|
|
|
9593
9897
|
DialogAnchor,
|
|
9594
9898
|
{
|
|
9595
9899
|
allowFlip,
|
|
9900
|
+
closeOnClickOutside,
|
|
9901
|
+
closeTransitionMs,
|
|
9596
9902
|
dialogManagerId,
|
|
9597
9903
|
focus,
|
|
9598
9904
|
id,
|
|
@@ -9930,7 +10236,9 @@ const useBaseMessageActionSetFilter = (messageActionSet, disable = false) => {
|
|
|
9930
10236
|
if (isBounced || isInitialMessage || // not sure whether this thing even works anymore
|
|
9931
10237
|
!message.type || message.type === "system" || message.type === "ephemeral" || message.status === "sending")
|
|
9932
10238
|
return [];
|
|
9933
|
-
return messageActionSet.filter((
|
|
10239
|
+
return messageActionSet.filter((action) => {
|
|
10240
|
+
if (action.placement === "quick-dropdown-toggle") return true;
|
|
10241
|
+
const type = action.type;
|
|
9934
10242
|
if (ACTIONS_NOT_WORKING_IN_THREAD.includes(type) && isMessageThreadReply)
|
|
9935
10243
|
return false;
|
|
9936
10244
|
if (message.error) {
|
|
@@ -10277,14 +10585,14 @@ const matchMarkdownLinks = (message) => {
|
|
|
10277
10585
|
const regexMdLinks = /\[([^[]+)\](\(.*\))/gm;
|
|
10278
10586
|
const matches = message.match(regexMdLinks);
|
|
10279
10587
|
const singleMatch = /\[([^[]+)\]\((.*)\)/;
|
|
10280
|
-
const links = matches ? matches.map((
|
|
10281
|
-
const i = singleMatch.exec(
|
|
10588
|
+
const links = matches ? matches.map((match) => {
|
|
10589
|
+
const i = singleMatch.exec(match);
|
|
10282
10590
|
return i && [i[1], i[2]];
|
|
10283
10591
|
}) : [];
|
|
10284
10592
|
return links.flat();
|
|
10285
10593
|
};
|
|
10286
10594
|
const emojiMarkdownPlugin = () => {
|
|
10287
|
-
const replace = (
|
|
10595
|
+
const replace = (match) => u("element", { properties: {}, tagName: "emoji" }, [u("text", match)]);
|
|
10288
10596
|
const transform2 = (node) => findAndReplace(node, [emojiRegex(), replace]);
|
|
10289
10597
|
return transform2;
|
|
10290
10598
|
};
|
|
@@ -10294,13 +10602,13 @@ const mentionsMarkdownPlugin = (mentioned_users) => () => {
|
|
|
10294
10602
|
mentioned_usernames.map((username) => `@${username}`).join("|"),
|
|
10295
10603
|
"g"
|
|
10296
10604
|
);
|
|
10297
|
-
const replace = (
|
|
10298
|
-
const usernameOrId =
|
|
10605
|
+
const replace = (match) => {
|
|
10606
|
+
const usernameOrId = match.replace("@", "");
|
|
10299
10607
|
const user = mentioned_users.find(
|
|
10300
10608
|
({ id, name }) => name === usernameOrId || id === usernameOrId
|
|
10301
10609
|
);
|
|
10302
10610
|
return u("element", { mentionedUser: user, properties: {}, tagName: "mention" }, [
|
|
10303
|
-
u("text",
|
|
10611
|
+
u("text", match)
|
|
10304
10612
|
]);
|
|
10305
10613
|
};
|
|
10306
10614
|
const transform2 = (tree) => {
|
|
@@ -10405,12 +10713,12 @@ const plusPlusToEmphasis = () => {
|
|
|
10405
10713
|
if (node.type !== "text" || parent == null || typeof index !== "number") return;
|
|
10406
10714
|
const value = node.value;
|
|
10407
10715
|
INS_REGEX.lastIndex = 0;
|
|
10408
|
-
let
|
|
10716
|
+
let match;
|
|
10409
10717
|
let last = 0;
|
|
10410
10718
|
const out = [];
|
|
10411
|
-
while (
|
|
10412
|
-
const [full, inner] =
|
|
10413
|
-
const start =
|
|
10719
|
+
while (match = INS_REGEX.exec(value)) {
|
|
10720
|
+
const [full, inner] = match;
|
|
10721
|
+
const start = match.index;
|
|
10414
10722
|
if (start > last) out.push({ type: "text", value: value.slice(last, start) });
|
|
10415
10723
|
out.push({
|
|
10416
10724
|
children: [{ type: "text", value: inner }],
|
|
@@ -11838,6 +12146,7 @@ const toBaseImageDescriptors = (attachment, options = {}) => {
|
|
|
11838
12146
|
title: attachment.title
|
|
11839
12147
|
};
|
|
11840
12148
|
}
|
|
12149
|
+
return void 0;
|
|
11841
12150
|
};
|
|
11842
12151
|
const BASE_FILE_ICON_CLASSNAME = "str-chat__file-icon";
|
|
11843
12152
|
const FILE_ICON_GRAPHIC_CLASSNAME = "str-chat__file-icon__graphic";
|
|
@@ -14675,7 +14984,8 @@ const PollOptionWithVotes = ({
|
|
|
14675
14984
|
"div",
|
|
14676
14985
|
{
|
|
14677
14986
|
className: clsx("str-chat__poll-option", {
|
|
14678
|
-
"str-chat__poll-option--has-more-votes": isVotesPreview && voteCount > countVotesPreview
|
|
14987
|
+
"str-chat__poll-option--has-more-votes": isVotesPreview && voteCount > countVotesPreview,
|
|
14988
|
+
"str-chat__poll-option--has-votes": voteCount
|
|
14679
14989
|
}),
|
|
14680
14990
|
children: [
|
|
14681
14991
|
/* @__PURE__ */ jsx(PollOptionWithVotesHeader, { option, optionOrderNumber: orderNumber }),
|
|
@@ -15688,7 +15998,7 @@ const AttachmentSelector = ({
|
|
|
15688
15998
|
getModalPortalDestination
|
|
15689
15999
|
}) => {
|
|
15690
16000
|
const { t } = useTranslationContext();
|
|
15691
|
-
const { Modal = GlobalModal } = useComponentContext();
|
|
16001
|
+
const { ContextMenu: ContextMenuComponent = ContextMenu, Modal = GlobalModal } = useComponentContext();
|
|
15692
16002
|
const { channelCapabilities } = useChannelStateContext();
|
|
15693
16003
|
const messageComposer = useMessageComposerController();
|
|
15694
16004
|
const isCooldownActive = useIsCooldownActive();
|
|
@@ -15748,7 +16058,7 @@ const AttachmentSelector = ({
|
|
|
15748
16058
|
}
|
|
15749
16059
|
),
|
|
15750
16060
|
/* @__PURE__ */ jsx(
|
|
15751
|
-
|
|
16061
|
+
ContextMenuComponent,
|
|
15752
16062
|
{
|
|
15753
16063
|
allowFlip: true,
|
|
15754
16064
|
backLabel: t("Back"),
|
|
@@ -17778,7 +18088,10 @@ const SuggestionList = ({
|
|
|
17778
18088
|
setFocusedItemIndex,
|
|
17779
18089
|
suggestionItemComponents = defaultComponents
|
|
17780
18090
|
}) => {
|
|
17781
|
-
const {
|
|
18091
|
+
const {
|
|
18092
|
+
AutocompleteSuggestionItem = SuggestionListItem,
|
|
18093
|
+
ContextMenu: ContextMenuComponent = ContextMenu
|
|
18094
|
+
} = useComponentContext();
|
|
17782
18095
|
const { textareaRef } = useMessageComposerContext();
|
|
17783
18096
|
const messageComposer = useMessageComposerController();
|
|
17784
18097
|
const { textComposer } = messageComposer;
|
|
@@ -17896,7 +18209,7 @@ const SuggestionList = ({
|
|
|
17896
18209
|
zIndex: 1e3
|
|
17897
18210
|
},
|
|
17898
18211
|
children: /* @__PURE__ */ jsx(
|
|
17899
|
-
|
|
18212
|
+
ContextMenuComponent,
|
|
17900
18213
|
{
|
|
17901
18214
|
className: clsx("str-chat__suggestion-list", className),
|
|
17902
18215
|
Header: suggestions.searchSource.type === "commands" ? CommandsMenuHeader : void 0,
|
|
@@ -18122,12 +18435,6 @@ const TextareaComposer = ({
|
|
|
18122
18435
|
if (!textareaRef.current || textareaIsFocused || !focus) return;
|
|
18123
18436
|
textareaRef.current.focus();
|
|
18124
18437
|
}, [attachments, focus, quotedMessage, textareaRef]);
|
|
18125
|
-
useEffect(
|
|
18126
|
-
() => () => {
|
|
18127
|
-
messageComposer.clear();
|
|
18128
|
-
},
|
|
18129
|
-
[messageComposer]
|
|
18130
|
-
);
|
|
18131
18438
|
useLayoutEffect(() => {
|
|
18132
18439
|
const textarea = textareaRef.current;
|
|
18133
18440
|
if (!textarea || isComposing) return;
|
|
@@ -18581,7 +18888,7 @@ const MessageComposerProvider = (props) => {
|
|
|
18581
18888
|
const messageComposer = useMessageComposerController();
|
|
18582
18889
|
useEffect(
|
|
18583
18890
|
() => () => {
|
|
18584
|
-
messageComposer.createDraft();
|
|
18891
|
+
messageComposer.createDraft().finally(() => messageComposer.clear());
|
|
18585
18892
|
},
|
|
18586
18893
|
[messageComposer]
|
|
18587
18894
|
);
|
|
@@ -18899,7 +19206,7 @@ const useChat = ({
|
|
|
18899
19206
|
};
|
|
18900
19207
|
useEffect(() => {
|
|
18901
19208
|
if (!client) return;
|
|
18902
|
-
const version = "14.0.0-beta.
|
|
19209
|
+
const version = "14.0.0-beta.3";
|
|
18903
19210
|
const userAgent = client.getUserAgent();
|
|
18904
19211
|
if (!userAgent.includes("stream-chat-react")) {
|
|
18905
19212
|
client.setUserAgent(`stream-chat-react-${version}-${userAgent}`);
|
|
@@ -19400,10 +19707,10 @@ const ReactionSelector = (props) => {
|
|
|
19400
19707
|
) })
|
|
19401
19708
|
] });
|
|
19402
19709
|
};
|
|
19403
|
-
ReactionSelector.getDialogId = (
|
|
19710
|
+
ReactionSelector.getDialogId = ({ messageId, threadList }) => {
|
|
19404
19711
|
const dialogIdNamespace = threadList ? "-thread" : "";
|
|
19405
|
-
return `reaction-selector${dialogIdNamespace}
|
|
19406
|
-
}
|
|
19712
|
+
return `reaction-selector${dialogIdNamespace}-${messageId}`;
|
|
19713
|
+
};
|
|
19407
19714
|
ReactionSelector.displayName = "ReactionSelector";
|
|
19408
19715
|
const ReactionSelectorWithButton = ({
|
|
19409
19716
|
ReactionIcon
|
|
@@ -19488,6 +19795,7 @@ const QuickMessageActionsButton = ({ className, ...props }) => /* @__PURE__ */ j
|
|
|
19488
19795
|
appearance: "ghost",
|
|
19489
19796
|
circular: true,
|
|
19490
19797
|
className: clsx("str-chat__message-actions-box-button", className),
|
|
19798
|
+
size: "sm",
|
|
19491
19799
|
variant: "secondary",
|
|
19492
19800
|
...props
|
|
19493
19801
|
}
|
|
@@ -19848,6 +20156,32 @@ const DefaultMessageActionComponents = {
|
|
|
19848
20156
|
}
|
|
19849
20157
|
},
|
|
19850
20158
|
quick: {
|
|
20159
|
+
// eslint-disable-next-line react/display-name
|
|
20160
|
+
DropdownToggle: forwardRef((_, ref) => {
|
|
20161
|
+
const { t } = useTranslationContext();
|
|
20162
|
+
const { message } = useMessageContext();
|
|
20163
|
+
const dropdownDialogIsOpen = useDialogIsOpen(
|
|
20164
|
+
MessageActions.getDialogId({ messageId: message.id })
|
|
20165
|
+
);
|
|
20166
|
+
const { dialog } = useDialogOnNearestManager({
|
|
20167
|
+
id: MessageActions.getDialogId({ messageId: message.id })
|
|
20168
|
+
});
|
|
20169
|
+
return /* @__PURE__ */ jsx(
|
|
20170
|
+
QuickMessageActionsButton,
|
|
20171
|
+
{
|
|
20172
|
+
"aria-expanded": dropdownDialogIsOpen,
|
|
20173
|
+
"aria-haspopup": "true",
|
|
20174
|
+
"aria-label": t("aria/Open Message Actions Menu"),
|
|
20175
|
+
className: "str-chat__message-actions-box-button",
|
|
20176
|
+
"data-testid": "message-actions-toggle-button",
|
|
20177
|
+
onClick: () => {
|
|
20178
|
+
dialog?.toggle();
|
|
20179
|
+
},
|
|
20180
|
+
ref,
|
|
20181
|
+
children: /* @__PURE__ */ jsx(IconDotGrid1x3Horizontal, { className: "str-chat__message-action-icon" })
|
|
20182
|
+
}
|
|
20183
|
+
);
|
|
20184
|
+
}),
|
|
19851
20185
|
React() {
|
|
19852
20186
|
return /* @__PURE__ */ jsx(ReactionSelectorWithButton, { ReactionIcon: IconEmojiSmile });
|
|
19853
20187
|
},
|
|
@@ -19868,7 +20202,10 @@ const DefaultMessageActionComponents = {
|
|
|
19868
20202
|
}
|
|
19869
20203
|
};
|
|
19870
20204
|
const defaultMessageActionSet = [
|
|
19871
|
-
|
|
20205
|
+
{
|
|
20206
|
+
Component: DefaultMessageActionComponents.quick.DropdownToggle,
|
|
20207
|
+
placement: "quick-dropdown-toggle"
|
|
20208
|
+
},
|
|
19872
20209
|
{
|
|
19873
20210
|
Component: DefaultMessageActionComponents.quick.Reply,
|
|
19874
20211
|
placement: "quick",
|
|
@@ -19958,14 +20295,14 @@ function useFetchReactions(options) {
|
|
|
19958
20295
|
const handleFetchReactions = propHandleFetchReactions ?? contextHandleFetchReactions;
|
|
19959
20296
|
const [refetchNonce, setRefetchNonce] = useState(null);
|
|
19960
20297
|
useEffect(() => {
|
|
19961
|
-
if (!shouldFetch
|
|
20298
|
+
if (!shouldFetch) {
|
|
19962
20299
|
return;
|
|
19963
20300
|
}
|
|
19964
20301
|
let cancel = false;
|
|
19965
20302
|
(async () => {
|
|
19966
20303
|
try {
|
|
19967
20304
|
setIsLoading(true);
|
|
19968
|
-
const reactions2 = await handleFetchReactions(reactionType, sort);
|
|
20305
|
+
const reactions2 = await handleFetchReactions(reactionType ?? void 0, sort);
|
|
19969
20306
|
if (!cancel) {
|
|
19970
20307
|
setReactions(reactions2);
|
|
19971
20308
|
}
|
|
@@ -19989,6 +20326,16 @@ function useFetchReactions(options) {
|
|
|
19989
20326
|
return { isLoading, reactions, refetch };
|
|
19990
20327
|
}
|
|
19991
20328
|
const defaultReactionDetailsSort = { created_at: -1 };
|
|
20329
|
+
const MessageReactionsDetailLoadingIndicator = () => {
|
|
20330
|
+
const elements = useMemo(
|
|
20331
|
+
() => Array.from({ length: 3 }, (_, index) => /* @__PURE__ */ jsxs("div", { className: "str-chat__message-reactions-detail__skeleton-item", children: [
|
|
20332
|
+
/* @__PURE__ */ jsx("div", { className: "str-chat__message-reactions-detail__skeleton-avatar" }),
|
|
20333
|
+
/* @__PURE__ */ jsx("div", { className: "str-chat__message-reactions-detail__skeleton-line" })
|
|
20334
|
+
] }, index)),
|
|
20335
|
+
[]
|
|
20336
|
+
);
|
|
20337
|
+
return /* @__PURE__ */ jsx(Fragment, { children: elements });
|
|
20338
|
+
};
|
|
19992
20339
|
function MessageReactionsDetail({
|
|
19993
20340
|
handleFetchReactions,
|
|
19994
20341
|
onSelectedReactionTypeChange,
|
|
@@ -19999,7 +20346,11 @@ function MessageReactionsDetail({
|
|
|
19999
20346
|
totalReactionCount
|
|
20000
20347
|
}) {
|
|
20001
20348
|
const { client } = useChatContext();
|
|
20002
|
-
const {
|
|
20349
|
+
const {
|
|
20350
|
+
Avatar: Avatar$1 = Avatar,
|
|
20351
|
+
LoadingIndicator: LoadingIndicator2 = MessageReactionsDetailLoadingIndicator,
|
|
20352
|
+
reactionOptions = defaultReactionOptions
|
|
20353
|
+
} = useComponentContext(MessageReactionsDetail.name);
|
|
20003
20354
|
const { t } = useTranslationContext();
|
|
20004
20355
|
const {
|
|
20005
20356
|
handleReaction: contextHandleReaction,
|
|
@@ -20026,7 +20377,7 @@ function MessageReactionsDetail({
|
|
|
20026
20377
|
"div",
|
|
20027
20378
|
{
|
|
20028
20379
|
className: "str-chat__message-reactions-detail",
|
|
20029
|
-
"data-testid": "reactions-
|
|
20380
|
+
"data-testid": "message-reactions-detail",
|
|
20030
20381
|
children: [
|
|
20031
20382
|
typeof totalReactionCount === "number" && /* @__PURE__ */ jsx("div", { className: "str-chat__message-reactions-detail__total-count", children: t("{{ count }} reactions", { count: totalReactionCount }) }),
|
|
20032
20383
|
/* @__PURE__ */ jsx("div", { className: "str-chat__message-reactions-detail__reaction-type-list-container", children: /* @__PURE__ */ jsx("ul", { className: "str-chat__message-reactions-detail__reaction-type-list", children: reactions.map(
|
|
@@ -20039,7 +20390,9 @@ function MessageReactionsDetail({
|
|
|
20039
20390
|
{
|
|
20040
20391
|
"aria-pressed": reactionType === selectedReactionType,
|
|
20041
20392
|
className: "str-chat__message-reactions-detail__reaction-type-list-item-button",
|
|
20042
|
-
onClick: () => onSelectedReactionTypeChange?.(
|
|
20393
|
+
onClick: () => onSelectedReactionTypeChange?.(
|
|
20394
|
+
selectedReactionType === reactionType ? null : reactionType
|
|
20395
|
+
),
|
|
20043
20396
|
children: [
|
|
20044
20397
|
/* @__PURE__ */ jsx("span", { className: "str-chat__message-reactions-detail__reaction-type-list-item-icon", children: /* @__PURE__ */ jsx(EmojiComponent, {}) }),
|
|
20045
20398
|
reactionCount > 1 && /* @__PURE__ */ jsx(
|
|
@@ -20063,22 +20416,10 @@ function MessageReactionsDetail({
|
|
|
20063
20416
|
className: "str-chat__message-reactions-detail__user-list",
|
|
20064
20417
|
"data-testid": "all-reacting-users",
|
|
20065
20418
|
children: [
|
|
20066
|
-
areReactionsLoading && /* @__PURE__ */
|
|
20067
|
-
|
|
20068
|
-
/* @__PURE__ */ jsx("div", { className: "str-chat__message-reactions-detail__skeleton-avatar" }),
|
|
20069
|
-
/* @__PURE__ */ jsx("div", { className: "str-chat__message-reactions-detail__skeleton-line" })
|
|
20070
|
-
] }),
|
|
20071
|
-
/* @__PURE__ */ jsxs("div", { className: "str-chat__message-reactions-detail__skeleton-item", children: [
|
|
20072
|
-
/* @__PURE__ */ jsx("div", { className: "str-chat__message-reactions-detail__skeleton-avatar" }),
|
|
20073
|
-
/* @__PURE__ */ jsx("div", { className: "str-chat__message-reactions-detail__skeleton-line" })
|
|
20074
|
-
] }),
|
|
20075
|
-
/* @__PURE__ */ jsxs("div", { className: "str-chat__message-reactions-detail__skeleton-item", children: [
|
|
20076
|
-
/* @__PURE__ */ jsx("div", { className: "str-chat__message-reactions-detail__skeleton-avatar" }),
|
|
20077
|
-
/* @__PURE__ */ jsx("div", { className: "str-chat__message-reactions-detail__skeleton-line" })
|
|
20078
|
-
] })
|
|
20079
|
-
] }),
|
|
20080
|
-
!areReactionsLoading && /* @__PURE__ */ jsx(Fragment, { children: reactionDetailsWithLegacyFallback.map(({ user }) => {
|
|
20419
|
+
areReactionsLoading && /* @__PURE__ */ jsx(LoadingIndicator2, {}),
|
|
20420
|
+
!areReactionsLoading && /* @__PURE__ */ jsx(Fragment, { children: reactionDetailsWithLegacyFallback.map(({ type, user }) => {
|
|
20081
20421
|
const belongsToCurrentUser = client.user?.id === user?.id;
|
|
20422
|
+
const EmojiComponent = Array.isArray(reactionOptions) ? void 0 : reactionOptions.quick[type]?.Component ?? reactionOptions.extended?.[type]?.Component;
|
|
20082
20423
|
return /* @__PURE__ */ jsxs(
|
|
20083
20424
|
"div",
|
|
20084
20425
|
{
|
|
@@ -20103,23 +20444,23 @@ function MessageReactionsDetail({
|
|
|
20103
20444
|
children: belongsToCurrentUser ? t("You") : user?.name || user?.id
|
|
20104
20445
|
}
|
|
20105
20446
|
),
|
|
20106
|
-
belongsToCurrentUser &&
|
|
20447
|
+
belongsToCurrentUser && /* @__PURE__ */ jsx(
|
|
20107
20448
|
"button",
|
|
20108
20449
|
{
|
|
20109
20450
|
className: "str-chat__message-reactions-detail__user-list-item-button",
|
|
20110
20451
|
"data-testid": "remove-reaction-button",
|
|
20111
|
-
onClick: (e) => {
|
|
20112
|
-
contextHandleReaction(
|
|
20113
|
-
|
|
20114
|
-
});
|
|
20452
|
+
onClick: async (e) => {
|
|
20453
|
+
await contextHandleReaction(type, e);
|
|
20454
|
+
refetch();
|
|
20115
20455
|
},
|
|
20116
20456
|
children: t("Tap to remove")
|
|
20117
20457
|
}
|
|
20118
20458
|
)
|
|
20119
|
-
] })
|
|
20459
|
+
] }),
|
|
20460
|
+
/* @__PURE__ */ jsx("span", { className: "str-chat__message-reactions-detail__user-list-item-icon", children: EmojiComponent && !selectedReactionType && /* @__PURE__ */ jsx(EmojiComponent, {}) })
|
|
20120
20461
|
]
|
|
20121
20462
|
},
|
|
20122
|
-
user?.id
|
|
20463
|
+
`${user?.id}-${type}`
|
|
20123
20464
|
);
|
|
20124
20465
|
}) })
|
|
20125
20466
|
]
|
|
@@ -20268,6 +20609,7 @@ const UnMemoizedMessageReactions = (props) => {
|
|
|
20268
20609
|
const divRef = useRef(null);
|
|
20269
20610
|
const dialogId2 = `message-reactions-detail-${message.id}`;
|
|
20270
20611
|
const { dialog, dialogManager } = useDialogOnNearestManager({ id: dialogId2 });
|
|
20612
|
+
const isDialogOpen = useDialogIsOpen(dialogId2, dialogManager?.id);
|
|
20271
20613
|
const handleReactionButtonClick = (reactionType) => {
|
|
20272
20614
|
if (totalReactionCount > MAX_MESSAGE_REACTIONS_TO_FETCH) {
|
|
20273
20615
|
return;
|
|
@@ -20302,6 +20644,8 @@ const UnMemoizedMessageReactions = (props) => {
|
|
|
20302
20644
|
children: /* @__PURE__ */ jsxs(
|
|
20303
20645
|
FragmentOrButton,
|
|
20304
20646
|
{
|
|
20647
|
+
"aria-expanded": isDialogOpen,
|
|
20648
|
+
"aria-pressed": isDialogOpen,
|
|
20305
20649
|
buttonIf: visualStyle === "clustered",
|
|
20306
20650
|
className: "str-chat__message-reactions__list-button",
|
|
20307
20651
|
onClick: () => handleReactionButtonClick(existingReactions[0]?.reactionType ?? null),
|
|
@@ -20339,9 +20683,7 @@ const UnMemoizedMessageReactions = (props) => {
|
|
|
20339
20683
|
"button",
|
|
20340
20684
|
{
|
|
20341
20685
|
className: "str-chat__message-reactions__list-item-button",
|
|
20342
|
-
onClick: () => handleReactionButtonClick(
|
|
20343
|
-
existingReactions.at(-1)?.reactionType ?? null
|
|
20344
|
-
),
|
|
20686
|
+
onClick: () => handleReactionButtonClick(null),
|
|
20345
20687
|
children: /* @__PURE__ */ jsxs("span", { className: "str-chat__message-reactions__overflow-count", children: [
|
|
20346
20688
|
"+",
|
|
20347
20689
|
totalReactionCount - cappedExistingReactions.reactionCountToDisplay
|
|
@@ -20466,91 +20808,74 @@ const StreamEmoji = ({
|
|
|
20466
20808
|
const useSplitActionSet = (actionSet) => useMemo(() => {
|
|
20467
20809
|
const quickActionSet = [];
|
|
20468
20810
|
const dropdownActionSet = [];
|
|
20811
|
+
let quickDropdownToggleAction;
|
|
20469
20812
|
for (const action of actionSet) {
|
|
20470
20813
|
if (action.placement === "quick")
|
|
20471
20814
|
quickActionSet.push(action);
|
|
20472
20815
|
if (action.placement === "dropdown")
|
|
20473
20816
|
dropdownActionSet.push(action);
|
|
20817
|
+
if (action.placement === "quick-dropdown-toggle") {
|
|
20818
|
+
quickDropdownToggleAction ?? (quickDropdownToggleAction = action);
|
|
20819
|
+
}
|
|
20474
20820
|
}
|
|
20475
|
-
return { dropdownActionSet, quickActionSet };
|
|
20821
|
+
return { dropdownActionSet, quickActionSet, quickDropdownToggleAction };
|
|
20476
20822
|
}, [actionSet]);
|
|
20477
20823
|
const MessageActions = ({
|
|
20478
20824
|
disableBaseMessageActionSetFilter = false,
|
|
20479
20825
|
messageActionSet = defaultMessageActionSet
|
|
20480
20826
|
}) => {
|
|
20481
|
-
const { theme } = useChatContext();
|
|
20482
20827
|
const { isMyMessage, message, threadList } = useMessageContext();
|
|
20828
|
+
const { ContextMenu: ContextMenuComponent = ContextMenu } = useComponentContext();
|
|
20483
20829
|
const { t } = useTranslationContext();
|
|
20484
20830
|
const [actionsBoxButtonElement, setActionsBoxButtonElement] = useState(null);
|
|
20485
20831
|
const filteredMessageActionSet = useBaseMessageActionSetFilter(
|
|
20486
20832
|
messageActionSet,
|
|
20487
20833
|
disableBaseMessageActionSetFilter
|
|
20488
20834
|
);
|
|
20489
|
-
const { dropdownActionSet, quickActionSet } = useSplitActionSet(
|
|
20490
|
-
|
|
20491
|
-
);
|
|
20492
|
-
const dropdownDialogId = `message-actions--${message.id}`;
|
|
20835
|
+
const { dropdownActionSet, quickActionSet, quickDropdownToggleAction } = useSplitActionSet(filteredMessageActionSet);
|
|
20836
|
+
const messageActionsDialogId = MessageActions.getDialogId({ messageId: message.id });
|
|
20493
20837
|
const reactionSelectorDialogId = ReactionSelector.getDialogId({
|
|
20494
20838
|
messageId: message.id,
|
|
20495
20839
|
threadList
|
|
20496
20840
|
});
|
|
20497
|
-
const { dialog, dialogManager } = useDialogOnNearestManager({
|
|
20498
|
-
|
|
20841
|
+
const { dialog, dialogManager } = useDialogOnNearestManager({
|
|
20842
|
+
id: messageActionsDialogId
|
|
20843
|
+
});
|
|
20844
|
+
const messageActionsDialogIsOpen = useDialogIsOpen(
|
|
20845
|
+
messageActionsDialogId,
|
|
20846
|
+
dialogManager?.id
|
|
20847
|
+
);
|
|
20499
20848
|
const reactionSelectorDialogIsOpen = useDialogIsOpen(
|
|
20500
20849
|
reactionSelectorDialogId,
|
|
20501
20850
|
dialogManager?.id
|
|
20502
20851
|
);
|
|
20503
|
-
const contextMenuItems = useMemo(
|
|
20504
|
-
() => dropdownActionSet.map(({ Component: Component2 }) => {
|
|
20505
|
-
const ActionItem = (menuProps) => /* @__PURE__ */ jsx(Component2, { ...menuProps });
|
|
20506
|
-
return ActionItem;
|
|
20507
|
-
}),
|
|
20508
|
-
[dropdownActionSet]
|
|
20509
|
-
);
|
|
20510
20852
|
if (dropdownActionSet.length + quickActionSet.length === 0) {
|
|
20511
20853
|
return null;
|
|
20512
20854
|
}
|
|
20513
20855
|
return /* @__PURE__ */ jsxs(
|
|
20514
20856
|
"div",
|
|
20515
20857
|
{
|
|
20516
|
-
className: clsx(
|
|
20517
|
-
"str-chat__message-options--active":
|
|
20858
|
+
className: clsx("str-chat__message-options", {
|
|
20859
|
+
"str-chat__message-options--active": messageActionsDialogIsOpen || reactionSelectorDialogIsOpen
|
|
20518
20860
|
}),
|
|
20519
20861
|
children: [
|
|
20520
|
-
dropdownActionSet.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
20521
|
-
/* @__PURE__ */ jsx(
|
|
20522
|
-
Button,
|
|
20523
|
-
{
|
|
20524
|
-
appearance: "ghost",
|
|
20525
|
-
"aria-expanded": dropdownDialogIsOpen,
|
|
20526
|
-
"aria-haspopup": "true",
|
|
20527
|
-
"aria-label": t("aria/Open Message Actions Menu"),
|
|
20528
|
-
circular: true,
|
|
20529
|
-
className: "str-chat__message-actions-box-button",
|
|
20530
|
-
"data-testid": "message-actions-toggle-button",
|
|
20531
|
-
onClick: () => {
|
|
20532
|
-
dialog?.toggle();
|
|
20533
|
-
},
|
|
20534
|
-
ref: setActionsBoxButtonElement,
|
|
20535
|
-
variant: "secondary",
|
|
20536
|
-
children: /* @__PURE__ */ jsx(IconDotGrid1x3Horizontal, { className: "str-chat__message-action-icon" })
|
|
20537
|
-
}
|
|
20538
|
-
),
|
|
20862
|
+
quickDropdownToggleAction && dropdownActionSet.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
20863
|
+
/* @__PURE__ */ jsx(quickDropdownToggleAction.Component, { ref: setActionsBoxButtonElement }),
|
|
20539
20864
|
/* @__PURE__ */ jsx(
|
|
20540
|
-
|
|
20865
|
+
ContextMenuComponent,
|
|
20541
20866
|
{
|
|
20542
20867
|
backLabel: t("Back"),
|
|
20543
20868
|
className: clsx("str-chat__message-actions-box", {
|
|
20544
|
-
"str-chat__message-actions-box--open":
|
|
20869
|
+
"str-chat__message-actions-box--open": messageActionsDialogIsOpen
|
|
20545
20870
|
}),
|
|
20546
20871
|
dialogManagerId: dialogManager?.id,
|
|
20547
|
-
id:
|
|
20548
|
-
items: contextMenuItems,
|
|
20872
|
+
id: messageActionsDialogId,
|
|
20549
20873
|
onClose: dialog?.close,
|
|
20550
20874
|
placement: isMyMessage() ? "top-end" : "top-start",
|
|
20551
20875
|
referenceElement: actionsBoxButtonElement,
|
|
20552
20876
|
tabIndex: -1,
|
|
20553
|
-
trapFocus: true
|
|
20877
|
+
trapFocus: true,
|
|
20878
|
+
children: dropdownActionSet.map(({ Component: Component2, type }) => /* @__PURE__ */ jsx(Component2, {}, type))
|
|
20554
20879
|
}
|
|
20555
20880
|
)
|
|
20556
20881
|
] }),
|
|
@@ -20559,6 +20884,8 @@ const MessageActions = ({
|
|
|
20559
20884
|
}
|
|
20560
20885
|
);
|
|
20561
20886
|
};
|
|
20887
|
+
MessageActions.getDialogId = ({ messageId }) => `message-actions-${messageId}`;
|
|
20888
|
+
MessageActions.displayName = "MessageActions";
|
|
20562
20889
|
const MessageUIWithContext = ({
|
|
20563
20890
|
endOfGroup,
|
|
20564
20891
|
firstOfGroup,
|
|
@@ -21385,6 +21712,7 @@ const useScrollLocationLogic = (params) => {
|
|
|
21385
21712
|
const closeToBottom = useRef(false);
|
|
21386
21713
|
const closeToTop = useRef(false);
|
|
21387
21714
|
const previousScrollTopRef = useRef(0);
|
|
21715
|
+
const previousMessagesLengthRef = useRef(messages.length);
|
|
21388
21716
|
const anchorRestoreCleanupRef = useRef(null);
|
|
21389
21717
|
const captureAnchor = useCallback(() => {
|
|
21390
21718
|
if (!listElement) return null;
|
|
@@ -21536,6 +21864,60 @@ const useScrollLocationLogic = (params) => {
|
|
|
21536
21864
|
scrollToBottom();
|
|
21537
21865
|
}
|
|
21538
21866
|
}, [disableAutoScrollToBottom, justReachedLatestMessageSet, listElement, hasMoreNewer]);
|
|
21867
|
+
useLayoutEffect(() => {
|
|
21868
|
+
if (!listElement || disableAutoScrollToBottom || hasMoreNewer || suppressAutoscroll || justReachedLatestMessageSet || isRestoringOlderAnchorRef.current) {
|
|
21869
|
+
return;
|
|
21870
|
+
}
|
|
21871
|
+
const initialDistanceToBottom = listElement.scrollHeight - (listElement.scrollTop + listElement.clientHeight);
|
|
21872
|
+
const messagesHydrated = previousMessagesLengthRef.current === 0 && messages.length > 0;
|
|
21873
|
+
if (initialDistanceToBottom > scrolledUpThreshold && !messagesHydrated) {
|
|
21874
|
+
return;
|
|
21875
|
+
}
|
|
21876
|
+
let keepPinnedToBottom = true;
|
|
21877
|
+
const maybeScrollToBottom = () => {
|
|
21878
|
+
if (keepPinnedToBottom) {
|
|
21879
|
+
scrollToBottom();
|
|
21880
|
+
}
|
|
21881
|
+
};
|
|
21882
|
+
maybeScrollToBottom();
|
|
21883
|
+
const settleDelays = [80, messagesHydrated ? 260 : 420, 900, 1700];
|
|
21884
|
+
const settleTimeoutIds = settleDelays.map(
|
|
21885
|
+
(delay) => setTimeout(maybeScrollToBottom, delay)
|
|
21886
|
+
);
|
|
21887
|
+
const stopKeepingPinnedToBottom = () => {
|
|
21888
|
+
keepPinnedToBottom = false;
|
|
21889
|
+
};
|
|
21890
|
+
listElement.addEventListener("pointerdown", stopKeepingPinnedToBottom, {
|
|
21891
|
+
passive: true
|
|
21892
|
+
});
|
|
21893
|
+
listElement.addEventListener("touchstart", stopKeepingPinnedToBottom, {
|
|
21894
|
+
passive: true
|
|
21895
|
+
});
|
|
21896
|
+
listElement.addEventListener("wheel", stopKeepingPinnedToBottom, {
|
|
21897
|
+
passive: true
|
|
21898
|
+
});
|
|
21899
|
+
listElement.addEventListener("keydown", stopKeepingPinnedToBottom);
|
|
21900
|
+
const pinWindowTimeoutId = setTimeout(() => {
|
|
21901
|
+
stopKeepingPinnedToBottom();
|
|
21902
|
+
}, 2200);
|
|
21903
|
+
return () => {
|
|
21904
|
+
settleTimeoutIds.forEach(clearTimeout);
|
|
21905
|
+
clearTimeout(pinWindowTimeoutId);
|
|
21906
|
+
listElement.removeEventListener("pointerdown", stopKeepingPinnedToBottom);
|
|
21907
|
+
listElement.removeEventListener("touchstart", stopKeepingPinnedToBottom);
|
|
21908
|
+
listElement.removeEventListener("wheel", stopKeepingPinnedToBottom);
|
|
21909
|
+
listElement.removeEventListener("keydown", stopKeepingPinnedToBottom);
|
|
21910
|
+
};
|
|
21911
|
+
}, [
|
|
21912
|
+
disableAutoScrollToBottom,
|
|
21913
|
+
hasMoreNewer,
|
|
21914
|
+
justReachedLatestMessageSet,
|
|
21915
|
+
listElement,
|
|
21916
|
+
messages.length,
|
|
21917
|
+
scrollToBottom,
|
|
21918
|
+
scrolledUpThreshold,
|
|
21919
|
+
suppressAutoscroll
|
|
21920
|
+
]);
|
|
21539
21921
|
const updateScrollTop = useMessageListScrollManager({
|
|
21540
21922
|
captureAnchor,
|
|
21541
21923
|
disableScrollManagement: disableScrollManagement || isRestoringOlderAnchorRef.current,
|
|
@@ -21562,6 +21944,9 @@ const useScrollLocationLogic = (params) => {
|
|
|
21562
21944
|
useLayoutEffect(() => {
|
|
21563
21945
|
previousHasMoreNewerRef.current = hasMoreNewer;
|
|
21564
21946
|
}, [hasMoreNewer]);
|
|
21947
|
+
useLayoutEffect(() => {
|
|
21948
|
+
previousMessagesLengthRef.current = messages.length;
|
|
21949
|
+
}, [messages.length]);
|
|
21565
21950
|
const onScroll = useCallback(
|
|
21566
21951
|
(event) => {
|
|
21567
21952
|
const element = event.target;
|
|
@@ -21570,8 +21955,10 @@ const useScrollLocationLogic = (params) => {
|
|
|
21570
21955
|
updateScrollTop(scrollTop, captureAnchor);
|
|
21571
21956
|
const offsetHeight = element.offsetHeight;
|
|
21572
21957
|
const scrollHeight = element.scrollHeight;
|
|
21958
|
+
const distanceToBottom = scrollHeight - (scrollTop + offsetHeight);
|
|
21959
|
+
const bottomEnterThreshold = Math.max(Math.floor(scrolledUpThreshold * 0.6), 24);
|
|
21573
21960
|
const prevCloseToBottom = closeToBottom.current;
|
|
21574
|
-
closeToBottom.current =
|
|
21961
|
+
closeToBottom.current = prevCloseToBottom ? distanceToBottom < scrolledUpThreshold : distanceToBottom < bottomEnterThreshold;
|
|
21575
21962
|
closeToTop.current = scrollTop < scrolledUpThreshold;
|
|
21576
21963
|
if (closeToBottom.current) {
|
|
21577
21964
|
setHasNewMessages(false);
|
|
@@ -23506,11 +23893,17 @@ const useConnectionRecoveredListener = (forceUpdate) => {
|
|
|
23506
23893
|
const MOBILE_NAV_BREAKPOINT = 768;
|
|
23507
23894
|
const useMobileNavigation = (channelListRef, navOpen, closeMobileNav) => {
|
|
23508
23895
|
useEffect(() => {
|
|
23896
|
+
const isClickInsideChannelList = (event) => {
|
|
23897
|
+
const channelListElement = channelListRef.current;
|
|
23898
|
+
if (!channelListElement) return false;
|
|
23899
|
+
const eventPath = event.composedPath();
|
|
23900
|
+
return eventPath.includes(channelListElement);
|
|
23901
|
+
};
|
|
23509
23902
|
const handleClickOutside = (event) => {
|
|
23510
23903
|
if (typeof window !== "undefined" && window.innerWidth >= MOBILE_NAV_BREAKPOINT) {
|
|
23511
23904
|
return;
|
|
23512
23905
|
}
|
|
23513
|
-
if (closeMobileNav && channelListRef.current && !
|
|
23906
|
+
if (closeMobileNav && channelListRef.current && !isClickInsideChannelList(event) && navOpen) {
|
|
23514
23907
|
closeMobileNav();
|
|
23515
23908
|
}
|
|
23516
23909
|
};
|
|
@@ -24640,7 +25033,7 @@ const UnMemoizedLoadMoreButton = ({
|
|
|
24640
25033
|
return /* @__PURE__ */ jsx("div", { className: "str-chat__load-more-button", children: /* @__PURE__ */ jsx(
|
|
24641
25034
|
Button,
|
|
24642
25035
|
{
|
|
24643
|
-
appearance: "
|
|
25036
|
+
appearance: "ghost",
|
|
24644
25037
|
"aria-label": t("aria/Load More Channels"),
|
|
24645
25038
|
"data-testid": "load-more-button",
|
|
24646
25039
|
disabled: loading,
|
|
@@ -25248,6 +25641,36 @@ const useArchiveActionButtonBehavior = () => {
|
|
|
25248
25641
|
};
|
|
25249
25642
|
};
|
|
25250
25643
|
const defaultChannelActionSet = [
|
|
25644
|
+
{
|
|
25645
|
+
// eslint-disable-next-line react/display-name
|
|
25646
|
+
Component: forwardRef((_, ref) => {
|
|
25647
|
+
const { channel } = useChannelListItemContext();
|
|
25648
|
+
const dialogId2 = ChannelListItemActionButtons.getDialogId({
|
|
25649
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
25650
|
+
channelId: channel.id
|
|
25651
|
+
});
|
|
25652
|
+
const { dialog, dialogManager } = useDialogOnNearestManager({ id: dialogId2 });
|
|
25653
|
+
const dialogIsOpen = useDialogIsOpen(dialogId2, dialogManager?.id);
|
|
25654
|
+
return /* @__PURE__ */ jsx(
|
|
25655
|
+
Button,
|
|
25656
|
+
{
|
|
25657
|
+
appearance: "ghost",
|
|
25658
|
+
"aria-expanded": dialogIsOpen,
|
|
25659
|
+
"aria-pressed": dialogIsOpen,
|
|
25660
|
+
circular: true,
|
|
25661
|
+
onClick: (e) => {
|
|
25662
|
+
e.stopPropagation();
|
|
25663
|
+
dialog.toggle();
|
|
25664
|
+
},
|
|
25665
|
+
ref,
|
|
25666
|
+
size: "sm",
|
|
25667
|
+
variant: "secondary",
|
|
25668
|
+
children: /* @__PURE__ */ jsx(IconDotGrid1x3Horizontal, {})
|
|
25669
|
+
}
|
|
25670
|
+
);
|
|
25671
|
+
}),
|
|
25672
|
+
placement: "quick-dropdown-toggle"
|
|
25673
|
+
},
|
|
25251
25674
|
{
|
|
25252
25675
|
Component() {
|
|
25253
25676
|
const behaviorProps = useArchiveActionButtonBehavior();
|
|
@@ -25380,7 +25803,7 @@ const defaultChannelActionSet = [
|
|
|
25380
25803
|
const membership = useChannelMembershipState(channel);
|
|
25381
25804
|
const dialogId2 = ChannelListItemActionButtons.getDialogId(
|
|
25382
25805
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
25383
|
-
channel.id
|
|
25806
|
+
{ channelId: channel.id }
|
|
25384
25807
|
);
|
|
25385
25808
|
const { dialog } = useDialogOnNearestManager({ id: dialogId2 });
|
|
25386
25809
|
const [inProgress, setInProgress] = useState(false);
|
|
@@ -25482,59 +25905,23 @@ const useBaseChannelActionSetFilter = (channelActionSet) => {
|
|
|
25482
25905
|
const connectedUserIsMember = typeof membership.user !== "undefined";
|
|
25483
25906
|
const ownCapabilities = channel.data?.own_capabilities;
|
|
25484
25907
|
return useMemo(() => {
|
|
25485
|
-
const filtered = channelActionSet.filter(
|
|
25486
|
-
(action)
|
|
25487
|
-
|
|
25488
|
-
|
|
25489
|
-
|
|
25490
|
-
|
|
25491
|
-
|
|
25492
|
-
|
|
25493
|
-
|
|
25494
|
-
|
|
25495
|
-
|
|
25496
|
-
|
|
25497
|
-
|
|
25498
|
-
|
|
25499
|
-
|
|
25500
|
-
|
|
25501
|
-
|
|
25502
|
-
},
|
|
25503
|
-
isDirectMessageChannel: false
|
|
25504
|
-
},
|
|
25505
|
-
{
|
|
25506
|
-
action: { placement: "dropdown", type: "mute" },
|
|
25507
|
-
isDirectMessageChannel: true,
|
|
25508
|
-
ownCapabilities: P.when(
|
|
25509
|
-
(capabilities) => capabilities?.includes("mute-channel")
|
|
25510
|
-
)
|
|
25511
|
-
},
|
|
25512
|
-
{
|
|
25513
|
-
action: { placement: "quick", type: "mute" },
|
|
25514
|
-
isDirectMessageChannel: false,
|
|
25515
|
-
ownCapabilities: P.when(
|
|
25516
|
-
(capabilities) => capabilities?.includes("mute-channel")
|
|
25517
|
-
)
|
|
25518
|
-
},
|
|
25519
|
-
{
|
|
25520
|
-
action: { type: "ban" },
|
|
25521
|
-
memberCount: P.number.gt(0).and(P.number.lte(2)),
|
|
25522
|
-
ownCapabilities: P.when(
|
|
25523
|
-
(capabilities) => capabilities?.includes("ban-channel-members")
|
|
25524
|
-
)
|
|
25525
|
-
},
|
|
25526
|
-
{
|
|
25527
|
-
action: { type: "leave" },
|
|
25528
|
-
ownCapabilities: P.when(
|
|
25529
|
-
(capabilities) => capabilities?.includes("leave-channel")
|
|
25530
|
-
)
|
|
25531
|
-
},
|
|
25532
|
-
{
|
|
25533
|
-
action: { connectedUserIsMember: true, type: "pin" }
|
|
25534
|
-
},
|
|
25535
|
-
() => true
|
|
25536
|
-
).otherwise(() => false)
|
|
25537
|
-
);
|
|
25908
|
+
const filtered = channelActionSet.filter((action) => {
|
|
25909
|
+
if (action.placement === "quick-dropdown-toggle") return true;
|
|
25910
|
+
switch (action.type) {
|
|
25911
|
+
case "archive":
|
|
25912
|
+
return connectedUserIsMember && (action.placement === "quick" && isDirectMessageChannel || action.placement === "dropdown" && !isDirectMessageChannel);
|
|
25913
|
+
case "mute":
|
|
25914
|
+
return ownCapabilities?.includes("mute-channel") && (action.placement === "dropdown" && isDirectMessageChannel || action.placement === "quick" && !isDirectMessageChannel);
|
|
25915
|
+
case "ban":
|
|
25916
|
+
return memberCount > 0 && memberCount <= 2 && ownCapabilities?.includes("ban-channel-members");
|
|
25917
|
+
case "leave":
|
|
25918
|
+
return ownCapabilities?.includes("leave-channel");
|
|
25919
|
+
case "pin":
|
|
25920
|
+
return connectedUserIsMember;
|
|
25921
|
+
default:
|
|
25922
|
+
return true;
|
|
25923
|
+
}
|
|
25924
|
+
});
|
|
25538
25925
|
return filtered;
|
|
25539
25926
|
}, [
|
|
25540
25927
|
channelActionSet,
|
|
@@ -25545,17 +25932,18 @@ const useBaseChannelActionSetFilter = (channelActionSet) => {
|
|
|
25545
25932
|
]);
|
|
25546
25933
|
};
|
|
25547
25934
|
const ChannelListItemActionButtons = () => {
|
|
25935
|
+
const { ContextMenu: ContextMenuComponent = ContextMenu } = useComponentContext();
|
|
25548
25936
|
const { channel } = useChannelListItemContext();
|
|
25549
25937
|
const [referenceElement, setReferenceElement] = React.useState(null);
|
|
25550
|
-
const dialogId2 = ChannelListItemActionButtons.getDialogId(
|
|
25938
|
+
const dialogId2 = ChannelListItemActionButtons.getDialogId({
|
|
25551
25939
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
25552
|
-
channel.id
|
|
25553
|
-
);
|
|
25940
|
+
channelId: channel.id
|
|
25941
|
+
});
|
|
25554
25942
|
const { dialog, dialogManager } = useDialogOnNearestManager({ id: dialogId2 });
|
|
25555
25943
|
const dialogIsOpen = useDialogIsOpen(dialogId2, dialogManager?.id);
|
|
25556
25944
|
const filteredActionSet = useBaseChannelActionSetFilter(defaultChannelActionSet);
|
|
25557
|
-
const
|
|
25558
|
-
if (
|
|
25945
|
+
const { dropdownActionSet, quickActionSet, quickDropdownToggleAction } = useSplitActionSet(filteredActionSet);
|
|
25946
|
+
if (quickActionSet.length + dropdownActionSet.length === 0) {
|
|
25559
25947
|
return null;
|
|
25560
25948
|
}
|
|
25561
25949
|
return /* @__PURE__ */ jsxs(
|
|
@@ -25565,26 +25953,10 @@ const ChannelListItemActionButtons = () => {
|
|
|
25565
25953
|
"str-chat__channel-list-item__action-buttons--active": dialogIsOpen
|
|
25566
25954
|
}),
|
|
25567
25955
|
children: [
|
|
25568
|
-
|
|
25569
|
-
|
|
25570
|
-
{
|
|
25571
|
-
appearance: "ghost",
|
|
25572
|
-
"aria-expanded": dialogIsOpen,
|
|
25573
|
-
"aria-pressed": dialogIsOpen,
|
|
25574
|
-
circular: true,
|
|
25575
|
-
onClick: (e) => {
|
|
25576
|
-
e.stopPropagation();
|
|
25577
|
-
dialog.toggle();
|
|
25578
|
-
},
|
|
25579
|
-
ref: setReferenceElement,
|
|
25580
|
-
size: "sm",
|
|
25581
|
-
variant: "secondary",
|
|
25582
|
-
children: /* @__PURE__ */ jsx(IconDotGrid1x3Horizontal, {})
|
|
25583
|
-
}
|
|
25584
|
-
),
|
|
25585
|
-
splitActionSet.quickActionSet.map(({ Component: Component2, type }) => /* @__PURE__ */ jsx(Component2, {}, type)),
|
|
25956
|
+
quickDropdownToggleAction && dropdownActionSet.length > 0 && /* @__PURE__ */ jsx(quickDropdownToggleAction.Component, { ref: setReferenceElement }),
|
|
25957
|
+
quickActionSet.map(({ Component: Component2, type }) => /* @__PURE__ */ jsx(Component2, {}, type)),
|
|
25586
25958
|
/* @__PURE__ */ jsx(
|
|
25587
|
-
|
|
25959
|
+
ContextMenuComponent,
|
|
25588
25960
|
{
|
|
25589
25961
|
className: "str-chat__channel-list-item__action-buttons-context-menu",
|
|
25590
25962
|
dialogManagerId: dialogManager?.id,
|
|
@@ -25594,14 +25966,14 @@ const ChannelListItemActionButtons = () => {
|
|
|
25594
25966
|
referenceElement,
|
|
25595
25967
|
tabIndex: -1,
|
|
25596
25968
|
trapFocus: true,
|
|
25597
|
-
children:
|
|
25969
|
+
children: dropdownActionSet.map(({ Component: Component2, type }) => /* @__PURE__ */ jsx(Component2, {}, type))
|
|
25598
25970
|
}
|
|
25599
25971
|
)
|
|
25600
25972
|
]
|
|
25601
25973
|
}
|
|
25602
25974
|
);
|
|
25603
25975
|
};
|
|
25604
|
-
ChannelListItemActionButtons.getDialogId = (channelId) => `channel-action-buttons-${channelId}`;
|
|
25976
|
+
ChannelListItemActionButtons.getDialogId = ({ channelId }) => `channel-action-buttons-${channelId}`;
|
|
25605
25977
|
ChannelListItemActionButtons.displayName = "ChannelListItemActionButtons";
|
|
25606
25978
|
function ChannelListItemTimestamp({ lastMessage }) {
|
|
25607
25979
|
const { t, tDateTimeParser } = useTranslationContext("ChannelListItemTimestamp");
|
|
@@ -26927,7 +27299,7 @@ const VoiceRecordingPlayerUI = ({ audioPlayer }) => {
|
|
|
26927
27299
|
secondsElapsed
|
|
26928
27300
|
} = useStateStore(audioPlayer?.state, audioPlayerStateSelector) ?? {};
|
|
26929
27301
|
return /* @__PURE__ */ jsxs("div", { className: rootClassName, "data-testid": "voice-recording-widget", children: [
|
|
26930
|
-
/* @__PURE__ */ jsx(PlayButton, { isPlaying: !!isPlaying, onClick: audioPlayer.togglePlay }),
|
|
27302
|
+
/* @__PURE__ */ jsx("div", { className: "str-chat__message-attachment__voice-recording-widget__play-button-container", children: /* @__PURE__ */ jsx(PlayButton, { isPlaying: !!isPlaying, onClick: audioPlayer.togglePlay }) }),
|
|
26931
27303
|
/* @__PURE__ */ jsx("div", { className: "str-chat__message-attachment__voice-recording-widget__metadata", children: /* @__PURE__ */ jsxs("div", { className: "str-chat__message-attachment__voice-recording-widget__audio-state", children: [
|
|
26932
27304
|
/* @__PURE__ */ jsx("div", { className: "str-chat__message-attachment__voice-recording-widget__timer", children: durationSeconds ? /* @__PURE__ */ jsx(
|
|
26933
27305
|
DurationDisplay,
|
|
@@ -27336,23 +27708,44 @@ const FileAttachment = ({ attachment }) => {
|
|
|
27336
27708
|
);
|
|
27337
27709
|
};
|
|
27338
27710
|
const Giphy = ({ attachment }) => {
|
|
27339
|
-
const { giphyVersion: giphyVersionName } = useChannelStateContext();
|
|
27711
|
+
const { giphyVersion: giphyVersionName, imageAttachmentSizeHandler } = useChannelStateContext();
|
|
27340
27712
|
const { BaseImage: BaseImage$1 = BaseImage } = useComponentContext();
|
|
27341
27713
|
const { t } = useTranslationContext();
|
|
27342
27714
|
const usesDefaultBaseImage = BaseImage$1 === BaseImage;
|
|
27715
|
+
const imageElement = useRef(null);
|
|
27716
|
+
const [attachmentConfiguration, setAttachmentConfiguration] = useState(void 0);
|
|
27343
27717
|
const imageDescriptors = useMemo(
|
|
27344
27718
|
() => toGalleryItemDescriptors(attachment, { giphyVersionName }),
|
|
27345
27719
|
[attachment, giphyVersionName]
|
|
27346
27720
|
);
|
|
27347
|
-
|
|
27348
|
-
const
|
|
27721
|
+
const alt = imageDescriptors && imageDescriptors.alt;
|
|
27722
|
+
const dimensions = imageDescriptors && imageDescriptors.dimensions;
|
|
27723
|
+
const imageUrl = imageDescriptors && imageDescriptors.imageUrl;
|
|
27724
|
+
const title = imageDescriptors && imageDescriptors.title;
|
|
27725
|
+
const resolvedImageUrl = attachmentConfiguration?.url || imageUrl;
|
|
27726
|
+
const imageStyleVariables = useMemo(() => {
|
|
27727
|
+
const originalHeight = Number(dimensions?.height);
|
|
27728
|
+
const originalWidth = Number(dimensions?.width);
|
|
27729
|
+
return {
|
|
27730
|
+
"--original-height": String(originalHeight > 1 ? originalHeight : 1e6),
|
|
27731
|
+
"--original-width": String(originalWidth > 1 ? originalWidth : 1e6)
|
|
27732
|
+
};
|
|
27733
|
+
}, [dimensions?.height, dimensions?.width]);
|
|
27734
|
+
useLayoutEffect(() => {
|
|
27735
|
+
if (!imageElement.current || !imageAttachmentSizeHandler) return;
|
|
27736
|
+
const config = imageAttachmentSizeHandler(attachment, imageElement.current);
|
|
27737
|
+
setAttachmentConfiguration(config);
|
|
27738
|
+
}, [attachment, imageAttachmentSizeHandler]);
|
|
27739
|
+
if (!imageUrl) return null;
|
|
27349
27740
|
return /* @__PURE__ */ jsxs("div", { className: clsx(`str-chat__message-attachment-giphy`), children: [
|
|
27350
27741
|
/* @__PURE__ */ jsx(
|
|
27351
27742
|
BaseImage$1,
|
|
27352
27743
|
{
|
|
27353
27744
|
alt: alt ?? title ?? t("User uploaded content"),
|
|
27354
27745
|
height: dimensions?.height,
|
|
27355
|
-
|
|
27746
|
+
ref: imageElement,
|
|
27747
|
+
src: resolvedImageUrl,
|
|
27748
|
+
style: imageStyleVariables,
|
|
27356
27749
|
width: dimensions?.width,
|
|
27357
27750
|
...usesDefaultBaseImage ? { showDownloadButtonOnError: false } : {}
|
|
27358
27751
|
}
|
|
@@ -28011,6 +28404,7 @@ export {
|
|
|
28011
28404
|
ContextMenuBackButton,
|
|
28012
28405
|
ContextMenuBody,
|
|
28013
28406
|
ContextMenuButton,
|
|
28407
|
+
ContextMenuContent,
|
|
28014
28408
|
ContextMenuHeader,
|
|
28015
28409
|
ContextMenuRoot,
|
|
28016
28410
|
CooldownTimer,
|
|
@@ -28245,6 +28639,7 @@ export {
|
|
|
28245
28639
|
MessageProvider,
|
|
28246
28640
|
MessageReactions,
|
|
28247
28641
|
MessageReactionsDetail,
|
|
28642
|
+
MessageReactionsDetailLoadingIndicator,
|
|
28248
28643
|
MessageRepliesCountButton,
|
|
28249
28644
|
MessageSearchResultItem,
|
|
28250
28645
|
MessageStatus,
|