stream-chat-react 14.0.1 → 14.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/emojis.js +8 -8
- package/dist/cjs/emojis.js.map +1 -1
- package/dist/cjs/index.js +18599 -16466
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/{WithAudioPlayback.ba05c770.js → useNotificationApi.f2c7704d.js} +1442 -1363
- package/dist/cjs/useNotificationApi.f2c7704d.js.map +1 -0
- package/dist/css/index.css +614 -557
- package/dist/css/index.css.map +1 -1
- package/dist/es/emojis.mjs +1 -1
- package/dist/es/index.mjs +18216 -16083
- package/dist/es/index.mjs.map +1 -1
- package/dist/es/{WithAudioPlayback.610fdf2c.mjs → useNotificationApi.f91ae46b.mjs} +1576 -1497
- package/dist/es/useNotificationApi.f91ae46b.mjs.map +1 -0
- package/dist/types/a11y/a11yUtils.d.ts +23 -0
- package/dist/types/a11y/a11yUtils.d.ts.map +1 -0
- package/dist/types/a11y/hooks/useAriaIdentifiers.d.ts +15 -0
- package/dist/types/a11y/hooks/useAriaIdentifiers.d.ts.map +1 -0
- package/dist/types/a11y/hooks/useResolvedModalAriaProps.d.ts +22 -0
- package/dist/types/a11y/hooks/useResolvedModalAriaProps.d.ts.map +1 -0
- package/dist/types/components/Accessibility/AriaLiveRegion.d.ts +3 -0
- package/dist/types/components/Accessibility/AriaLiveRegion.d.ts.map +1 -0
- package/dist/types/components/Accessibility/NotificationAnnouncer.d.ts +14 -0
- package/dist/types/components/Accessibility/NotificationAnnouncer.d.ts.map +1 -0
- package/dist/types/components/Accessibility/hooks/useIncomingMessageAnnouncements.d.ts +9 -0
- package/dist/types/components/Accessibility/hooks/useIncomingMessageAnnouncements.d.ts.map +1 -0
- package/dist/types/components/Accessibility/index.d.ts +5 -0
- package/dist/types/components/Accessibility/index.d.ts.map +1 -0
- package/dist/types/components/Accessibility/useAriaLiveAnnouncer.d.ts +9 -0
- package/dist/types/components/Accessibility/useAriaLiveAnnouncer.d.ts.map +1 -0
- package/dist/types/components/Attachment/Audio.d.ts.map +1 -1
- package/dist/types/components/Attachment/LinkPreview/CardAudio.d.ts.map +1 -1
- package/dist/types/components/Attachment/ModalGallery.d.ts.map +1 -1
- package/dist/types/components/Attachment/VoiceRecording.d.ts.map +1 -1
- package/dist/types/components/AudioPlayback/components/DurationDisplay.d.ts.map +1 -1
- package/dist/types/components/AudioPlayback/components/ProgressBar.d.ts +5 -1
- package/dist/types/components/AudioPlayback/components/ProgressBar.d.ts.map +1 -1
- package/dist/types/components/AudioPlayback/components/WaveProgressBar.d.ts +5 -1
- package/dist/types/components/AudioPlayback/components/WaveProgressBar.d.ts.map +1 -1
- package/dist/types/components/AudioPlayback/components/formatTime.d.ts +2 -0
- package/dist/types/components/AudioPlayback/components/formatTime.d.ts.map +1 -0
- package/dist/types/components/AudioPlayback/components/keyboardSeek.d.ts +12 -0
- package/dist/types/components/AudioPlayback/components/keyboardSeek.d.ts.map +1 -0
- package/dist/types/components/AudioPlayback/components/progressBarA11y.d.ts +10 -0
- package/dist/types/components/AudioPlayback/components/progressBarA11y.d.ts.map +1 -0
- package/dist/types/components/Avatar/Avatar.d.ts +1 -1
- package/dist/types/components/Avatar/Avatar.d.ts.map +1 -1
- package/dist/types/components/BaseImage/BaseImage.d.ts.map +1 -1
- package/dist/types/components/Button/PlayButton.d.ts.map +1 -1
- package/dist/types/components/ChannelList/hooks/usePaginatedChannels.d.ts.map +1 -1
- package/dist/types/components/ChannelListItem/ChannelListItem.d.ts +2 -0
- package/dist/types/components/ChannelListItem/ChannelListItem.d.ts.map +1 -1
- package/dist/types/components/ChannelListItem/ChannelListItemActionButtons.d.ts.map +1 -1
- package/dist/types/components/ChannelListItem/ChannelListItemActionButtons.defaults.d.ts.map +1 -1
- package/dist/types/components/ChannelListItem/ChannelListItemUI.d.ts.map +1 -1
- package/dist/types/components/Chat/Chat.d.ts.map +1 -1
- package/dist/types/components/ChatView/ChatView.a11y.utility.d.ts +26 -0
- package/dist/types/components/ChatView/ChatView.a11y.utility.d.ts.map +1 -0
- package/dist/types/components/ChatView/ChatView.d.ts +9 -0
- package/dist/types/components/ChatView/ChatView.d.ts.map +1 -1
- package/dist/types/components/Dialog/components/Alert.d.ts +3 -1
- package/dist/types/components/Dialog/components/Alert.d.ts.map +1 -1
- package/dist/types/components/Dialog/components/ContextMenu.d.ts +31 -6
- package/dist/types/components/Dialog/components/ContextMenu.d.ts.map +1 -1
- package/dist/types/components/Dialog/components/Prompt.d.ts +3 -1
- package/dist/types/components/Dialog/components/Prompt.d.ts.map +1 -1
- package/dist/types/components/Dialog/components/Viewer.d.ts +3 -1
- package/dist/types/components/Dialog/components/Viewer.d.ts.map +1 -1
- package/dist/types/components/Dialog/service/DialogAnchor.d.ts.map +1 -1
- package/dist/types/components/Form/Dropdown.d.ts +2 -1
- package/dist/types/components/Form/Dropdown.d.ts.map +1 -1
- package/dist/types/components/Form/NumericInput.d.ts.map +1 -1
- package/dist/types/components/Form/SwitchField.d.ts +5 -2
- package/dist/types/components/Form/SwitchField.d.ts.map +1 -1
- package/dist/types/components/Form/TextInput.d.ts.map +1 -1
- package/dist/types/components/Icons/BaseIcon.d.ts +4 -1
- package/dist/types/components/Icons/BaseIcon.d.ts.map +1 -1
- package/dist/types/components/Icons/createIcon.d.ts +6 -3
- package/dist/types/components/Icons/createIcon.d.ts.map +1 -1
- package/dist/types/components/Icons/icons.d.ts +81 -82
- package/dist/types/components/Icons/icons.d.ts.map +1 -1
- package/dist/types/components/InfiniteScrollPaginator/InfiniteScroll.d.ts.map +1 -1
- package/dist/types/components/Loading/LoadingIndicator.d.ts +2 -2
- package/dist/types/components/Loading/LoadingIndicator.d.ts.map +1 -1
- package/dist/types/components/Location/ShareLocationDialog.d.ts +1 -0
- package/dist/types/components/Location/ShareLocationDialog.d.ts.map +1 -1
- package/dist/types/components/MediaRecorder/AudioRecorder/AudioRecorderRecordingControls.d.ts.map +1 -1
- package/dist/types/components/MediaRecorder/AudioRecorder/AudioRecordingButtonWithNotification.d.ts.map +1 -1
- package/dist/types/components/MediaRecorder/AudioRecorder/AudioRecordingPlayback.d.ts.map +1 -1
- package/dist/types/components/Message/Message.d.ts.map +1 -1
- package/dist/types/components/Message/MessageText.d.ts.map +1 -1
- package/dist/types/components/Message/MessageUI.d.ts.map +1 -1
- package/dist/types/components/Message/types.d.ts +4 -2
- package/dist/types/components/Message/types.d.ts.map +1 -1
- package/dist/types/components/MessageActions/DeleteMessageAlert.d.ts.map +1 -1
- package/dist/types/components/MessageActions/MessageActions.d.ts.map +1 -1
- package/dist/types/components/MessageActions/MessageActions.defaults.d.ts.map +1 -1
- package/dist/types/components/MessageBounce/MessageBouncePrompt.d.ts.map +1 -1
- package/dist/types/components/MessageComposer/AttachmentPreviewList/AttachmentPreviewList.d.ts.map +1 -1
- package/dist/types/components/MessageComposer/AttachmentPreviewList/AudioAttachmentPreview.d.ts.map +1 -1
- package/dist/types/components/MessageComposer/AttachmentPreviewList/utils/AttachmentPreviewRoot.d.ts.map +1 -1
- package/dist/types/components/MessageComposer/AttachmentSelector/AttachmentSelector.d.ts.map +1 -1
- package/dist/types/components/MessageComposer/AttachmentSelector/CommandsMenu.d.ts +2 -1
- package/dist/types/components/MessageComposer/AttachmentSelector/CommandsMenu.d.ts.map +1 -1
- package/dist/types/components/MessageComposer/CommandChip.d.ts.map +1 -1
- package/dist/types/components/MessageComposer/EditedMessagePreview.d.ts.map +1 -1
- package/dist/types/components/MessageComposer/QuotedMessagePreview.d.ts +4 -2
- package/dist/types/components/MessageComposer/QuotedMessagePreview.d.ts.map +1 -1
- package/dist/types/components/MessageComposer/WithDragAndDropUpload.d.ts.map +1 -1
- package/dist/types/components/MessageComposer/hooks/index.d.ts +1 -0
- package/dist/types/components/MessageComposer/hooks/index.d.ts.map +1 -1
- package/dist/types/components/MessageComposer/hooks/useMessageComposerCommands.d.ts +9 -0
- package/dist/types/components/MessageComposer/hooks/useMessageComposerCommands.d.ts.map +1 -0
- package/dist/types/components/MessageList/MessageList.d.ts.map +1 -1
- package/dist/types/components/MessageList/NewMessageNotification.d.ts.map +1 -1
- package/dist/types/components/MessageList/ScrollToLatestMessageButton.d.ts +1 -2
- package/dist/types/components/MessageList/ScrollToLatestMessageButton.d.ts.map +1 -1
- package/dist/types/components/MessageList/UnreadMessagesNotification.d.ts.map +1 -1
- package/dist/types/components/MessageList/UnreadMessagesSeparator.d.ts.map +1 -1
- package/dist/types/components/MessageList/VirtualizedMessageList.d.ts +1 -1
- package/dist/types/components/MessageList/VirtualizedMessageList.d.ts.map +1 -1
- package/dist/types/components/MessageList/hooks/MessageList/useMessageListScrollManager.d.ts +1 -0
- package/dist/types/components/MessageList/hooks/MessageList/useMessageListScrollManager.d.ts.map +1 -1
- package/dist/types/components/MessageList/hooks/MessageList/useScrollLocationLogic.d.ts.map +1 -1
- package/dist/types/components/MessageList/hooks/useReducedMotionPreference.d.ts +2 -0
- package/dist/types/components/MessageList/hooks/useReducedMotionPreference.d.ts.map +1 -0
- package/dist/types/components/Modal/CloseButtonOnModalOverlay.d.ts.map +1 -1
- package/dist/types/components/Modal/GlobalModal.d.ts +9 -1
- package/dist/types/components/Modal/GlobalModal.d.ts.map +1 -1
- package/dist/types/components/Notifications/Notification.d.ts.map +1 -1
- package/dist/types/components/Notifications/NotificationList.d.ts.map +1 -1
- package/dist/types/components/Poll/PollActions/AddCommentPrompt.d.ts.map +1 -1
- package/dist/types/components/Poll/PollActions/PollAnswerList.d.ts.map +1 -1
- package/dist/types/components/Poll/PollActions/PollOptionsFullList.d.ts.map +1 -1
- package/dist/types/components/Poll/PollActions/PollResults/PollResults.d.ts.map +1 -1
- package/dist/types/components/Poll/PollActions/SuggestPollOptionPrompt.d.ts.map +1 -1
- package/dist/types/components/Poll/PollCreationDialog/MultipleAnswersField.d.ts.map +1 -1
- package/dist/types/components/Poll/PollCreationDialog/NameField.d.ts.map +1 -1
- package/dist/types/components/Poll/PollCreationDialog/OptionFieldSet.d.ts.map +1 -1
- package/dist/types/components/Poll/PollCreationDialog/PollCreationDialog.d.ts.map +1 -1
- package/dist/types/components/Poll/PollOptionSelector.d.ts.map +1 -1
- package/dist/types/components/Reactions/MessageReactions.d.ts.map +1 -1
- package/dist/types/components/Reactions/MessageReactionsDetail.d.ts.map +1 -1
- package/dist/types/components/Reactions/ReactionSelector.d.ts.map +1 -1
- package/dist/types/components/Search/SearchBar/SearchBar.d.ts.map +1 -1
- package/dist/types/components/Search/SearchResults/SearchResultItem.d.ts.map +1 -1
- package/dist/types/components/Search/SearchResults/SearchResultsHeader.d.ts.map +1 -1
- package/dist/types/components/SkipNavigation/SkipNavigation.d.ts +38 -0
- package/dist/types/components/SkipNavigation/SkipNavigation.d.ts.map +1 -0
- package/dist/types/components/SkipNavigation/index.d.ts +2 -0
- package/dist/types/components/SkipNavigation/index.d.ts.map +1 -0
- package/dist/types/components/TextareaComposer/SuggestionList/CommandItem.d.ts +1 -0
- package/dist/types/components/TextareaComposer/SuggestionList/CommandItem.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 +1 -0
- package/dist/types/components/TextareaComposer/TextareaComposer.d.ts.map +1 -1
- package/dist/types/components/Threads/ThreadList/ThreadList.d.ts.map +1 -1
- package/dist/types/components/TypingIndicator/TypingIndicator.d.ts.map +1 -1
- package/dist/types/components/TypingIndicator/TypingIndicatorHeader.d.ts.map +1 -1
- package/dist/types/components/TypingIndicator/utils/getTypingStatusMessage.d.ts +8 -0
- package/dist/types/components/TypingIndicator/utils/getTypingStatusMessage.d.ts.map +1 -0
- package/dist/types/components/VisuallyHidden/VisuallyHidden.d.ts +7 -0
- package/dist/types/components/VisuallyHidden/VisuallyHidden.d.ts.map +1 -0
- package/dist/types/components/VisuallyHidden/index.d.ts +2 -0
- package/dist/types/components/VisuallyHidden/index.d.ts.map +1 -0
- package/dist/types/components/index.d.ts +3 -0
- package/dist/types/components/index.d.ts.map +1 -1
- package/dist/types/context/ComponentContext.d.ts +10 -1
- package/dist/types/context/ComponentContext.d.ts.map +1 -1
- package/dist/types/context/ModalContext.d.ts +1 -0
- package/dist/types/context/ModalContext.d.ts.map +1 -1
- package/dist/types/context/index.d.ts +1 -0
- package/dist/types/context/index.d.ts.map +1 -1
- package/dist/types/i18n/Streami18n.d.ts +61 -2
- package/dist/types/i18n/Streami18n.d.ts.map +1 -1
- package/dist/types/i18n/TranslationBuilder/notifications/translators.d.ts +1 -0
- package/dist/types/i18n/TranslationBuilder/notifications/translators.d.ts.map +1 -1
- package/dist/types/i18n/TranslationBuilder/notifications/translatorsByNotificationType.d.ts.map +1 -1
- package/package.json +9 -5
- package/dist/cjs/WithAudioPlayback.ba05c770.js.map +0 -1
- package/dist/es/WithAudioPlayback.610fdf2c.mjs.map +0 -1
|
@@ -3,12 +3,12 @@ const jsxRuntime = require("react/jsx-runtime");
|
|
|
3
3
|
const React = require("react");
|
|
4
4
|
const react = require("@floating-ui/react");
|
|
5
5
|
const streamChat = require("stream-chat");
|
|
6
|
-
const throttle = require("lodash.throttle");
|
|
7
|
-
const shim = require("use-sync-external-store/shim");
|
|
8
6
|
const clsx = require("clsx");
|
|
9
7
|
const debounce = require("lodash.debounce");
|
|
8
|
+
const throttle = require("lodash.throttle");
|
|
10
9
|
const Dayjs = require("dayjs");
|
|
11
10
|
const linkify = require("linkifyjs");
|
|
11
|
+
const shim = require("use-sync-external-store/shim");
|
|
12
12
|
const nanoid = require("nanoid");
|
|
13
13
|
const deepequal = require("react-fast-compare");
|
|
14
14
|
const emojiRegex = require("emoji-regex");
|
|
@@ -390,15 +390,96 @@ const useTypingContext = (componentName) => {
|
|
|
390
390
|
}
|
|
391
391
|
return contextValue;
|
|
392
392
|
};
|
|
393
|
-
const
|
|
394
|
-
"
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
393
|
+
const NOTIFICATION_TARGET_PANELS = [
|
|
394
|
+
"channel",
|
|
395
|
+
"thread",
|
|
396
|
+
"channel-list",
|
|
397
|
+
"thread-list"
|
|
398
|
+
];
|
|
399
|
+
const isNotificationTargetPanel = (value) => typeof value === "string" && NOTIFICATION_TARGET_PANELS.includes(value);
|
|
400
|
+
const getNotificationTargetPanel = (notification) => {
|
|
401
|
+
const targetTag = notification.tags?.find((tag) => tag.startsWith("target:"));
|
|
402
|
+
if (targetTag) {
|
|
403
|
+
const candidate = targetTag.slice("target:".length);
|
|
404
|
+
if (isNotificationTargetPanel(candidate)) return candidate;
|
|
400
405
|
}
|
|
401
|
-
|
|
406
|
+
const panel = notification.origin.context?.panel;
|
|
407
|
+
return isNotificationTargetPanel(panel) ? panel : void 0;
|
|
408
|
+
};
|
|
409
|
+
const getNotificationTargetPanels = (notification) => {
|
|
410
|
+
const targetPanels = (notification.tags ?? []).filter((tag) => tag.startsWith("target:")).map((tag) => tag.slice("target:".length)).filter(
|
|
411
|
+
(value) => isNotificationTargetPanel(value)
|
|
412
|
+
);
|
|
413
|
+
if (targetPanels.length > 0) {
|
|
414
|
+
return Array.from(new Set(targetPanels));
|
|
415
|
+
}
|
|
416
|
+
const panel = notification.origin.context?.panel;
|
|
417
|
+
return isNotificationTargetPanel(panel) ? [panel] : [];
|
|
418
|
+
};
|
|
419
|
+
const getNotificationTargetTag = (panel) => `target:${panel}`;
|
|
420
|
+
const addNotificationTargetTag = (panel, tags) => {
|
|
421
|
+
if (!panel) return tags ?? [];
|
|
422
|
+
return Array.from(/* @__PURE__ */ new Set([getNotificationTargetTag(panel), ...tags ?? []]));
|
|
423
|
+
};
|
|
424
|
+
const isNotificationForPanel = (notification, panel, options) => {
|
|
425
|
+
const explicitTargetPanels = getNotificationTargetPanels(notification);
|
|
426
|
+
if (explicitTargetPanels.length > 0) {
|
|
427
|
+
return explicitTargetPanels.includes(panel);
|
|
428
|
+
}
|
|
429
|
+
const resolvedPanel = options?.fallbackPanel ?? "channel";
|
|
430
|
+
return resolvedPanel === panel;
|
|
431
|
+
};
|
|
432
|
+
const variantToClass = {
|
|
433
|
+
danger: "str-chat__button--destructive",
|
|
434
|
+
primary: "str-chat__button--primary",
|
|
435
|
+
secondary: "str-chat__button--secondary"
|
|
436
|
+
};
|
|
437
|
+
const appearanceToClass = {
|
|
438
|
+
ghost: "str-chat__button--ghost",
|
|
439
|
+
outline: "str-chat__button--outline",
|
|
440
|
+
solid: "str-chat__button--solid"
|
|
441
|
+
};
|
|
442
|
+
const sizeToClass = {
|
|
443
|
+
lg: "str-chat__button--size-lg",
|
|
444
|
+
md: "str-chat__button--size-md",
|
|
445
|
+
sm: "str-chat__button--size-sm",
|
|
446
|
+
xs: "str-chat__button--size-xs"
|
|
447
|
+
};
|
|
448
|
+
const Button = React.forwardRef(function Button2({ appearance, children, circular, className, inverseTheme, size, variant, ...props }, ref) {
|
|
449
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
450
|
+
"button",
|
|
451
|
+
{
|
|
452
|
+
ref,
|
|
453
|
+
type: "button",
|
|
454
|
+
...props,
|
|
455
|
+
className: clsx(
|
|
456
|
+
"str-chat__button",
|
|
457
|
+
variant != null && variantToClass[variant],
|
|
458
|
+
appearance != null && appearanceToClass[appearance],
|
|
459
|
+
circular && "str-chat__button--circular",
|
|
460
|
+
inverseTheme && "str-chat__theme-inverse",
|
|
461
|
+
size != null && sizeToClass[size],
|
|
462
|
+
className
|
|
463
|
+
),
|
|
464
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "str-chat__button__content", children })
|
|
465
|
+
}
|
|
466
|
+
);
|
|
467
|
+
});
|
|
468
|
+
const BaseIcon = ({ className, decorative = true, ...props }) => {
|
|
469
|
+
const ariaHidden = props["aria-hidden"] ?? (decorative ? true : void 0);
|
|
470
|
+
const focusable = props.focusable ?? (decorative ? false : void 0);
|
|
471
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
472
|
+
"svg",
|
|
473
|
+
{
|
|
474
|
+
viewBox: "0 0 20 20",
|
|
475
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
476
|
+
...props,
|
|
477
|
+
"aria-hidden": ariaHidden,
|
|
478
|
+
className: clsx("str-chat__icon", className),
|
|
479
|
+
focusable
|
|
480
|
+
}
|
|
481
|
+
);
|
|
482
|
+
};
|
|
402
483
|
function toIconClass(name) {
|
|
403
484
|
return "str-chat__icon--" + name.replace(/^Icon/, "").replace(/([a-z])([A-Z])/g, "$1-$2").replace(/([A-Za-z])(\d)/g, "$1-$2").replace(/(\d)([A-Za-z])/g, "$1-$2").replace(/_/g, "-").toLowerCase();
|
|
404
485
|
}
|
|
@@ -1513,977 +1594,259 @@ const IconGiphy = createIcon(
|
|
|
1513
1594
|
)
|
|
1514
1595
|
] })
|
|
1515
1596
|
);
|
|
1516
|
-
const
|
|
1517
|
-
const
|
|
1518
|
-
const
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1597
|
+
const UnMemoizedEmptyStateIndicator = (props) => {
|
|
1598
|
+
const { listType, messageText } = props;
|
|
1599
|
+
const { t } = useTranslationContext("EmptyStateIndicator");
|
|
1600
|
+
if (listType === "thread") return null;
|
|
1601
|
+
if (listType === "channel") {
|
|
1602
|
+
const text = t("No conversations yet");
|
|
1603
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "str-chat__channel-list-empty", children: [
|
|
1604
|
+
/* @__PURE__ */ jsxRuntime.jsx(IconMessageBubbles, {}),
|
|
1605
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { role: "listitem", children: text })
|
|
1606
|
+
] });
|
|
1607
|
+
}
|
|
1608
|
+
if (listType === "message") {
|
|
1609
|
+
const text = t(messageText || "Send a message to start the conversation");
|
|
1610
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "str-chat__empty-channel", children: [
|
|
1611
|
+
/* @__PURE__ */ jsxRuntime.jsx(IconMessageBubble, {}),
|
|
1612
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "str-chat__empty-channel-text", role: "listitem", children: text })
|
|
1613
|
+
] });
|
|
1614
|
+
}
|
|
1615
|
+
return /* @__PURE__ */ jsxRuntime.jsx("p", { children: t("No items exist") });
|
|
1523
1616
|
};
|
|
1524
|
-
const
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
title,
|
|
1536
|
-
waveformData
|
|
1537
|
-
}) {
|
|
1538
|
-
this._plugins = /* @__PURE__ */ new Map();
|
|
1539
|
-
this.playTimeout = void 0;
|
|
1540
|
-
this.unsubscribeEventListeners = null;
|
|
1541
|
-
this._disposed = false;
|
|
1542
|
-
this._metadataProbe = null;
|
|
1543
|
-
this._restoringPosition = false;
|
|
1544
|
-
this._removalTimeout = void 0;
|
|
1545
|
-
this.setDurationSeconds = (durationSeconds2) => {
|
|
1546
|
-
this._data.durationSeconds = durationSeconds2;
|
|
1547
|
-
this.state.partialNext({ durationSeconds: durationSeconds2 });
|
|
1548
|
-
};
|
|
1549
|
-
this.setPlaybackStartSafetyTimeout = () => {
|
|
1550
|
-
clearTimeout(this.playTimeout);
|
|
1551
|
-
this.playTimeout = setTimeout(() => {
|
|
1552
|
-
if (!this.elementRef) return;
|
|
1553
|
-
try {
|
|
1554
|
-
this.elementRef.pause();
|
|
1555
|
-
this.state.partialNext({ isPlaying: false });
|
|
1556
|
-
} catch (e) {
|
|
1557
|
-
this.registerError({ errCode: "failed-to-start" });
|
|
1558
|
-
}
|
|
1559
|
-
}, 2e3);
|
|
1560
|
-
};
|
|
1561
|
-
this.updateDurationFromElement = (element) => {
|
|
1562
|
-
const duration = element.duration;
|
|
1563
|
-
if (typeof duration !== "number" || isNaN(duration) || !isFinite(duration) || duration <= 0) {
|
|
1564
|
-
return;
|
|
1565
|
-
}
|
|
1566
|
-
this.setDurationSeconds(duration);
|
|
1567
|
-
};
|
|
1568
|
-
this.clearMetadataProbe = () => {
|
|
1569
|
-
const probe = this._metadataProbe;
|
|
1570
|
-
this._metadataProbe = null;
|
|
1571
|
-
this._metadataProbePromise = void 0;
|
|
1572
|
-
if (!probe) return;
|
|
1573
|
-
try {
|
|
1574
|
-
probe.pause();
|
|
1575
|
-
} catch {
|
|
1576
|
-
}
|
|
1577
|
-
probe.removeAttribute("src");
|
|
1578
|
-
try {
|
|
1579
|
-
probe.load();
|
|
1580
|
-
} catch {
|
|
1581
|
-
}
|
|
1582
|
-
};
|
|
1583
|
-
this.preloadMetadata = () => {
|
|
1584
|
-
if (this._disposed || this.durationSeconds != null || !this.src || this._metadataProbePromise || typeof document === "undefined") {
|
|
1585
|
-
return;
|
|
1586
|
-
}
|
|
1587
|
-
const probe = document.createElement("audio");
|
|
1588
|
-
probe.preload = "metadata";
|
|
1589
|
-
this._metadataProbe = probe;
|
|
1590
|
-
this._metadataProbePromise = new Promise((resolve) => {
|
|
1591
|
-
const cleanup = () => {
|
|
1592
|
-
probe.removeEventListener("loadedmetadata", handleLoadedMetadata);
|
|
1593
|
-
probe.removeEventListener("error", handleError);
|
|
1594
|
-
if (this._metadataProbe === probe) {
|
|
1595
|
-
this.clearMetadataProbe();
|
|
1596
|
-
} else {
|
|
1597
|
-
this._metadataProbePromise = void 0;
|
|
1598
|
-
}
|
|
1599
|
-
resolve();
|
|
1600
|
-
};
|
|
1601
|
-
const handleLoadedMetadata = () => {
|
|
1602
|
-
this.updateDurationFromElement(probe);
|
|
1603
|
-
cleanup();
|
|
1604
|
-
};
|
|
1605
|
-
const handleError = () => {
|
|
1606
|
-
cleanup();
|
|
1607
|
-
};
|
|
1608
|
-
probe.addEventListener("loadedmetadata", handleLoadedMetadata, { once: true });
|
|
1609
|
-
probe.addEventListener("error", handleError, { once: true });
|
|
1610
|
-
probe.src = this.src;
|
|
1611
|
-
try {
|
|
1612
|
-
probe.load();
|
|
1613
|
-
} catch {
|
|
1614
|
-
cleanup();
|
|
1615
|
-
}
|
|
1616
|
-
});
|
|
1617
|
-
};
|
|
1618
|
-
this.clearPlaybackStartSafetyTimeout = () => {
|
|
1619
|
-
if (!this.elementRef) return;
|
|
1620
|
-
clearTimeout(this.playTimeout);
|
|
1621
|
-
this.playTimeout = void 0;
|
|
1622
|
-
};
|
|
1623
|
-
this.clearPendingLoadedMeta = () => {
|
|
1624
|
-
const pending = this._pendingLoadedMeta;
|
|
1625
|
-
if (pending?.element && pending.onLoaded) {
|
|
1626
|
-
pending.element.removeEventListener("loadedmetadata", pending.onLoaded);
|
|
1627
|
-
}
|
|
1628
|
-
this._pendingLoadedMeta = void 0;
|
|
1629
|
-
};
|
|
1630
|
-
this.restoreSavedPosition = (elementRef) => {
|
|
1631
|
-
const saved = this.secondsElapsed;
|
|
1632
|
-
if (!saved || saved <= 0) return;
|
|
1633
|
-
const apply = () => {
|
|
1634
|
-
const duration = elementRef.duration;
|
|
1635
|
-
const clamped = typeof duration === "number" && !isNaN(duration) && isFinite(duration) ? Math.min(saved, duration) : saved;
|
|
1636
|
-
try {
|
|
1637
|
-
if (elementRef.currentTime === clamped) return;
|
|
1638
|
-
elementRef.currentTime = clamped;
|
|
1639
|
-
this.setSecondsElapsed(clamped);
|
|
1640
|
-
} catch {
|
|
1641
|
-
}
|
|
1617
|
+
const EmptyStateIndicator = React.memo(
|
|
1618
|
+
UnMemoizedEmptyStateIndicator
|
|
1619
|
+
);
|
|
1620
|
+
const makeChannelReducer = () => (state, action) => {
|
|
1621
|
+
switch (action.type) {
|
|
1622
|
+
case "closeThread": {
|
|
1623
|
+
return {
|
|
1624
|
+
...state,
|
|
1625
|
+
thread: null,
|
|
1626
|
+
threadLoadingMore: false,
|
|
1627
|
+
threadMessages: []
|
|
1642
1628
|
};
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
apply();
|
|
1654
|
-
this._restoringPosition = false;
|
|
1655
|
-
};
|
|
1656
|
-
elementRef.addEventListener("loadedmetadata", onLoaded, { once: true });
|
|
1657
|
-
this._pendingLoadedMeta = { element: elementRef, onLoaded };
|
|
1658
|
-
} else {
|
|
1659
|
-
this._restoringPosition = true;
|
|
1660
|
-
apply();
|
|
1661
|
-
this._restoringPosition = false;
|
|
1662
|
-
}
|
|
1663
|
-
};
|
|
1664
|
-
this.elementIsReady = () => {
|
|
1665
|
-
if (this._elementIsReadyPromise) return this._elementIsReadyPromise;
|
|
1666
|
-
this._elementIsReadyPromise = new Promise((resolve) => {
|
|
1667
|
-
if (!this.elementRef) return resolve(false);
|
|
1668
|
-
const element = this.elementRef;
|
|
1669
|
-
const handleLoaded = () => {
|
|
1670
|
-
element.removeEventListener("loadedmetadata", handleLoaded);
|
|
1671
|
-
resolve(element.readyState > 0);
|
|
1672
|
-
};
|
|
1673
|
-
element.addEventListener("loadedmetadata", handleLoaded);
|
|
1674
|
-
});
|
|
1675
|
-
return this._elementIsReadyPromise;
|
|
1676
|
-
};
|
|
1677
|
-
this.setRef = (elementRef) => {
|
|
1678
|
-
if (elementIsPlaying(this.elementRef)) {
|
|
1679
|
-
this.releaseElement({ resetState: false });
|
|
1680
|
-
}
|
|
1681
|
-
this.clearPendingLoadedMeta();
|
|
1682
|
-
this.clearMetadataProbe();
|
|
1683
|
-
this._restoringPosition = false;
|
|
1684
|
-
this._elementIsReadyPromise = void 0;
|
|
1685
|
-
this.state.partialNext({ elementRef });
|
|
1686
|
-
if (elementRef) {
|
|
1687
|
-
this.registerSubscriptions();
|
|
1688
|
-
}
|
|
1689
|
-
};
|
|
1690
|
-
this.setSecondsElapsed = (secondsElapsed) => {
|
|
1691
|
-
const duration = this.elementRef?.duration ?? this.durationSeconds;
|
|
1692
|
-
this.state.partialNext({
|
|
1693
|
-
progressPercent: duration && secondsElapsed ? secondsElapsed / duration * 100 : 0,
|
|
1694
|
-
secondsElapsed
|
|
1695
|
-
});
|
|
1696
|
-
};
|
|
1697
|
-
this.canPlayMimeType = (mimeType2) => {
|
|
1698
|
-
if (!mimeType2) return false;
|
|
1699
|
-
if (this.elementRef) return !!this.elementRef.canPlayType(mimeType2);
|
|
1700
|
-
return !!new Audio().canPlayType(mimeType2);
|
|
1701
|
-
};
|
|
1702
|
-
this.play = async (params) => {
|
|
1703
|
-
if (this._disposed) return;
|
|
1704
|
-
const elementRef = this.ensureElementRef();
|
|
1705
|
-
if (elementIsPlaying(this.elementRef)) {
|
|
1706
|
-
if (this.isPlaying) return;
|
|
1707
|
-
this.state.partialNext({ isPlaying: true });
|
|
1708
|
-
return;
|
|
1709
|
-
}
|
|
1710
|
-
const { currentPlaybackRate, playbackRates: playbackRates2 } = {
|
|
1711
|
-
currentPlaybackRate: this.currentPlaybackRate,
|
|
1712
|
-
playbackRates: this.playbackRates,
|
|
1713
|
-
...params
|
|
1629
|
+
}
|
|
1630
|
+
case "copyMessagesFromChannel": {
|
|
1631
|
+
const { channel, parentId } = action;
|
|
1632
|
+
return {
|
|
1633
|
+
...state,
|
|
1634
|
+
messages: [...channel.state.messages],
|
|
1635
|
+
pinnedMessages: [...channel.state.pinnedMessages],
|
|
1636
|
+
// copying messages from channel happens with new message - this resets the suppressAutoscroll
|
|
1637
|
+
suppressAutoscroll: false,
|
|
1638
|
+
threadMessages: parentId ? { ...channel.state.threads }[parentId] || [] : state.threadMessages
|
|
1714
1639
|
};
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
isPlaying: true,
|
|
1727
|
-
playbackRates: playbackRates2
|
|
1728
|
-
});
|
|
1729
|
-
this._pool.setActiveAudioPlayer(this);
|
|
1730
|
-
} catch (e) {
|
|
1731
|
-
this.registerError({ error: e });
|
|
1732
|
-
this.state.partialNext({ isPlaying: false });
|
|
1733
|
-
} finally {
|
|
1734
|
-
this.clearPlaybackStartSafetyTimeout();
|
|
1735
|
-
}
|
|
1736
|
-
};
|
|
1737
|
-
this.pause = () => {
|
|
1738
|
-
if (!elementIsPlaying(this.elementRef)) return;
|
|
1739
|
-
this.clearPlaybackStartSafetyTimeout();
|
|
1740
|
-
this.elementRef.pause();
|
|
1741
|
-
this.state.partialNext({ isPlaying: false });
|
|
1742
|
-
};
|
|
1743
|
-
this.stop = () => {
|
|
1744
|
-
this.pause();
|
|
1745
|
-
this.state.partialNext({ isPlaying: false });
|
|
1746
|
-
this.setSecondsElapsed(0);
|
|
1747
|
-
if (this.elementRef) this.elementRef.currentTime = 0;
|
|
1748
|
-
};
|
|
1749
|
-
this.togglePlay = async () => this.isPlaying ? this.pause() : await this.play();
|
|
1750
|
-
this.increasePlaybackRate = () => {
|
|
1751
|
-
let currentPlaybackRateIndex = this.state.getLatestValue().playbackRates.findIndex((rate) => rate === this.currentPlaybackRate);
|
|
1752
|
-
if (currentPlaybackRateIndex === -1) {
|
|
1753
|
-
currentPlaybackRateIndex = 0;
|
|
1754
|
-
}
|
|
1755
|
-
const nextIndex = currentPlaybackRateIndex === this.playbackRates.length - 1 ? 0 : currentPlaybackRateIndex + 1;
|
|
1756
|
-
const currentPlaybackRate = this.playbackRates[nextIndex];
|
|
1757
|
-
this.state.partialNext({ currentPlaybackRate });
|
|
1758
|
-
if (this.elementRef) {
|
|
1759
|
-
this.elementRef.playbackRate = currentPlaybackRate;
|
|
1760
|
-
}
|
|
1761
|
-
};
|
|
1762
|
-
this.seek = throttle(async ({ clientX, currentTarget }) => {
|
|
1763
|
-
let element = this.elementRef;
|
|
1764
|
-
if (!this.elementRef) {
|
|
1765
|
-
element = this.ensureElementRef();
|
|
1766
|
-
const isReady = await this.elementIsReady();
|
|
1767
|
-
if (!isReady) return;
|
|
1768
|
-
}
|
|
1769
|
-
if (!currentTarget || !element) return;
|
|
1770
|
-
if (!isSeekable(element)) {
|
|
1771
|
-
this.registerError({ errCode: "seek-not-supported" });
|
|
1772
|
-
return;
|
|
1773
|
-
}
|
|
1774
|
-
const { width, x } = currentTarget.getBoundingClientRect();
|
|
1775
|
-
const ratio = (clientX - x) / width;
|
|
1776
|
-
if (ratio > 1 || ratio < 0) return;
|
|
1777
|
-
const currentTime = ratio * element.duration;
|
|
1778
|
-
this.setSecondsElapsed(currentTime);
|
|
1779
|
-
element.currentTime = currentTime;
|
|
1780
|
-
}, 16);
|
|
1781
|
-
this.registerError = (params) => {
|
|
1782
|
-
defaultRegisterAudioPlayerError(params);
|
|
1783
|
-
this.plugins.forEach(({ onError }) => onError?.({ player: this, ...params }));
|
|
1784
|
-
};
|
|
1785
|
-
this.requestRemoval = () => {
|
|
1786
|
-
this._disposed = true;
|
|
1787
|
-
this.cancelScheduledRemoval();
|
|
1788
|
-
this.clearPendingLoadedMeta();
|
|
1789
|
-
this.clearMetadataProbe();
|
|
1790
|
-
this._restoringPosition = false;
|
|
1791
|
-
this.releaseElement({ resetState: true });
|
|
1792
|
-
this.unsubscribeEventListeners?.();
|
|
1793
|
-
this.unsubscribeEventListeners = null;
|
|
1794
|
-
this.plugins.forEach(({ onRemove }) => onRemove?.({ player: this }));
|
|
1795
|
-
this._pool.deregister(this.id);
|
|
1796
|
-
};
|
|
1797
|
-
this.cancelScheduledRemoval = () => {
|
|
1798
|
-
clearTimeout(this._removalTimeout);
|
|
1799
|
-
this._removalTimeout = void 0;
|
|
1800
|
-
};
|
|
1801
|
-
this.scheduleRemoval = (ms = 0) => {
|
|
1802
|
-
this.cancelScheduledRemoval();
|
|
1803
|
-
this._removalTimeout = setTimeout(() => {
|
|
1804
|
-
if (this.disposed) return;
|
|
1805
|
-
this.requestRemoval();
|
|
1806
|
-
}, ms);
|
|
1807
|
-
};
|
|
1808
|
-
this.releaseElementForHandoff = () => {
|
|
1809
|
-
if (!this.elementRef) return;
|
|
1810
|
-
this.releaseElement({ resetState: false });
|
|
1811
|
-
this.unsubscribeEventListeners?.();
|
|
1812
|
-
this.unsubscribeEventListeners = null;
|
|
1813
|
-
};
|
|
1814
|
-
this.registerSubscriptions = () => {
|
|
1815
|
-
this.unsubscribeEventListeners?.();
|
|
1816
|
-
const audioElement = this.elementRef;
|
|
1817
|
-
if (!audioElement) return;
|
|
1818
|
-
const handleEnded = () => {
|
|
1819
|
-
if (audioElement) {
|
|
1820
|
-
this.updateDurationFromElement(audioElement);
|
|
1821
|
-
}
|
|
1822
|
-
this.stop();
|
|
1640
|
+
}
|
|
1641
|
+
case "copyStateFromChannelOnEvent": {
|
|
1642
|
+
const { channel } = action;
|
|
1643
|
+
return {
|
|
1644
|
+
...state,
|
|
1645
|
+
members: { ...channel.state.members },
|
|
1646
|
+
messages: [...channel.state.messages],
|
|
1647
|
+
pinnedMessages: [...channel.state.pinnedMessages],
|
|
1648
|
+
read: { ...channel.state.read },
|
|
1649
|
+
watcherCount: channel.state.watcher_count,
|
|
1650
|
+
watchers: { ...channel.state.watchers }
|
|
1823
1651
|
};
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
}
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
"MEDIA_ERR_ABORTED: fetch aborted by user",
|
|
1838
|
-
"MEDIA_ERR_NETWORK: network failed while fetching",
|
|
1839
|
-
"MEDIA_ERR_DECODE: audio fetched but couldn’t decode",
|
|
1840
|
-
"MEDIA_ERR_SRC_NOT_SUPPORTED: source not supported"
|
|
1841
|
-
][audio?.error?.code];
|
|
1842
|
-
if (!errorMsg) return;
|
|
1843
|
-
defaultRegisterAudioPlayerError({ error: new Error(errorMsg + ` (${audio.src})`) });
|
|
1652
|
+
}
|
|
1653
|
+
case "initStateFromChannel": {
|
|
1654
|
+
const { channel, hasMore } = action;
|
|
1655
|
+
return {
|
|
1656
|
+
...state,
|
|
1657
|
+
hasMore,
|
|
1658
|
+
loading: false,
|
|
1659
|
+
members: { ...channel.state.members },
|
|
1660
|
+
messages: [...channel.state.messages],
|
|
1661
|
+
pinnedMessages: [...channel.state.pinnedMessages],
|
|
1662
|
+
read: { ...channel.state.read },
|
|
1663
|
+
watcherCount: channel.state.watcher_count,
|
|
1664
|
+
watchers: { ...channel.state.watchers }
|
|
1844
1665
|
};
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1666
|
+
}
|
|
1667
|
+
case "jumpToLatestMessageFinished": {
|
|
1668
|
+
const { hasMore, hasMoreNewer, messages } = action;
|
|
1669
|
+
return {
|
|
1670
|
+
...state,
|
|
1671
|
+
hasMore,
|
|
1672
|
+
hasMoreNewer,
|
|
1673
|
+
highlightedMessageId: void 0,
|
|
1674
|
+
loading: false,
|
|
1675
|
+
messages,
|
|
1676
|
+
suppressAutoscroll: false
|
|
1850
1677
|
};
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1678
|
+
}
|
|
1679
|
+
case "jumpToMessageFinished": {
|
|
1680
|
+
return {
|
|
1681
|
+
...state,
|
|
1682
|
+
hasMore: action.channel.state.messagePagination.hasPrev,
|
|
1683
|
+
hasMoreNewer: action.channel.state.messagePagination.hasNext,
|
|
1684
|
+
highlightedMessageId: action.highlightedMessageId,
|
|
1685
|
+
loadingMore: false,
|
|
1686
|
+
loadingMoreForJumpToChannelMessage: false,
|
|
1687
|
+
messages: action.channel.state.messages,
|
|
1688
|
+
suppressAutoscroll: false
|
|
1855
1689
|
};
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
audioElement.pause();
|
|
1862
|
-
audioElement.removeEventListener("ended", handleEnded);
|
|
1863
|
-
audioElement.removeEventListener("error", handleError);
|
|
1864
|
-
audioElement.removeEventListener("loadedmetadata", handleLoadedMetadata);
|
|
1865
|
-
audioElement.removeEventListener("timeupdate", handleTimeupdate);
|
|
1690
|
+
}
|
|
1691
|
+
case "clearHighlightedMessage": {
|
|
1692
|
+
return {
|
|
1693
|
+
...state,
|
|
1694
|
+
highlightedMessageId: void 0
|
|
1866
1695
|
};
|
|
1867
|
-
};
|
|
1868
|
-
this._data = {
|
|
1869
|
-
durationSeconds,
|
|
1870
|
-
fileSize,
|
|
1871
|
-
id,
|
|
1872
|
-
mimeType,
|
|
1873
|
-
src,
|
|
1874
|
-
title,
|
|
1875
|
-
waveformData
|
|
1876
|
-
};
|
|
1877
|
-
this._pool = pool;
|
|
1878
|
-
this.setPlugins(() => plugins ?? []);
|
|
1879
|
-
const playbackRates = customPlaybackRates?.length ? customPlaybackRates : DEFAULT_PLAYBACK_RATES;
|
|
1880
|
-
const canPlayRecord = mimeType ? !!new Audio().canPlayType(mimeType) : true;
|
|
1881
|
-
this.state = new streamChat.StateStore({
|
|
1882
|
-
canPlayRecord,
|
|
1883
|
-
currentPlaybackRate: playbackRates[0],
|
|
1884
|
-
durationSeconds,
|
|
1885
|
-
elementRef: null,
|
|
1886
|
-
isPlaying: false,
|
|
1887
|
-
playbackError: null,
|
|
1888
|
-
playbackRates,
|
|
1889
|
-
progressPercent: 0,
|
|
1890
|
-
secondsElapsed: 0
|
|
1891
|
-
});
|
|
1892
|
-
this.plugins.forEach((p) => p.onInit?.({ player: this }));
|
|
1893
|
-
this.preloadMetadata();
|
|
1894
|
-
}
|
|
1895
|
-
get plugins() {
|
|
1896
|
-
return Array.from(this._plugins.values());
|
|
1897
|
-
}
|
|
1898
|
-
get canPlayRecord() {
|
|
1899
|
-
return this.state.getLatestValue().canPlayRecord;
|
|
1900
|
-
}
|
|
1901
|
-
get elementRef() {
|
|
1902
|
-
return this.state.getLatestValue().elementRef;
|
|
1903
|
-
}
|
|
1904
|
-
get isPlaying() {
|
|
1905
|
-
return this.state.getLatestValue().isPlaying;
|
|
1906
|
-
}
|
|
1907
|
-
get currentPlaybackRate() {
|
|
1908
|
-
return this.state.getLatestValue().currentPlaybackRate;
|
|
1909
|
-
}
|
|
1910
|
-
get playbackRates() {
|
|
1911
|
-
return this.state.getLatestValue().playbackRates;
|
|
1912
|
-
}
|
|
1913
|
-
get durationSeconds() {
|
|
1914
|
-
return this.state.getLatestValue().durationSeconds;
|
|
1915
|
-
}
|
|
1916
|
-
get fileSize() {
|
|
1917
|
-
return this._data.fileSize;
|
|
1918
|
-
}
|
|
1919
|
-
get id() {
|
|
1920
|
-
return this._data.id;
|
|
1921
|
-
}
|
|
1922
|
-
get src() {
|
|
1923
|
-
return this._data.src;
|
|
1924
|
-
}
|
|
1925
|
-
get mimeType() {
|
|
1926
|
-
return this._data.mimeType;
|
|
1927
|
-
}
|
|
1928
|
-
get title() {
|
|
1929
|
-
return this._data.title;
|
|
1930
|
-
}
|
|
1931
|
-
get waveformData() {
|
|
1932
|
-
return this._data.waveformData;
|
|
1933
|
-
}
|
|
1934
|
-
get secondsElapsed() {
|
|
1935
|
-
return this.state.getLatestValue().secondsElapsed;
|
|
1936
|
-
}
|
|
1937
|
-
get progressPercent() {
|
|
1938
|
-
return this.state.getLatestValue().progressPercent;
|
|
1939
|
-
}
|
|
1940
|
-
get disposed() {
|
|
1941
|
-
return this._disposed;
|
|
1942
|
-
}
|
|
1943
|
-
ensureElementRef() {
|
|
1944
|
-
if (this._disposed) {
|
|
1945
|
-
throw new Error("AudioPlayer is disposed");
|
|
1946
1696
|
}
|
|
1947
|
-
|
|
1948
|
-
const
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1697
|
+
case "loadMoreFinished": {
|
|
1698
|
+
const { hasMore, messages } = action;
|
|
1699
|
+
return {
|
|
1700
|
+
...state,
|
|
1701
|
+
hasMore,
|
|
1702
|
+
loadingMore: false,
|
|
1703
|
+
messages,
|
|
1704
|
+
suppressAutoscroll: false
|
|
1705
|
+
};
|
|
1953
1706
|
}
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1707
|
+
case "loadMoreNewerFinished": {
|
|
1708
|
+
const { hasMoreNewer, messages } = action;
|
|
1709
|
+
return {
|
|
1710
|
+
...state,
|
|
1711
|
+
hasMoreNewer,
|
|
1712
|
+
loadingMoreNewer: false,
|
|
1713
|
+
messages
|
|
1714
|
+
};
|
|
1961
1715
|
}
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
}
|
|
1970
|
-
return;
|
|
1716
|
+
case "loadMoreThreadFinished": {
|
|
1717
|
+
const { threadHasMore, threadMessages } = action;
|
|
1718
|
+
return {
|
|
1719
|
+
...state,
|
|
1720
|
+
threadHasMore,
|
|
1721
|
+
threadLoadingMore: false,
|
|
1722
|
+
threadMessages
|
|
1723
|
+
};
|
|
1971
1724
|
}
|
|
1972
|
-
|
|
1973
|
-
|
|
1725
|
+
case "openThread": {
|
|
1726
|
+
const { channel, message } = action;
|
|
1727
|
+
return {
|
|
1728
|
+
...state,
|
|
1729
|
+
thread: message,
|
|
1730
|
+
threadHasMore: true,
|
|
1731
|
+
threadMessages: message.id ? { ...channel.state.threads }[message.id] || [] : [],
|
|
1732
|
+
threadSuppressAutoscroll: false
|
|
1733
|
+
};
|
|
1974
1734
|
}
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
this.clearMetadataProbe();
|
|
1979
|
-
this._restoringPosition = false;
|
|
1980
|
-
if (resetState) {
|
|
1981
|
-
this.stop();
|
|
1982
|
-
} else {
|
|
1983
|
-
this.state.partialNext({ isPlaying: false });
|
|
1984
|
-
if (this.elementRef) {
|
|
1985
|
-
try {
|
|
1986
|
-
this.elementRef.pause();
|
|
1987
|
-
} catch {
|
|
1988
|
-
}
|
|
1989
|
-
}
|
|
1735
|
+
case "setError": {
|
|
1736
|
+
const { error } = action;
|
|
1737
|
+
return { ...state, error };
|
|
1990
1738
|
}
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1739
|
+
case "setLoadingMore": {
|
|
1740
|
+
const { loadingMore } = action;
|
|
1741
|
+
return { ...state, loadingMore, suppressAutoscroll: loadingMore };
|
|
1994
1742
|
}
|
|
1743
|
+
case "setLoadingMoreForJumpToChannelMessage": {
|
|
1744
|
+
const { loadingMoreForJumpToChannelMessage } = action;
|
|
1745
|
+
return {
|
|
1746
|
+
...state,
|
|
1747
|
+
loadingMoreForJumpToChannelMessage,
|
|
1748
|
+
suppressAutoscroll: loadingMoreForJumpToChannelMessage
|
|
1749
|
+
};
|
|
1750
|
+
}
|
|
1751
|
+
case "setLoadingMoreNewer": {
|
|
1752
|
+
const { loadingMoreNewer } = action;
|
|
1753
|
+
return { ...state, loadingMoreNewer };
|
|
1754
|
+
}
|
|
1755
|
+
case "setThread": {
|
|
1756
|
+
const { message } = action;
|
|
1757
|
+
return { ...state, thread: message };
|
|
1758
|
+
}
|
|
1759
|
+
case "setTyping": {
|
|
1760
|
+
const { channel } = action;
|
|
1761
|
+
return {
|
|
1762
|
+
...state,
|
|
1763
|
+
typing: { ...channel.state.typing }
|
|
1764
|
+
};
|
|
1765
|
+
}
|
|
1766
|
+
case "startLoadingThread": {
|
|
1767
|
+
return {
|
|
1768
|
+
...state,
|
|
1769
|
+
threadLoadingMore: true,
|
|
1770
|
+
threadSuppressAutoscroll: true
|
|
1771
|
+
};
|
|
1772
|
+
}
|
|
1773
|
+
case "updateThreadOnEvent": {
|
|
1774
|
+
const { channel, message } = action;
|
|
1775
|
+
if (!state.thread) return state;
|
|
1776
|
+
return {
|
|
1777
|
+
...state,
|
|
1778
|
+
thread: message?.id === state.thread.id ? channel.state.formatMessage(message) : state.thread,
|
|
1779
|
+
threadMessages: state.thread?.id ? { ...channel.state.threads }[state.thread.id] || [] : []
|
|
1780
|
+
};
|
|
1781
|
+
}
|
|
1782
|
+
default:
|
|
1783
|
+
return state;
|
|
1995
1784
|
}
|
|
1996
|
-
setPlugins(setter) {
|
|
1997
|
-
this._plugins = setter(this.plugins).reduce((acc, plugin) => {
|
|
1998
|
-
if (plugin.id) {
|
|
1999
|
-
acc.set(plugin.id, plugin);
|
|
2000
|
-
}
|
|
2001
|
-
return acc;
|
|
2002
|
-
}, /* @__PURE__ */ new Map());
|
|
2003
|
-
}
|
|
2004
|
-
}
|
|
2005
|
-
class AudioPlayerPool {
|
|
2006
|
-
constructor(config) {
|
|
2007
|
-
this.state = new streamChat.StateStore({
|
|
2008
|
-
activeAudioPlayer: null
|
|
2009
|
-
});
|
|
2010
|
-
this.pool = /* @__PURE__ */ new Map();
|
|
2011
|
-
this.audios = /* @__PURE__ */ new Map();
|
|
2012
|
-
this.sharedAudio = null;
|
|
2013
|
-
this.sharedOwnerId = null;
|
|
2014
|
-
this.getOrAdd = (params) => {
|
|
2015
|
-
const { playbackRates, plugins, ...descriptor } = params;
|
|
2016
|
-
let player = this.pool.get(params.id);
|
|
2017
|
-
if (player) {
|
|
2018
|
-
if (!player.disposed) {
|
|
2019
|
-
player.setDescriptor(descriptor);
|
|
2020
|
-
return player;
|
|
2021
|
-
}
|
|
2022
|
-
this.deregister(params.id);
|
|
2023
|
-
}
|
|
2024
|
-
player = new AudioPlayer({
|
|
2025
|
-
playbackRates,
|
|
2026
|
-
plugins,
|
|
2027
|
-
...descriptor,
|
|
2028
|
-
pool: this
|
|
2029
|
-
});
|
|
2030
|
-
this.pool.set(params.id, player);
|
|
2031
|
-
return player;
|
|
2032
|
-
};
|
|
2033
|
-
this.acquireElement = ({ ownerId, src }) => {
|
|
2034
|
-
if (!this.allowConcurrentPlayback) {
|
|
2035
|
-
if (!this.sharedAudio) {
|
|
2036
|
-
this.sharedAudio = new Audio();
|
|
2037
|
-
}
|
|
2038
|
-
if (this.sharedOwnerId && this.sharedOwnerId !== ownerId) {
|
|
2039
|
-
const previous = this.pool.get(this.sharedOwnerId);
|
|
2040
|
-
previous?.pause();
|
|
2041
|
-
previous?.releaseElementForHandoff();
|
|
2042
|
-
}
|
|
2043
|
-
this.sharedOwnerId = ownerId;
|
|
2044
|
-
if (this.sharedAudio.src !== src) {
|
|
2045
|
-
this.sharedAudio.src = src;
|
|
2046
|
-
}
|
|
2047
|
-
return this.sharedAudio;
|
|
2048
|
-
}
|
|
2049
|
-
let audio = this.audios.get(ownerId);
|
|
2050
|
-
if (!audio) {
|
|
2051
|
-
audio = new Audio();
|
|
2052
|
-
this.audios.set(ownerId, audio);
|
|
2053
|
-
}
|
|
2054
|
-
if (audio.src !== src) {
|
|
2055
|
-
audio.src = src;
|
|
2056
|
-
}
|
|
2057
|
-
return audio;
|
|
2058
|
-
};
|
|
2059
|
-
this.releaseElement = (ownerId) => {
|
|
2060
|
-
if (!this.allowConcurrentPlayback) {
|
|
2061
|
-
if (this.sharedOwnerId !== ownerId) return;
|
|
2062
|
-
const el2 = this.sharedAudio;
|
|
2063
|
-
if (el2) {
|
|
2064
|
-
try {
|
|
2065
|
-
el2.pause();
|
|
2066
|
-
} catch {
|
|
2067
|
-
}
|
|
2068
|
-
el2.removeAttribute("src");
|
|
2069
|
-
el2.load();
|
|
2070
|
-
}
|
|
2071
|
-
this.sharedOwnerId = null;
|
|
2072
|
-
return;
|
|
2073
|
-
}
|
|
2074
|
-
const el = this.audios.get(ownerId);
|
|
2075
|
-
if (!el) return;
|
|
2076
|
-
try {
|
|
2077
|
-
el.pause();
|
|
2078
|
-
} catch {
|
|
2079
|
-
}
|
|
2080
|
-
el.removeAttribute("src");
|
|
2081
|
-
el.load();
|
|
2082
|
-
this.audios.delete(ownerId);
|
|
2083
|
-
};
|
|
2084
|
-
this.setActiveAudioPlayer = (activeAudioPlayer) => {
|
|
2085
|
-
if (this.allowConcurrentPlayback) return;
|
|
2086
|
-
this.state.partialNext({ activeAudioPlayer });
|
|
2087
|
-
};
|
|
2088
|
-
this.remove = (id) => {
|
|
2089
|
-
const player = this.pool.get(id);
|
|
2090
|
-
if (!player) return;
|
|
2091
|
-
player.requestRemoval();
|
|
2092
|
-
};
|
|
2093
|
-
this.clear = () => {
|
|
2094
|
-
this.players.forEach((player) => {
|
|
2095
|
-
this.remove(player.id);
|
|
2096
|
-
});
|
|
2097
|
-
};
|
|
2098
|
-
this.registerSubscriptions = () => {
|
|
2099
|
-
this.players.forEach((p) => {
|
|
2100
|
-
if (p.elementRef) {
|
|
2101
|
-
p.registerSubscriptions();
|
|
2102
|
-
}
|
|
2103
|
-
});
|
|
2104
|
-
};
|
|
2105
|
-
this.allowConcurrentPlayback = !!config?.allowConcurrentPlayback;
|
|
2106
|
-
}
|
|
2107
|
-
get players() {
|
|
2108
|
-
return Array.from(this.pool.values());
|
|
2109
|
-
}
|
|
2110
|
-
get activeAudioPlayer() {
|
|
2111
|
-
return this.state.getLatestValue().activeAudioPlayer;
|
|
2112
|
-
}
|
|
2113
|
-
/** Removes the AudioPlayer instance from the pool of players */
|
|
2114
|
-
deregister(id) {
|
|
2115
|
-
if (this.pool.has(id)) {
|
|
2116
|
-
this.pool.delete(id);
|
|
2117
|
-
}
|
|
2118
|
-
if (this.activeAudioPlayer?.id === id) {
|
|
2119
|
-
this.setActiveAudioPlayer(null);
|
|
2120
|
-
}
|
|
2121
|
-
}
|
|
2122
|
-
}
|
|
2123
|
-
const SEEK_NOT_SUPPORTED_NOTIFICATION_DEBOUNCE_INTERVAL_MS = 1e3;
|
|
2124
|
-
const audioPlayerNotificationsPluginFactory = ({
|
|
2125
|
-
addNotification,
|
|
2126
|
-
panel = "channel",
|
|
2127
|
-
t
|
|
2128
|
-
}) => {
|
|
2129
|
-
const errors = {
|
|
2130
|
-
"failed-to-start": new Error(t("Failed to play the recording")),
|
|
2131
|
-
"not-playable": new Error(
|
|
2132
|
-
t("Recording format is not supported and cannot be reproduced")
|
|
2133
|
-
),
|
|
2134
|
-
"seek-not-supported": new Error(t("Cannot seek in the recording"))
|
|
2135
|
-
};
|
|
2136
|
-
let lastSeekNotSupportedNotificationAt;
|
|
2137
|
-
return {
|
|
2138
|
-
id: "AudioPlayerNotificationsPlugin",
|
|
2139
|
-
onError: ({ errCode, error: e }) => {
|
|
2140
|
-
if (errCode === "seek-not-supported") {
|
|
2141
|
-
const now = Date.now();
|
|
2142
|
-
if (typeof lastSeekNotSupportedNotificationAt === "number" && now - lastSeekNotSupportedNotificationAt < SEEK_NOT_SUPPORTED_NOTIFICATION_DEBOUNCE_INTERVAL_MS) {
|
|
2143
|
-
return;
|
|
2144
|
-
}
|
|
2145
|
-
lastSeekNotSupportedNotificationAt = now;
|
|
2146
|
-
}
|
|
2147
|
-
const error = (errCode && errors[errCode]) ?? e ?? new Error(t("Error reproducing the recording"));
|
|
2148
|
-
addNotification({
|
|
2149
|
-
emitter: "AudioPlayer",
|
|
2150
|
-
error,
|
|
2151
|
-
message: error.message,
|
|
2152
|
-
severity: "error",
|
|
2153
|
-
targetPanels: [panel],
|
|
2154
|
-
type: "browser:audio:playback:error"
|
|
2155
|
-
});
|
|
2156
|
-
}
|
|
2157
|
-
};
|
|
2158
|
-
};
|
|
2159
|
-
const NOTIFICATION_TARGET_PANELS = [
|
|
2160
|
-
"channel",
|
|
2161
|
-
"thread",
|
|
2162
|
-
"channel-list",
|
|
2163
|
-
"thread-list"
|
|
2164
|
-
];
|
|
2165
|
-
const isNotificationTargetPanel = (value) => typeof value === "string" && NOTIFICATION_TARGET_PANELS.includes(value);
|
|
2166
|
-
const getNotificationTargetPanel = (notification) => {
|
|
2167
|
-
const targetTag = notification.tags?.find((tag) => tag.startsWith("target:"));
|
|
2168
|
-
if (targetTag) {
|
|
2169
|
-
const candidate = targetTag.slice("target:".length);
|
|
2170
|
-
if (isNotificationTargetPanel(candidate)) return candidate;
|
|
2171
|
-
}
|
|
2172
|
-
const panel = notification.origin.context?.panel;
|
|
2173
|
-
return isNotificationTargetPanel(panel) ? panel : void 0;
|
|
2174
|
-
};
|
|
2175
|
-
const getNotificationTargetPanels = (notification) => {
|
|
2176
|
-
const targetPanels = (notification.tags ?? []).filter((tag) => tag.startsWith("target:")).map((tag) => tag.slice("target:".length)).filter(
|
|
2177
|
-
(value) => isNotificationTargetPanel(value)
|
|
2178
|
-
);
|
|
2179
|
-
if (targetPanels.length > 0) {
|
|
2180
|
-
return Array.from(new Set(targetPanels));
|
|
2181
|
-
}
|
|
2182
|
-
const panel = notification.origin.context?.panel;
|
|
2183
|
-
return isNotificationTargetPanel(panel) ? [panel] : [];
|
|
2184
1785
|
};
|
|
2185
|
-
const
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
1786
|
+
const initialState = {
|
|
1787
|
+
error: null,
|
|
1788
|
+
hasMore: true,
|
|
1789
|
+
hasMoreNewer: false,
|
|
1790
|
+
loading: true,
|
|
1791
|
+
loadingMore: false,
|
|
1792
|
+
loadingMoreForJumpToChannelMessage: false,
|
|
1793
|
+
members: {},
|
|
1794
|
+
messages: [],
|
|
1795
|
+
pinnedMessages: [],
|
|
1796
|
+
read: {},
|
|
1797
|
+
suppressAutoscroll: false,
|
|
1798
|
+
thread: null,
|
|
1799
|
+
threadHasMore: true,
|
|
1800
|
+
threadLoadingMore: false,
|
|
1801
|
+
threadMessages: [],
|
|
1802
|
+
threadSuppressAutoscroll: false,
|
|
1803
|
+
typing: {},
|
|
1804
|
+
watcherCount: 0,
|
|
1805
|
+
watchers: {}
|
|
2189
1806
|
};
|
|
2190
|
-
const
|
|
2191
|
-
const
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
});
|
|
2234
|
-
const UnMemoizedEmptyStateIndicator = (props) => {
|
|
2235
|
-
const { listType, messageText } = props;
|
|
2236
|
-
const { t } = useTranslationContext("EmptyStateIndicator");
|
|
2237
|
-
if (listType === "thread") return null;
|
|
2238
|
-
if (listType === "channel") {
|
|
2239
|
-
const text = t("No conversations yet");
|
|
2240
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "str-chat__channel-list-empty", children: [
|
|
2241
|
-
/* @__PURE__ */ jsxRuntime.jsx(IconMessageBubbles, {}),
|
|
2242
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { role: "listitem", children: text })
|
|
2243
|
-
] });
|
|
2244
|
-
}
|
|
2245
|
-
if (listType === "message") {
|
|
2246
|
-
const text = t(messageText || "Send a message to start the conversation");
|
|
2247
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "str-chat__empty-channel", children: [
|
|
2248
|
-
/* @__PURE__ */ jsxRuntime.jsx(IconMessageBubble, {}),
|
|
2249
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "str-chat__empty-channel-text", role: "listitem", children: text })
|
|
2250
|
-
] });
|
|
2251
|
-
}
|
|
2252
|
-
return /* @__PURE__ */ jsxRuntime.jsx("p", { children: t("No items exist") });
|
|
2253
|
-
};
|
|
2254
|
-
const EmptyStateIndicator = React.memo(
|
|
2255
|
-
UnMemoizedEmptyStateIndicator
|
|
2256
|
-
);
|
|
2257
|
-
const makeChannelReducer = () => (state, action) => {
|
|
2258
|
-
switch (action.type) {
|
|
2259
|
-
case "closeThread": {
|
|
2260
|
-
return {
|
|
2261
|
-
...state,
|
|
2262
|
-
thread: null,
|
|
2263
|
-
threadLoadingMore: false,
|
|
2264
|
-
threadMessages: []
|
|
2265
|
-
};
|
|
2266
|
-
}
|
|
2267
|
-
case "copyMessagesFromChannel": {
|
|
2268
|
-
const { channel, parentId } = action;
|
|
2269
|
-
return {
|
|
2270
|
-
...state,
|
|
2271
|
-
messages: [...channel.state.messages],
|
|
2272
|
-
pinnedMessages: [...channel.state.pinnedMessages],
|
|
2273
|
-
// copying messages from channel happens with new message - this resets the suppressAutoscroll
|
|
2274
|
-
suppressAutoscroll: false,
|
|
2275
|
-
threadMessages: parentId ? { ...channel.state.threads }[parentId] || [] : state.threadMessages
|
|
2276
|
-
};
|
|
2277
|
-
}
|
|
2278
|
-
case "copyStateFromChannelOnEvent": {
|
|
2279
|
-
const { channel } = action;
|
|
2280
|
-
return {
|
|
2281
|
-
...state,
|
|
2282
|
-
members: { ...channel.state.members },
|
|
2283
|
-
messages: [...channel.state.messages],
|
|
2284
|
-
pinnedMessages: [...channel.state.pinnedMessages],
|
|
2285
|
-
read: { ...channel.state.read },
|
|
2286
|
-
watcherCount: channel.state.watcher_count,
|
|
2287
|
-
watchers: { ...channel.state.watchers }
|
|
2288
|
-
};
|
|
2289
|
-
}
|
|
2290
|
-
case "initStateFromChannel": {
|
|
2291
|
-
const { channel, hasMore } = action;
|
|
2292
|
-
return {
|
|
2293
|
-
...state,
|
|
2294
|
-
hasMore,
|
|
2295
|
-
loading: false,
|
|
2296
|
-
members: { ...channel.state.members },
|
|
2297
|
-
messages: [...channel.state.messages],
|
|
2298
|
-
pinnedMessages: [...channel.state.pinnedMessages],
|
|
2299
|
-
read: { ...channel.state.read },
|
|
2300
|
-
watcherCount: channel.state.watcher_count,
|
|
2301
|
-
watchers: { ...channel.state.watchers }
|
|
2302
|
-
};
|
|
2303
|
-
}
|
|
2304
|
-
case "jumpToLatestMessageFinished": {
|
|
2305
|
-
const { hasMore, hasMoreNewer, messages } = action;
|
|
2306
|
-
return {
|
|
2307
|
-
...state,
|
|
2308
|
-
hasMore,
|
|
2309
|
-
hasMoreNewer,
|
|
2310
|
-
highlightedMessageId: void 0,
|
|
2311
|
-
loading: false,
|
|
2312
|
-
messages,
|
|
2313
|
-
suppressAutoscroll: false
|
|
2314
|
-
};
|
|
2315
|
-
}
|
|
2316
|
-
case "jumpToMessageFinished": {
|
|
2317
|
-
return {
|
|
2318
|
-
...state,
|
|
2319
|
-
hasMore: action.channel.state.messagePagination.hasPrev,
|
|
2320
|
-
hasMoreNewer: action.channel.state.messagePagination.hasNext,
|
|
2321
|
-
highlightedMessageId: action.highlightedMessageId,
|
|
2322
|
-
loadingMore: false,
|
|
2323
|
-
loadingMoreForJumpToChannelMessage: false,
|
|
2324
|
-
messages: action.channel.state.messages,
|
|
2325
|
-
suppressAutoscroll: false
|
|
2326
|
-
};
|
|
2327
|
-
}
|
|
2328
|
-
case "clearHighlightedMessage": {
|
|
2329
|
-
return {
|
|
2330
|
-
...state,
|
|
2331
|
-
highlightedMessageId: void 0
|
|
2332
|
-
};
|
|
2333
|
-
}
|
|
2334
|
-
case "loadMoreFinished": {
|
|
2335
|
-
const { hasMore, messages } = action;
|
|
2336
|
-
return {
|
|
2337
|
-
...state,
|
|
2338
|
-
hasMore,
|
|
2339
|
-
loadingMore: false,
|
|
2340
|
-
messages,
|
|
2341
|
-
suppressAutoscroll: false
|
|
2342
|
-
};
|
|
2343
|
-
}
|
|
2344
|
-
case "loadMoreNewerFinished": {
|
|
2345
|
-
const { hasMoreNewer, messages } = action;
|
|
2346
|
-
return {
|
|
2347
|
-
...state,
|
|
2348
|
-
hasMoreNewer,
|
|
2349
|
-
loadingMoreNewer: false,
|
|
2350
|
-
messages
|
|
2351
|
-
};
|
|
2352
|
-
}
|
|
2353
|
-
case "loadMoreThreadFinished": {
|
|
2354
|
-
const { threadHasMore, threadMessages } = action;
|
|
2355
|
-
return {
|
|
2356
|
-
...state,
|
|
2357
|
-
threadHasMore,
|
|
2358
|
-
threadLoadingMore: false,
|
|
2359
|
-
threadMessages
|
|
2360
|
-
};
|
|
2361
|
-
}
|
|
2362
|
-
case "openThread": {
|
|
2363
|
-
const { channel, message } = action;
|
|
2364
|
-
return {
|
|
2365
|
-
...state,
|
|
2366
|
-
thread: message,
|
|
2367
|
-
threadHasMore: true,
|
|
2368
|
-
threadMessages: message.id ? { ...channel.state.threads }[message.id] || [] : [],
|
|
2369
|
-
threadSuppressAutoscroll: false
|
|
2370
|
-
};
|
|
2371
|
-
}
|
|
2372
|
-
case "setError": {
|
|
2373
|
-
const { error } = action;
|
|
2374
|
-
return { ...state, error };
|
|
2375
|
-
}
|
|
2376
|
-
case "setLoadingMore": {
|
|
2377
|
-
const { loadingMore } = action;
|
|
2378
|
-
return { ...state, loadingMore, suppressAutoscroll: loadingMore };
|
|
2379
|
-
}
|
|
2380
|
-
case "setLoadingMoreForJumpToChannelMessage": {
|
|
2381
|
-
const { loadingMoreForJumpToChannelMessage } = action;
|
|
2382
|
-
return {
|
|
2383
|
-
...state,
|
|
2384
|
-
loadingMoreForJumpToChannelMessage,
|
|
2385
|
-
suppressAutoscroll: loadingMoreForJumpToChannelMessage
|
|
2386
|
-
};
|
|
2387
|
-
}
|
|
2388
|
-
case "setLoadingMoreNewer": {
|
|
2389
|
-
const { loadingMoreNewer } = action;
|
|
2390
|
-
return { ...state, loadingMoreNewer };
|
|
2391
|
-
}
|
|
2392
|
-
case "setThread": {
|
|
2393
|
-
const { message } = action;
|
|
2394
|
-
return { ...state, thread: message };
|
|
2395
|
-
}
|
|
2396
|
-
case "setTyping": {
|
|
2397
|
-
const { channel } = action;
|
|
2398
|
-
return {
|
|
2399
|
-
...state,
|
|
2400
|
-
typing: { ...channel.state.typing }
|
|
2401
|
-
};
|
|
2402
|
-
}
|
|
2403
|
-
case "startLoadingThread": {
|
|
2404
|
-
return {
|
|
2405
|
-
...state,
|
|
2406
|
-
threadLoadingMore: true,
|
|
2407
|
-
threadSuppressAutoscroll: true
|
|
2408
|
-
};
|
|
2409
|
-
}
|
|
2410
|
-
case "updateThreadOnEvent": {
|
|
2411
|
-
const { channel, message } = action;
|
|
2412
|
-
if (!state.thread) return state;
|
|
2413
|
-
return {
|
|
2414
|
-
...state,
|
|
2415
|
-
thread: message?.id === state.thread.id ? channel.state.formatMessage(message) : state.thread,
|
|
2416
|
-
threadMessages: state.thread?.id ? { ...channel.state.threads }[state.thread.id] || [] : []
|
|
2417
|
-
};
|
|
2418
|
-
}
|
|
2419
|
-
default:
|
|
2420
|
-
return state;
|
|
2421
|
-
}
|
|
2422
|
-
};
|
|
2423
|
-
const initialState = {
|
|
2424
|
-
error: null,
|
|
2425
|
-
hasMore: true,
|
|
2426
|
-
hasMoreNewer: false,
|
|
2427
|
-
loading: true,
|
|
2428
|
-
loadingMore: false,
|
|
2429
|
-
loadingMoreForJumpToChannelMessage: false,
|
|
2430
|
-
members: {},
|
|
2431
|
-
messages: [],
|
|
2432
|
-
pinnedMessages: [],
|
|
2433
|
-
read: {},
|
|
2434
|
-
suppressAutoscroll: false,
|
|
2435
|
-
thread: null,
|
|
2436
|
-
threadHasMore: true,
|
|
2437
|
-
threadLoadingMore: false,
|
|
2438
|
-
threadMessages: [],
|
|
2439
|
-
threadSuppressAutoscroll: false,
|
|
2440
|
-
typing: {},
|
|
2441
|
-
watcherCount: 0,
|
|
2442
|
-
watchers: {}
|
|
2443
|
-
};
|
|
2444
|
-
const useCreateChannelStateContext = (value) => {
|
|
2445
|
-
const {
|
|
2446
|
-
channel,
|
|
2447
|
-
channelCapabilitiesArray = [],
|
|
2448
|
-
channelConfig,
|
|
2449
|
-
channelUnreadUiState,
|
|
2450
|
-
error,
|
|
2451
|
-
giphyVersion,
|
|
2452
|
-
hasMore,
|
|
2453
|
-
hasMoreNewer,
|
|
2454
|
-
highlightedMessageId,
|
|
2455
|
-
imageAttachmentSizeHandler,
|
|
2456
|
-
loading,
|
|
2457
|
-
loadingMore,
|
|
2458
|
-
loadingMoreForJumpToChannelMessage,
|
|
2459
|
-
members,
|
|
2460
|
-
messages = [],
|
|
2461
|
-
mutes,
|
|
2462
|
-
notifications,
|
|
2463
|
-
pinnedMessages,
|
|
2464
|
-
read = {},
|
|
2465
|
-
shouldGenerateVideoThumbnail,
|
|
2466
|
-
skipMessageDataMemoization,
|
|
2467
|
-
suppressAutoscroll,
|
|
2468
|
-
thread,
|
|
2469
|
-
threadHasMore,
|
|
2470
|
-
threadLoadingMore,
|
|
2471
|
-
threadMessages = [],
|
|
2472
|
-
videoAttachmentSizeHandler,
|
|
2473
|
-
watcher_count,
|
|
2474
|
-
watcherCount,
|
|
2475
|
-
watchers
|
|
2476
|
-
} = value;
|
|
2477
|
-
const channelId = channel.cid;
|
|
2478
|
-
const lastRead = channel.initialized && channel.lastRead()?.getTime();
|
|
2479
|
-
const membersLength = Object.keys(members || []).length;
|
|
2480
|
-
const notificationsLength = notifications.length;
|
|
2481
|
-
const readUsers = Object.values(read);
|
|
2482
|
-
const readUsersLength = readUsers.length;
|
|
2483
|
-
const readUsersLastReadDateStrings = [];
|
|
2484
|
-
for (const { last_read } of readUsers) {
|
|
2485
|
-
if (!lastRead) continue;
|
|
2486
|
-
readUsersLastReadDateStrings.push(last_read?.toISOString());
|
|
1807
|
+
const useCreateChannelStateContext = (value) => {
|
|
1808
|
+
const {
|
|
1809
|
+
channel,
|
|
1810
|
+
channelCapabilitiesArray = [],
|
|
1811
|
+
channelConfig,
|
|
1812
|
+
channelUnreadUiState,
|
|
1813
|
+
error,
|
|
1814
|
+
giphyVersion,
|
|
1815
|
+
hasMore,
|
|
1816
|
+
hasMoreNewer,
|
|
1817
|
+
highlightedMessageId,
|
|
1818
|
+
imageAttachmentSizeHandler,
|
|
1819
|
+
loading,
|
|
1820
|
+
loadingMore,
|
|
1821
|
+
loadingMoreForJumpToChannelMessage,
|
|
1822
|
+
members,
|
|
1823
|
+
messages = [],
|
|
1824
|
+
mutes,
|
|
1825
|
+
notifications,
|
|
1826
|
+
pinnedMessages,
|
|
1827
|
+
read = {},
|
|
1828
|
+
shouldGenerateVideoThumbnail,
|
|
1829
|
+
skipMessageDataMemoization,
|
|
1830
|
+
suppressAutoscroll,
|
|
1831
|
+
thread,
|
|
1832
|
+
threadHasMore,
|
|
1833
|
+
threadLoadingMore,
|
|
1834
|
+
threadMessages = [],
|
|
1835
|
+
videoAttachmentSizeHandler,
|
|
1836
|
+
watcher_count,
|
|
1837
|
+
watcherCount,
|
|
1838
|
+
watchers
|
|
1839
|
+
} = value;
|
|
1840
|
+
const channelId = channel.cid;
|
|
1841
|
+
const lastRead = channel.initialized && channel.lastRead()?.getTime();
|
|
1842
|
+
const membersLength = Object.keys(members || []).length;
|
|
1843
|
+
const notificationsLength = notifications.length;
|
|
1844
|
+
const readUsers = Object.values(read);
|
|
1845
|
+
const readUsersLength = readUsers.length;
|
|
1846
|
+
const readUsersLastReadDateStrings = [];
|
|
1847
|
+
for (const { last_read } of readUsers) {
|
|
1848
|
+
if (!lastRead) continue;
|
|
1849
|
+
readUsersLastReadDateStrings.push(last_read?.toISOString());
|
|
2487
1850
|
}
|
|
2488
1851
|
const readUsersLastReads = readUsersLastReadDateStrings.join();
|
|
2489
1852
|
const threadMessagesLength = threadMessages?.length;
|
|
@@ -2600,359 +1963,1067 @@ const useIsMounted = () => {
|
|
|
2600
1963
|
return () => {
|
|
2601
1964
|
isMounted.current = false;
|
|
2602
1965
|
};
|
|
2603
|
-
}, []);
|
|
2604
|
-
return isMounted;
|
|
2605
|
-
};
|
|
2606
|
-
const useMentionsHandlers = (onMentionsHover, onMentionsClick) => React.useCallback(
|
|
2607
|
-
(event, mentioned_users) => {
|
|
2608
|
-
if (!onMentionsHover && !onMentionsClick || !(event.target instanceof HTMLElement)) {
|
|
2609
|
-
return;
|
|
2610
|
-
}
|
|
2611
|
-
const target = event.target;
|
|
2612
|
-
const textContent = target.innerHTML.replace("*", "");
|
|
2613
|
-
if (textContent[0] === "@") {
|
|
2614
|
-
const userName = textContent.replace("@", "");
|
|
2615
|
-
const user = mentioned_users?.find(
|
|
2616
|
-
({ id, name }) => name === userName || id === userName
|
|
2617
|
-
);
|
|
2618
|
-
if (onMentionsHover && typeof onMentionsHover === "function" && event.type === "mouseover") {
|
|
2619
|
-
onMentionsHover(event, user);
|
|
2620
|
-
}
|
|
2621
|
-
if (onMentionsClick && event.type === "click" && typeof onMentionsClick === "function") {
|
|
2622
|
-
onMentionsClick(event, user);
|
|
2623
|
-
}
|
|
2624
|
-
}
|
|
2625
|
-
},
|
|
2626
|
-
[onMentionsClick, onMentionsHover]
|
|
2627
|
-
);
|
|
2628
|
-
const LoadingMessage = ({
|
|
2629
|
-
bubbleSize,
|
|
2630
|
-
metadataSize,
|
|
2631
|
-
outgoing = false
|
|
2632
|
-
}) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2633
|
-
"div",
|
|
2634
|
-
{
|
|
2635
|
-
className: `str-chat__loading-channel-message ${outgoing ? "str-chat__loading-channel-message--outgoing" : "str-chat__loading-channel-message--incoming"}`,
|
|
2636
|
-
children: [
|
|
2637
|
-
!outgoing ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "str-chat__loading-channel-message-avatar" }) : null,
|
|
2638
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "str-chat__loading-channel-message-content", children: [
|
|
2639
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2640
|
-
"div",
|
|
2641
|
-
{
|
|
2642
|
-
className: `str-chat__loading-channel-message-bubble str-chat__loading-channel-message-bubble--${bubbleSize}`
|
|
2643
|
-
}
|
|
2644
|
-
),
|
|
2645
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2646
|
-
"div",
|
|
2647
|
-
{
|
|
2648
|
-
className: `str-chat__loading-channel-message-metadata str-chat__loading-channel-message-metadata--${metadataSize}`
|
|
2649
|
-
}
|
|
2650
|
-
)
|
|
2651
|
-
] })
|
|
2652
|
-
]
|
|
2653
|
-
}
|
|
2654
|
-
);
|
|
2655
|
-
const LoadingMessageInput = () => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "str-chat__message-composer-container str-chat__message-composer-container--loading", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "str-chat__message-composer", children: [
|
|
2656
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "str-chat__loading-channel-message-input-button" }),
|
|
2657
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "str-chat__loading-channel-message-input-pill" })
|
|
2658
|
-
] }) });
|
|
2659
|
-
const LoadingChannelHeader = () => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "str-chat__channel-header str-chat__channel-header--loading", children: [
|
|
2660
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "str-chat__channel-header__data str-chat__channel-header__data--loading", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "str-chat__loading-channel-header-name" }) }),
|
|
2661
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "str-chat__loading-channel-header-avatar" })
|
|
2662
|
-
] });
|
|
2663
|
-
const LoadingChannel = () => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "str-chat__loading-channel", children: [
|
|
2664
|
-
/* @__PURE__ */ jsxRuntime.jsx(LoadingChannelHeader, {}),
|
|
2665
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "str-chat__message-list str-chat__message-list--loading", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "str-chat__message-list-scroll", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "str-chat__loading-channel-message-list", children: [
|
|
2666
|
-
/* @__PURE__ */ jsxRuntime.jsx(LoadingMessage, { bubbleSize: "lg", metadataSize: "md" }),
|
|
2667
|
-
/* @__PURE__ */ jsxRuntime.jsx(LoadingMessage, { bubbleSize: "md", metadataSize: "sm", outgoing: true }),
|
|
2668
|
-
/* @__PURE__ */ jsxRuntime.jsx(LoadingMessage, { bubbleSize: "lg", metadataSize: "md" })
|
|
2669
|
-
] }) }) }),
|
|
2670
|
-
/* @__PURE__ */ jsxRuntime.jsx(LoadingMessageInput, {})
|
|
2671
|
-
] });
|
|
2672
|
-
const UnMemoizedLoadingErrorIndicator = ({ error }) => {
|
|
2673
|
-
const { t } = useTranslationContext("LoadingErrorIndicator");
|
|
2674
|
-
if (!error) return null;
|
|
2675
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { children: t("Error: {{ errorMessage }}", { errorMessage: error.message }) });
|
|
2676
|
-
};
|
|
2677
|
-
const LoadingErrorIndicator = React.memo(
|
|
2678
|
-
UnMemoizedLoadingErrorIndicator,
|
|
2679
|
-
(prevProps, nextProps) => prevProps.error?.message === nextProps.error?.message
|
|
2680
|
-
);
|
|
2681
|
-
const CHANNEL_CONTAINER_ID = "str-chat__channel";
|
|
2682
|
-
const DEFAULT_NEXT_CHANNEL_PAGE_SIZE = 25;
|
|
2683
|
-
const DEFAULT_JUMP_TO_PAGE_SIZE = 25;
|
|
2684
|
-
const DEFAULT_THREAD_PAGE_SIZE = 25;
|
|
2685
|
-
const DEFAULT_LOAD_PAGE_SCROLL_THRESHOLD = 250;
|
|
2686
|
-
const DEFAULT_HIGHLIGHT_DURATION = 500;
|
|
2687
|
-
const validateAndGetMessage = (func, args) => {
|
|
2688
|
-
if (!func || typeof func !== "function") return null;
|
|
2689
|
-
if (!Array.isArray(args)) {
|
|
2690
|
-
args = [args];
|
|
2691
|
-
}
|
|
2692
|
-
const returnValue = func(...args);
|
|
2693
|
-
if (typeof returnValue !== "string") return null;
|
|
2694
|
-
return returnValue;
|
|
2695
|
-
};
|
|
2696
|
-
const isUserMuted = (message, mutes) => {
|
|
2697
|
-
if (!mutes || !message) return false;
|
|
2698
|
-
const userMuted = mutes.filter((el) => el.target.id === message.user?.id);
|
|
2699
|
-
return !!userMuted.length;
|
|
2700
|
-
};
|
|
2701
|
-
const OPTIONAL_MESSAGE_ACTIONS = {
|
|
2702
|
-
deleteForMe: "deleteForMe"
|
|
2703
|
-
};
|
|
2704
|
-
const MESSAGE_ACTIONS = {
|
|
2705
|
-
delete: "delete",
|
|
2706
|
-
download: "download",
|
|
2707
|
-
edit: "edit",
|
|
2708
|
-
flag: "flag",
|
|
2709
|
-
markUnread: "markUnread",
|
|
2710
|
-
mute: "mute",
|
|
2711
|
-
pin: "pin",
|
|
2712
|
-
quote: "quote",
|
|
2713
|
-
react: "react",
|
|
2714
|
-
remindMe: "remindMe",
|
|
2715
|
-
reply: "reply",
|
|
2716
|
-
saveForLater: "saveForLater"
|
|
2717
|
-
};
|
|
2718
|
-
const getMessageActions = (actions, {
|
|
2719
|
-
canDelete,
|
|
2720
|
-
canEdit,
|
|
2721
|
-
canFlag,
|
|
2722
|
-
canMarkUnread,
|
|
2723
|
-
canMute,
|
|
2724
|
-
canPin,
|
|
2725
|
-
canQuote,
|
|
2726
|
-
canReact,
|
|
2727
|
-
canReply
|
|
2728
|
-
}, channelConfig) => {
|
|
2729
|
-
const messageActionsAfterPermission = [];
|
|
2730
|
-
let messageActions = [];
|
|
2731
|
-
if (actions && typeof actions === "boolean") {
|
|
2732
|
-
messageActions = Object.keys(MESSAGE_ACTIONS);
|
|
2733
|
-
} else if (actions && Array.isArray(actions) && actions.length > 0) {
|
|
2734
|
-
messageActions = [...actions];
|
|
2735
|
-
} else {
|
|
2736
|
-
return [];
|
|
2737
|
-
}
|
|
2738
|
-
if (canDelete && messageActions.indexOf(MESSAGE_ACTIONS.delete) > -1) {
|
|
2739
|
-
messageActionsAfterPermission.push(MESSAGE_ACTIONS.delete);
|
|
1966
|
+
}, []);
|
|
1967
|
+
return isMounted;
|
|
1968
|
+
};
|
|
1969
|
+
const useMentionsHandlers = (onMentionsHover, onMentionsClick) => React.useCallback(
|
|
1970
|
+
(event, mentioned_users) => {
|
|
1971
|
+
if (!onMentionsHover && !onMentionsClick || !(event.target instanceof HTMLElement)) {
|
|
1972
|
+
return;
|
|
1973
|
+
}
|
|
1974
|
+
const target = event.target;
|
|
1975
|
+
const textContent = target.innerHTML.replace("*", "");
|
|
1976
|
+
if (textContent[0] === "@") {
|
|
1977
|
+
const userName = textContent.replace("@", "");
|
|
1978
|
+
const user = mentioned_users?.find(
|
|
1979
|
+
({ id, name }) => name === userName || id === userName
|
|
1980
|
+
);
|
|
1981
|
+
if (onMentionsHover && typeof onMentionsHover === "function" && event.type === "mouseover") {
|
|
1982
|
+
onMentionsHover(event, user);
|
|
1983
|
+
}
|
|
1984
|
+
if (onMentionsClick && event.type === "click" && typeof onMentionsClick === "function") {
|
|
1985
|
+
onMentionsClick(event, user);
|
|
1986
|
+
}
|
|
1987
|
+
}
|
|
1988
|
+
},
|
|
1989
|
+
[onMentionsClick, onMentionsHover]
|
|
1990
|
+
);
|
|
1991
|
+
const LoadingMessage = ({
|
|
1992
|
+
bubbleSize,
|
|
1993
|
+
metadataSize,
|
|
1994
|
+
outgoing = false
|
|
1995
|
+
}) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1996
|
+
"div",
|
|
1997
|
+
{
|
|
1998
|
+
className: `str-chat__loading-channel-message ${outgoing ? "str-chat__loading-channel-message--outgoing" : "str-chat__loading-channel-message--incoming"}`,
|
|
1999
|
+
children: [
|
|
2000
|
+
!outgoing ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "str-chat__loading-channel-message-avatar" }) : null,
|
|
2001
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "str-chat__loading-channel-message-content", children: [
|
|
2002
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2003
|
+
"div",
|
|
2004
|
+
{
|
|
2005
|
+
className: `str-chat__loading-channel-message-bubble str-chat__loading-channel-message-bubble--${bubbleSize}`
|
|
2006
|
+
}
|
|
2007
|
+
),
|
|
2008
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2009
|
+
"div",
|
|
2010
|
+
{
|
|
2011
|
+
className: `str-chat__loading-channel-message-metadata str-chat__loading-channel-message-metadata--${metadataSize}`
|
|
2012
|
+
}
|
|
2013
|
+
)
|
|
2014
|
+
] })
|
|
2015
|
+
]
|
|
2016
|
+
}
|
|
2017
|
+
);
|
|
2018
|
+
const LoadingMessageInput = () => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "str-chat__message-composer-container str-chat__message-composer-container--loading", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "str-chat__message-composer", children: [
|
|
2019
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "str-chat__loading-channel-message-input-button" }),
|
|
2020
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "str-chat__loading-channel-message-input-pill" })
|
|
2021
|
+
] }) });
|
|
2022
|
+
const LoadingChannelHeader = () => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "str-chat__channel-header str-chat__channel-header--loading", children: [
|
|
2023
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "str-chat__channel-header__data str-chat__channel-header__data--loading", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "str-chat__loading-channel-header-name" }) }),
|
|
2024
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "str-chat__loading-channel-header-avatar" })
|
|
2025
|
+
] });
|
|
2026
|
+
const LoadingChannel = () => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "str-chat__loading-channel", children: [
|
|
2027
|
+
/* @__PURE__ */ jsxRuntime.jsx(LoadingChannelHeader, {}),
|
|
2028
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "str-chat__message-list str-chat__message-list--loading", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "str-chat__message-list-scroll", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "str-chat__loading-channel-message-list", children: [
|
|
2029
|
+
/* @__PURE__ */ jsxRuntime.jsx(LoadingMessage, { bubbleSize: "lg", metadataSize: "md" }),
|
|
2030
|
+
/* @__PURE__ */ jsxRuntime.jsx(LoadingMessage, { bubbleSize: "md", metadataSize: "sm", outgoing: true }),
|
|
2031
|
+
/* @__PURE__ */ jsxRuntime.jsx(LoadingMessage, { bubbleSize: "lg", metadataSize: "md" })
|
|
2032
|
+
] }) }) }),
|
|
2033
|
+
/* @__PURE__ */ jsxRuntime.jsx(LoadingMessageInput, {})
|
|
2034
|
+
] });
|
|
2035
|
+
const UnMemoizedLoadingErrorIndicator = ({ error }) => {
|
|
2036
|
+
const { t } = useTranslationContext("LoadingErrorIndicator");
|
|
2037
|
+
if (!error) return null;
|
|
2038
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { children: t("Error: {{ errorMessage }}", { errorMessage: error.message }) });
|
|
2039
|
+
};
|
|
2040
|
+
const LoadingErrorIndicator = React.memo(
|
|
2041
|
+
UnMemoizedLoadingErrorIndicator,
|
|
2042
|
+
(prevProps, nextProps) => prevProps.error?.message === nextProps.error?.message
|
|
2043
|
+
);
|
|
2044
|
+
const CHANNEL_CONTAINER_ID = "str-chat__channel";
|
|
2045
|
+
const DEFAULT_NEXT_CHANNEL_PAGE_SIZE = 25;
|
|
2046
|
+
const DEFAULT_JUMP_TO_PAGE_SIZE = 25;
|
|
2047
|
+
const DEFAULT_THREAD_PAGE_SIZE = 25;
|
|
2048
|
+
const DEFAULT_LOAD_PAGE_SCROLL_THRESHOLD = 250;
|
|
2049
|
+
const DEFAULT_HIGHLIGHT_DURATION = 500;
|
|
2050
|
+
const validateAndGetMessage = (func, args) => {
|
|
2051
|
+
if (!func || typeof func !== "function") return null;
|
|
2052
|
+
if (!Array.isArray(args)) {
|
|
2053
|
+
args = [args];
|
|
2054
|
+
}
|
|
2055
|
+
const returnValue = func(...args);
|
|
2056
|
+
if (typeof returnValue !== "string") return null;
|
|
2057
|
+
return returnValue;
|
|
2058
|
+
};
|
|
2059
|
+
const isUserMuted = (message, mutes) => {
|
|
2060
|
+
if (!mutes || !message) return false;
|
|
2061
|
+
const userMuted = mutes.filter((el) => el.target.id === message.user?.id);
|
|
2062
|
+
return !!userMuted.length;
|
|
2063
|
+
};
|
|
2064
|
+
const OPTIONAL_MESSAGE_ACTIONS = {
|
|
2065
|
+
deleteForMe: "deleteForMe"
|
|
2066
|
+
};
|
|
2067
|
+
const MESSAGE_ACTIONS = {
|
|
2068
|
+
delete: "delete",
|
|
2069
|
+
download: "download",
|
|
2070
|
+
edit: "edit",
|
|
2071
|
+
flag: "flag",
|
|
2072
|
+
markUnread: "markUnread",
|
|
2073
|
+
mute: "mute",
|
|
2074
|
+
pin: "pin",
|
|
2075
|
+
quote: "quote",
|
|
2076
|
+
react: "react",
|
|
2077
|
+
remindMe: "remindMe",
|
|
2078
|
+
reply: "reply",
|
|
2079
|
+
saveForLater: "saveForLater"
|
|
2080
|
+
};
|
|
2081
|
+
const getMessageActions = (actions, {
|
|
2082
|
+
canDelete,
|
|
2083
|
+
canEdit,
|
|
2084
|
+
canFlag,
|
|
2085
|
+
canMarkUnread,
|
|
2086
|
+
canMute,
|
|
2087
|
+
canPin,
|
|
2088
|
+
canQuote,
|
|
2089
|
+
canReact,
|
|
2090
|
+
canReply
|
|
2091
|
+
}, channelConfig) => {
|
|
2092
|
+
const messageActionsAfterPermission = [];
|
|
2093
|
+
let messageActions = [];
|
|
2094
|
+
if (actions && typeof actions === "boolean") {
|
|
2095
|
+
messageActions = Object.keys(MESSAGE_ACTIONS);
|
|
2096
|
+
} else if (actions && Array.isArray(actions) && actions.length > 0) {
|
|
2097
|
+
messageActions = [...actions];
|
|
2098
|
+
} else {
|
|
2099
|
+
return [];
|
|
2100
|
+
}
|
|
2101
|
+
if (canDelete && messageActions.indexOf(MESSAGE_ACTIONS.delete) > -1) {
|
|
2102
|
+
messageActionsAfterPermission.push(MESSAGE_ACTIONS.delete);
|
|
2103
|
+
}
|
|
2104
|
+
if (messageActions.indexOf(MESSAGE_ACTIONS.download) > -1) {
|
|
2105
|
+
messageActionsAfterPermission.push(MESSAGE_ACTIONS.download);
|
|
2106
|
+
}
|
|
2107
|
+
if (canDelete && messageActions.indexOf(OPTIONAL_MESSAGE_ACTIONS.deleteForMe) > -1) {
|
|
2108
|
+
messageActionsAfterPermission.push(OPTIONAL_MESSAGE_ACTIONS.deleteForMe);
|
|
2109
|
+
}
|
|
2110
|
+
if (canEdit && messageActions.indexOf(MESSAGE_ACTIONS.edit) > -1) {
|
|
2111
|
+
messageActionsAfterPermission.push(MESSAGE_ACTIONS.edit);
|
|
2112
|
+
}
|
|
2113
|
+
if (canFlag && messageActions.indexOf(MESSAGE_ACTIONS.flag) > -1) {
|
|
2114
|
+
messageActionsAfterPermission.push(MESSAGE_ACTIONS.flag);
|
|
2115
|
+
}
|
|
2116
|
+
if (canMarkUnread && messageActions.indexOf(MESSAGE_ACTIONS.markUnread) > -1) {
|
|
2117
|
+
messageActionsAfterPermission.push(MESSAGE_ACTIONS.markUnread);
|
|
2118
|
+
}
|
|
2119
|
+
if (canMute && messageActions.indexOf(MESSAGE_ACTIONS.mute) > -1) {
|
|
2120
|
+
messageActionsAfterPermission.push(MESSAGE_ACTIONS.mute);
|
|
2121
|
+
}
|
|
2122
|
+
if (canPin && messageActions.indexOf(MESSAGE_ACTIONS.pin) > -1) {
|
|
2123
|
+
messageActionsAfterPermission.push(MESSAGE_ACTIONS.pin);
|
|
2124
|
+
}
|
|
2125
|
+
if (canQuote && messageActions.indexOf(MESSAGE_ACTIONS.quote) > -1) {
|
|
2126
|
+
messageActionsAfterPermission.push(MESSAGE_ACTIONS.quote);
|
|
2127
|
+
}
|
|
2128
|
+
if (canReact && messageActions.indexOf(MESSAGE_ACTIONS.react) > -1) {
|
|
2129
|
+
messageActionsAfterPermission.push(MESSAGE_ACTIONS.react);
|
|
2130
|
+
}
|
|
2131
|
+
if (channelConfig?.["user_message_reminders"] && messageActions.indexOf(MESSAGE_ACTIONS.remindMe) > -1) {
|
|
2132
|
+
messageActionsAfterPermission.push(MESSAGE_ACTIONS.remindMe);
|
|
2133
|
+
}
|
|
2134
|
+
if (canReply && messageActions.indexOf(MESSAGE_ACTIONS.reply) > -1) {
|
|
2135
|
+
messageActionsAfterPermission.push(MESSAGE_ACTIONS.reply);
|
|
2136
|
+
}
|
|
2137
|
+
if (channelConfig?.["user_message_reminders"] && messageActions.indexOf(MESSAGE_ACTIONS.saveForLater) > -1) {
|
|
2138
|
+
messageActionsAfterPermission.push(MESSAGE_ACTIONS.saveForLater);
|
|
2139
|
+
}
|
|
2140
|
+
return messageActionsAfterPermission;
|
|
2141
|
+
};
|
|
2142
|
+
const ACTIONS_NOT_WORKING_IN_THREAD = [
|
|
2143
|
+
MESSAGE_ACTIONS.pin,
|
|
2144
|
+
MESSAGE_ACTIONS.reply,
|
|
2145
|
+
MESSAGE_ACTIONS.markUnread
|
|
2146
|
+
];
|
|
2147
|
+
function areMessagesEqual(prevMessage, nextMessage) {
|
|
2148
|
+
const areBaseMessagesEqual = (prevMessage2, nextMessage2) => prevMessage2.deleted_at === nextMessage2.deleted_at && prevMessage2.latest_reactions?.length === nextMessage2.latest_reactions?.length && prevMessage2.own_reactions?.length === nextMessage2.own_reactions?.length && prevMessage2.pinned === nextMessage2.pinned && prevMessage2.reply_count === nextMessage2.reply_count && prevMessage2.show_in_channel === nextMessage2.show_in_channel && prevMessage2.status === nextMessage2.status && prevMessage2.text === nextMessage2.text && prevMessage2.type === nextMessage2.type && prevMessage2.updated_at === nextMessage2.updated_at && prevMessage2.user?.updated_at === nextMessage2.user?.updated_at;
|
|
2149
|
+
return areBaseMessagesEqual(prevMessage, nextMessage) && Boolean(prevMessage.quoted_message) === Boolean(nextMessage.quoted_message) && (!prevMessage.quoted_message && !nextMessage.quoted_message || areBaseMessagesEqual(
|
|
2150
|
+
prevMessage.quoted_message,
|
|
2151
|
+
nextMessage.quoted_message
|
|
2152
|
+
));
|
|
2153
|
+
}
|
|
2154
|
+
const areMessagePropsEqual = (prevProps, nextProps) => {
|
|
2155
|
+
const { message: prevMessage, Message: prevMessageUI } = prevProps;
|
|
2156
|
+
const { message: nextMessage, Message: nextMessageUI } = nextProps;
|
|
2157
|
+
if (prevMessageUI !== nextMessageUI) return false;
|
|
2158
|
+
if (nextProps.showDetailedReactions !== prevProps.showDetailedReactions) {
|
|
2159
|
+
return false;
|
|
2160
|
+
}
|
|
2161
|
+
if (nextProps.closeReactionSelectorOnClick !== prevProps.closeReactionSelectorOnClick) {
|
|
2162
|
+
return false;
|
|
2163
|
+
}
|
|
2164
|
+
const messagesAreEqual = areMessagesEqual(prevMessage, nextMessage);
|
|
2165
|
+
if (!messagesAreEqual) return false;
|
|
2166
|
+
const deepEqualProps = deepequal(nextProps.messageActions, prevProps.messageActions) && deepequal(nextProps.readBy, prevProps.readBy) && deepequal(nextProps.deliveredTo, prevProps.deliveredTo) && deepequal(nextProps.highlighted, prevProps.highlighted) && deepequal(nextProps.groupStyles, prevProps.groupStyles) && // last 3 messages can have different group styles
|
|
2167
|
+
deepequal(nextProps.mutes, prevProps.mutes) && deepequal(nextProps.lastReceivedId, prevProps.lastReceivedId);
|
|
2168
|
+
if (!deepEqualProps) return false;
|
|
2169
|
+
return prevProps.messageListRect === nextProps.messageListRect;
|
|
2170
|
+
};
|
|
2171
|
+
const areMessageUIPropsEqual = (prevProps, nextProps) => {
|
|
2172
|
+
const { lastReceivedId: prevLastReceivedId, message: prevMessage } = prevProps;
|
|
2173
|
+
const { lastReceivedId: nextLastReceivedId, message: nextMessage } = nextProps;
|
|
2174
|
+
if (prevProps.highlighted !== nextProps.highlighted) return false;
|
|
2175
|
+
if (prevProps.threadList !== nextProps.threadList) return false;
|
|
2176
|
+
if (prevProps.endOfGroup !== nextProps.endOfGroup) return false;
|
|
2177
|
+
if (prevProps.mutes?.length !== nextProps.mutes?.length) return false;
|
|
2178
|
+
if (prevProps.readBy?.length !== nextProps.readBy?.length) return false;
|
|
2179
|
+
if (prevProps.deliveredTo?.length !== nextProps.deliveredTo?.length) return false;
|
|
2180
|
+
if (prevProps.groupStyles !== nextProps.groupStyles) return false;
|
|
2181
|
+
if (prevProps.showDetailedReactions !== nextProps.showDetailedReactions) {
|
|
2182
|
+
return false;
|
|
2183
|
+
}
|
|
2184
|
+
if ((prevMessage.id === prevLastReceivedId || prevMessage.id === nextLastReceivedId) && prevLastReceivedId !== nextLastReceivedId) {
|
|
2185
|
+
return false;
|
|
2186
|
+
}
|
|
2187
|
+
return areMessagesEqual(prevMessage, nextMessage);
|
|
2188
|
+
};
|
|
2189
|
+
const messageHasReactions = (message) => Object.values(message?.reaction_groups ?? {}).some(({ count }) => count > 0);
|
|
2190
|
+
const messageHasQuotedMessage = (message) => !!message?.quoted_message;
|
|
2191
|
+
const messageHasAttachments = (message) => !!message?.attachments && !!message.attachments.length;
|
|
2192
|
+
const messageHasSingleAttachment = (message) => message?.attachments?.length === 1;
|
|
2193
|
+
const messageHasGiphyAttachment = (message) => !!message?.attachments?.some((att) => att.type === "giphy");
|
|
2194
|
+
const getImages = (message) => {
|
|
2195
|
+
if (!message?.attachments) {
|
|
2196
|
+
return [];
|
|
2197
|
+
}
|
|
2198
|
+
return message.attachments.filter((item) => item.type === "image");
|
|
2199
|
+
};
|
|
2200
|
+
const getNonImageAttachments = (message) => {
|
|
2201
|
+
if (!message?.attachments) {
|
|
2202
|
+
return [];
|
|
2203
|
+
}
|
|
2204
|
+
return message.attachments.filter((item) => item.type !== "image");
|
|
2205
|
+
};
|
|
2206
|
+
const mapToUserNameOrId = (user) => user.name || user.id;
|
|
2207
|
+
const getReadByTooltipText = (users, t, client, tooltipUserNameMapper) => {
|
|
2208
|
+
let outStr = "";
|
|
2209
|
+
if (!t) {
|
|
2210
|
+
throw new Error(
|
|
2211
|
+
"getReadByTooltipText was called, but translation function is not available"
|
|
2212
|
+
);
|
|
2213
|
+
}
|
|
2214
|
+
if (!tooltipUserNameMapper) {
|
|
2215
|
+
throw new Error(
|
|
2216
|
+
"getReadByTooltipText was called, but tooltipUserNameMapper function is not available"
|
|
2217
|
+
);
|
|
2218
|
+
}
|
|
2219
|
+
const otherUsers = users.filter((item) => item && client?.user && item.id !== client.user.id).map(tooltipUserNameMapper);
|
|
2220
|
+
const slicedArr = otherUsers.slice(0, 5);
|
|
2221
|
+
const restLength = otherUsers.length - slicedArr.length;
|
|
2222
|
+
if (slicedArr.length === 1) {
|
|
2223
|
+
outStr = `${slicedArr[0]} `;
|
|
2224
|
+
} else if (slicedArr.length === 2) {
|
|
2225
|
+
outStr = t("{{ firstUser }} and {{ secondUser }}", {
|
|
2226
|
+
firstUser: slicedArr[0],
|
|
2227
|
+
secondUser: slicedArr[1]
|
|
2228
|
+
});
|
|
2229
|
+
} else if (slicedArr.length > 2) {
|
|
2230
|
+
if (restLength === 0) {
|
|
2231
|
+
const lastUser = slicedArr.splice(slicedArr.length - 1, 1);
|
|
2232
|
+
outStr = t("{{ commaSeparatedUsers }}, and {{ lastUser }}", {
|
|
2233
|
+
commaSeparatedUsers: slicedArr.join(", "),
|
|
2234
|
+
lastUser
|
|
2235
|
+
});
|
|
2236
|
+
} else {
|
|
2237
|
+
outStr = t("{{ commaSeparatedUsers }} and {{ moreCount }} more", {
|
|
2238
|
+
commaSeparatedUsers: slicedArr.join(", "),
|
|
2239
|
+
moreCount: restLength
|
|
2240
|
+
});
|
|
2241
|
+
}
|
|
2242
|
+
}
|
|
2243
|
+
return outStr;
|
|
2244
|
+
};
|
|
2245
|
+
const countEmojis = (text) => {
|
|
2246
|
+
const matches = text?.match(emojiRegex());
|
|
2247
|
+
return matches ? matches.length : 0;
|
|
2248
|
+
};
|
|
2249
|
+
const messageTextHasEmojisOnly = (message) => {
|
|
2250
|
+
if (!message.text) return false;
|
|
2251
|
+
const noEmojis = message.text.replace(emojiRegex(), "");
|
|
2252
|
+
const noSpace = noEmojis.replace(/[\s\n]/gm, "");
|
|
2253
|
+
return !noSpace;
|
|
2254
|
+
};
|
|
2255
|
+
const isMessageErrorRetryable = (message) => message.status === "failed" && message.error?.status !== 403;
|
|
2256
|
+
const isNetworkSendFailure = (message) => message.status === "failed" && message.error?.status === 0;
|
|
2257
|
+
const isMessageBounced = (message) => message.type === "error" && (message.moderation_details?.action === "MESSAGE_RESPONSE_ACTION_BOUNCE" || message.moderation?.action === "bounce");
|
|
2258
|
+
const isMessageBlocked = (message) => message.shadowed || message.type === "error" && (message.moderation_details?.action === "MESSAGE_RESPONSE_ACTION_REMOVE" || message.moderation?.action === "remove");
|
|
2259
|
+
const isMessageDeleted = (message) => Boolean(message.deleted_at || message.type === "deleted" || message.deleted_for_me);
|
|
2260
|
+
const isMessageEdited = (message) => !!message.message_text_updated_at;
|
|
2261
|
+
const hasResizeObserver = typeof window !== "undefined" && "ResizeObserver" in window;
|
|
2262
|
+
function autoMiddlewareFor(p) {
|
|
2263
|
+
if (!String(p).startsWith("auto")) return null;
|
|
2264
|
+
const alignment = p === "auto-start" ? "start" : p === "auto-end" ? "end" : void 0;
|
|
2265
|
+
return react.autoPlacement({ alignment });
|
|
2266
|
+
}
|
|
2267
|
+
function toOffsetMw(opt) {
|
|
2268
|
+
if (opt == null) return null;
|
|
2269
|
+
if (Array.isArray(opt)) {
|
|
2270
|
+
const [crossAxis, mainAxis] = opt;
|
|
2271
|
+
return react.offset({ crossAxis, mainAxis });
|
|
2272
|
+
}
|
|
2273
|
+
if (typeof opt === "number") return react.offset(opt);
|
|
2274
|
+
return react.offset(opt);
|
|
2275
|
+
}
|
|
2276
|
+
function usePopoverPosition({
|
|
2277
|
+
allowFlip = true,
|
|
2278
|
+
allowShift = true,
|
|
2279
|
+
autoUpdateOptions,
|
|
2280
|
+
fitAvailableSpace = false,
|
|
2281
|
+
freeze = false,
|
|
2282
|
+
offset,
|
|
2283
|
+
placement = "bottom-start",
|
|
2284
|
+
shiftOptions
|
|
2285
|
+
}) {
|
|
2286
|
+
const autoMw = autoMiddlewareFor(placement);
|
|
2287
|
+
const offsetMiddleware = toOffsetMw(offset);
|
|
2288
|
+
const isSidePlacement = placement.startsWith("left") || placement.startsWith("right");
|
|
2289
|
+
const mergedShiftOptions = shiftOptions ? { padding: 8, ...shiftOptions } : { padding: 8 };
|
|
2290
|
+
const middleware = [
|
|
2291
|
+
// offset first (mirrors common Popper setups)
|
|
2292
|
+
...offsetMiddleware ? [offsetMiddleware] : [],
|
|
2293
|
+
// choose between autoPlacement (Popper's "auto*") OR flip()
|
|
2294
|
+
// only allow flip when not explicitly 'left*' or 'right*'
|
|
2295
|
+
...autoMw ? [autoMw] : allowFlip && !isSidePlacement ? [react.flip()] : [],
|
|
2296
|
+
// viewport collision adjustments
|
|
2297
|
+
...allowShift ? [react.shift(mergedShiftOptions)] : [],
|
|
2298
|
+
// optional size constraining
|
|
2299
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
2300
|
+
...fitAvailableSpace ? [react.size({ apply: () => {
|
|
2301
|
+
} })] : []
|
|
2302
|
+
];
|
|
2303
|
+
const seedPlacement = String(placement).startsWith("auto") ? "bottom" : placement;
|
|
2304
|
+
return react.useFloating({
|
|
2305
|
+
middleware,
|
|
2306
|
+
placement: seedPlacement,
|
|
2307
|
+
strategy: "fixed",
|
|
2308
|
+
whileElementsMounted: freeze ? void 0 : (reference, floating, update) => react.autoUpdate(reference, floating, update, {
|
|
2309
|
+
ancestorResize: true,
|
|
2310
|
+
ancestorScroll: true,
|
|
2311
|
+
animationFrame: false,
|
|
2312
|
+
elementResize: hasResizeObserver,
|
|
2313
|
+
...autoUpdateOptions
|
|
2314
|
+
})
|
|
2315
|
+
});
|
|
2316
|
+
}
|
|
2317
|
+
const LegacyThreadContext = React.createContext({ legacyThread: void 0 });
|
|
2318
|
+
const useLegacyThreadContext = () => React.useContext(LegacyThreadContext);
|
|
2319
|
+
const DEFAULT_PLAYBACK_RATES = [1, 1.5, 2];
|
|
2320
|
+
const isSeekable = (audioElement) => !(audioElement.duration === Infinity || isNaN(audioElement.duration));
|
|
2321
|
+
const defaultRegisterAudioPlayerError = ({
|
|
2322
|
+
error
|
|
2323
|
+
} = {}) => {
|
|
2324
|
+
if (!error) return;
|
|
2325
|
+
console.error("[AUDIO PLAYER]", error);
|
|
2326
|
+
};
|
|
2327
|
+
const elementIsPlaying = (audioElement) => audioElement && !(audioElement.paused || audioElement.ended);
|
|
2328
|
+
class AudioPlayer {
|
|
2329
|
+
constructor({
|
|
2330
|
+
durationSeconds,
|
|
2331
|
+
fileSize,
|
|
2332
|
+
id,
|
|
2333
|
+
mimeType,
|
|
2334
|
+
playbackRates: customPlaybackRates,
|
|
2335
|
+
plugins,
|
|
2336
|
+
pool,
|
|
2337
|
+
src,
|
|
2338
|
+
title,
|
|
2339
|
+
waveformData
|
|
2340
|
+
}) {
|
|
2341
|
+
this._plugins = /* @__PURE__ */ new Map();
|
|
2342
|
+
this.playTimeout = void 0;
|
|
2343
|
+
this.unsubscribeEventListeners = null;
|
|
2344
|
+
this._disposed = false;
|
|
2345
|
+
this._metadataProbe = null;
|
|
2346
|
+
this._restoringPosition = false;
|
|
2347
|
+
this._removalTimeout = void 0;
|
|
2348
|
+
this.setDurationSeconds = (durationSeconds2) => {
|
|
2349
|
+
this._data.durationSeconds = durationSeconds2;
|
|
2350
|
+
this.state.partialNext({ durationSeconds: durationSeconds2 });
|
|
2351
|
+
};
|
|
2352
|
+
this.setPlaybackStartSafetyTimeout = () => {
|
|
2353
|
+
clearTimeout(this.playTimeout);
|
|
2354
|
+
this.playTimeout = setTimeout(() => {
|
|
2355
|
+
if (!this.elementRef) return;
|
|
2356
|
+
try {
|
|
2357
|
+
this.elementRef.pause();
|
|
2358
|
+
this.state.partialNext({ isPlaying: false });
|
|
2359
|
+
} catch (e) {
|
|
2360
|
+
this.registerError({ errCode: "failed-to-start" });
|
|
2361
|
+
}
|
|
2362
|
+
}, 2e3);
|
|
2363
|
+
};
|
|
2364
|
+
this.updateDurationFromElement = (element) => {
|
|
2365
|
+
const duration = element.duration;
|
|
2366
|
+
if (typeof duration !== "number" || isNaN(duration) || !isFinite(duration) || duration <= 0) {
|
|
2367
|
+
return;
|
|
2368
|
+
}
|
|
2369
|
+
this.setDurationSeconds(duration);
|
|
2370
|
+
};
|
|
2371
|
+
this.clearMetadataProbe = () => {
|
|
2372
|
+
const probe = this._metadataProbe;
|
|
2373
|
+
this._metadataProbe = null;
|
|
2374
|
+
this._metadataProbePromise = void 0;
|
|
2375
|
+
if (!probe) return;
|
|
2376
|
+
try {
|
|
2377
|
+
probe.pause();
|
|
2378
|
+
} catch {
|
|
2379
|
+
}
|
|
2380
|
+
probe.removeAttribute("src");
|
|
2381
|
+
try {
|
|
2382
|
+
probe.load();
|
|
2383
|
+
} catch {
|
|
2384
|
+
}
|
|
2385
|
+
};
|
|
2386
|
+
this.preloadMetadata = () => {
|
|
2387
|
+
if (this._disposed || this.durationSeconds != null || !this.src || this._metadataProbePromise || typeof document === "undefined") {
|
|
2388
|
+
return;
|
|
2389
|
+
}
|
|
2390
|
+
const probe = document.createElement("audio");
|
|
2391
|
+
probe.preload = "metadata";
|
|
2392
|
+
this._metadataProbe = probe;
|
|
2393
|
+
this._metadataProbePromise = new Promise((resolve) => {
|
|
2394
|
+
const cleanup = () => {
|
|
2395
|
+
probe.removeEventListener("loadedmetadata", handleLoadedMetadata);
|
|
2396
|
+
probe.removeEventListener("error", handleError);
|
|
2397
|
+
if (this._metadataProbe === probe) {
|
|
2398
|
+
this.clearMetadataProbe();
|
|
2399
|
+
} else {
|
|
2400
|
+
this._metadataProbePromise = void 0;
|
|
2401
|
+
}
|
|
2402
|
+
resolve();
|
|
2403
|
+
};
|
|
2404
|
+
const handleLoadedMetadata = () => {
|
|
2405
|
+
this.updateDurationFromElement(probe);
|
|
2406
|
+
cleanup();
|
|
2407
|
+
};
|
|
2408
|
+
const handleError = () => {
|
|
2409
|
+
cleanup();
|
|
2410
|
+
};
|
|
2411
|
+
probe.addEventListener("loadedmetadata", handleLoadedMetadata, { once: true });
|
|
2412
|
+
probe.addEventListener("error", handleError, { once: true });
|
|
2413
|
+
probe.src = this.src;
|
|
2414
|
+
try {
|
|
2415
|
+
probe.load();
|
|
2416
|
+
} catch {
|
|
2417
|
+
cleanup();
|
|
2418
|
+
}
|
|
2419
|
+
});
|
|
2420
|
+
};
|
|
2421
|
+
this.clearPlaybackStartSafetyTimeout = () => {
|
|
2422
|
+
if (!this.elementRef) return;
|
|
2423
|
+
clearTimeout(this.playTimeout);
|
|
2424
|
+
this.playTimeout = void 0;
|
|
2425
|
+
};
|
|
2426
|
+
this.clearPendingLoadedMeta = () => {
|
|
2427
|
+
const pending = this._pendingLoadedMeta;
|
|
2428
|
+
if (pending?.element && pending.onLoaded) {
|
|
2429
|
+
pending.element.removeEventListener("loadedmetadata", pending.onLoaded);
|
|
2430
|
+
}
|
|
2431
|
+
this._pendingLoadedMeta = void 0;
|
|
2432
|
+
};
|
|
2433
|
+
this.restoreSavedPosition = (elementRef) => {
|
|
2434
|
+
const saved = this.secondsElapsed;
|
|
2435
|
+
if (!saved || saved <= 0) return;
|
|
2436
|
+
const apply = () => {
|
|
2437
|
+
const duration = elementRef.duration;
|
|
2438
|
+
const clamped = typeof duration === "number" && !isNaN(duration) && isFinite(duration) ? Math.min(saved, duration) : saved;
|
|
2439
|
+
try {
|
|
2440
|
+
if (elementRef.currentTime === clamped) return;
|
|
2441
|
+
elementRef.currentTime = clamped;
|
|
2442
|
+
this.setSecondsElapsed(clamped);
|
|
2443
|
+
} catch {
|
|
2444
|
+
}
|
|
2445
|
+
};
|
|
2446
|
+
if (elementRef.readyState < 1) {
|
|
2447
|
+
this.clearPendingLoadedMeta();
|
|
2448
|
+
this._restoringPosition = true;
|
|
2449
|
+
const onLoaded = () => {
|
|
2450
|
+
if (this._pendingLoadedMeta?.onLoaded !== onLoaded) return;
|
|
2451
|
+
this._pendingLoadedMeta = void 0;
|
|
2452
|
+
if (this.elementRef !== elementRef) {
|
|
2453
|
+
this._restoringPosition = false;
|
|
2454
|
+
return;
|
|
2455
|
+
}
|
|
2456
|
+
apply();
|
|
2457
|
+
this._restoringPosition = false;
|
|
2458
|
+
};
|
|
2459
|
+
elementRef.addEventListener("loadedmetadata", onLoaded, { once: true });
|
|
2460
|
+
this._pendingLoadedMeta = { element: elementRef, onLoaded };
|
|
2461
|
+
} else {
|
|
2462
|
+
this._restoringPosition = true;
|
|
2463
|
+
apply();
|
|
2464
|
+
this._restoringPosition = false;
|
|
2465
|
+
}
|
|
2466
|
+
};
|
|
2467
|
+
this.elementIsReady = () => {
|
|
2468
|
+
if (this._elementIsReadyPromise) return this._elementIsReadyPromise;
|
|
2469
|
+
this._elementIsReadyPromise = new Promise((resolve) => {
|
|
2470
|
+
if (!this.elementRef) return resolve(false);
|
|
2471
|
+
const element = this.elementRef;
|
|
2472
|
+
const handleLoaded = () => {
|
|
2473
|
+
element.removeEventListener("loadedmetadata", handleLoaded);
|
|
2474
|
+
resolve(element.readyState > 0);
|
|
2475
|
+
};
|
|
2476
|
+
element.addEventListener("loadedmetadata", handleLoaded);
|
|
2477
|
+
});
|
|
2478
|
+
return this._elementIsReadyPromise;
|
|
2479
|
+
};
|
|
2480
|
+
this.setRef = (elementRef) => {
|
|
2481
|
+
if (elementIsPlaying(this.elementRef)) {
|
|
2482
|
+
this.releaseElement({ resetState: false });
|
|
2483
|
+
}
|
|
2484
|
+
this.clearPendingLoadedMeta();
|
|
2485
|
+
this.clearMetadataProbe();
|
|
2486
|
+
this._restoringPosition = false;
|
|
2487
|
+
this._elementIsReadyPromise = void 0;
|
|
2488
|
+
this.state.partialNext({ elementRef });
|
|
2489
|
+
if (elementRef) {
|
|
2490
|
+
this.registerSubscriptions();
|
|
2491
|
+
}
|
|
2492
|
+
};
|
|
2493
|
+
this.setSecondsElapsed = (secondsElapsed) => {
|
|
2494
|
+
const duration = this.elementRef?.duration ?? this.durationSeconds;
|
|
2495
|
+
this.state.partialNext({
|
|
2496
|
+
progressPercent: duration && secondsElapsed ? secondsElapsed / duration * 100 : 0,
|
|
2497
|
+
secondsElapsed
|
|
2498
|
+
});
|
|
2499
|
+
};
|
|
2500
|
+
this.canPlayMimeType = (mimeType2) => {
|
|
2501
|
+
if (!mimeType2) return false;
|
|
2502
|
+
if (this.elementRef) return !!this.elementRef.canPlayType(mimeType2);
|
|
2503
|
+
return !!new Audio().canPlayType(mimeType2);
|
|
2504
|
+
};
|
|
2505
|
+
this.play = async (params) => {
|
|
2506
|
+
if (this._disposed) return;
|
|
2507
|
+
const elementRef = this.ensureElementRef();
|
|
2508
|
+
if (elementIsPlaying(this.elementRef)) {
|
|
2509
|
+
if (this.isPlaying) return;
|
|
2510
|
+
this.state.partialNext({ isPlaying: true });
|
|
2511
|
+
return;
|
|
2512
|
+
}
|
|
2513
|
+
const { currentPlaybackRate, playbackRates: playbackRates2 } = {
|
|
2514
|
+
currentPlaybackRate: this.currentPlaybackRate,
|
|
2515
|
+
playbackRates: this.playbackRates,
|
|
2516
|
+
...params
|
|
2517
|
+
};
|
|
2518
|
+
if (!this.canPlayRecord) {
|
|
2519
|
+
this.registerError({ errCode: "not-playable" });
|
|
2520
|
+
return;
|
|
2521
|
+
}
|
|
2522
|
+
this.restoreSavedPosition(elementRef);
|
|
2523
|
+
elementRef.playbackRate = currentPlaybackRate ?? this.currentPlaybackRate;
|
|
2524
|
+
this.setPlaybackStartSafetyTimeout();
|
|
2525
|
+
try {
|
|
2526
|
+
await elementRef.play();
|
|
2527
|
+
this.state.partialNext({
|
|
2528
|
+
currentPlaybackRate,
|
|
2529
|
+
isPlaying: true,
|
|
2530
|
+
playbackRates: playbackRates2
|
|
2531
|
+
});
|
|
2532
|
+
this._pool.setActiveAudioPlayer(this);
|
|
2533
|
+
} catch (e) {
|
|
2534
|
+
this.registerError({ error: e });
|
|
2535
|
+
this.state.partialNext({ isPlaying: false });
|
|
2536
|
+
} finally {
|
|
2537
|
+
this.clearPlaybackStartSafetyTimeout();
|
|
2538
|
+
}
|
|
2539
|
+
};
|
|
2540
|
+
this.pause = () => {
|
|
2541
|
+
if (!elementIsPlaying(this.elementRef)) return;
|
|
2542
|
+
this.clearPlaybackStartSafetyTimeout();
|
|
2543
|
+
this.elementRef.pause();
|
|
2544
|
+
this.state.partialNext({ isPlaying: false });
|
|
2545
|
+
};
|
|
2546
|
+
this.stop = () => {
|
|
2547
|
+
this.pause();
|
|
2548
|
+
this.state.partialNext({ isPlaying: false });
|
|
2549
|
+
this.setSecondsElapsed(0);
|
|
2550
|
+
if (this.elementRef) this.elementRef.currentTime = 0;
|
|
2551
|
+
};
|
|
2552
|
+
this.togglePlay = async () => this.isPlaying ? this.pause() : await this.play();
|
|
2553
|
+
this.increasePlaybackRate = () => {
|
|
2554
|
+
let currentPlaybackRateIndex = this.state.getLatestValue().playbackRates.findIndex((rate) => rate === this.currentPlaybackRate);
|
|
2555
|
+
if (currentPlaybackRateIndex === -1) {
|
|
2556
|
+
currentPlaybackRateIndex = 0;
|
|
2557
|
+
}
|
|
2558
|
+
const nextIndex = currentPlaybackRateIndex === this.playbackRates.length - 1 ? 0 : currentPlaybackRateIndex + 1;
|
|
2559
|
+
const currentPlaybackRate = this.playbackRates[nextIndex];
|
|
2560
|
+
this.state.partialNext({ currentPlaybackRate });
|
|
2561
|
+
if (this.elementRef) {
|
|
2562
|
+
this.elementRef.playbackRate = currentPlaybackRate;
|
|
2563
|
+
}
|
|
2564
|
+
};
|
|
2565
|
+
this.seek = throttle(async ({ clientX, currentTarget }) => {
|
|
2566
|
+
let element = this.elementRef;
|
|
2567
|
+
if (!this.elementRef) {
|
|
2568
|
+
element = this.ensureElementRef();
|
|
2569
|
+
const isReady = await this.elementIsReady();
|
|
2570
|
+
if (!isReady) return;
|
|
2571
|
+
}
|
|
2572
|
+
if (!currentTarget || !element) return;
|
|
2573
|
+
if (!isSeekable(element)) {
|
|
2574
|
+
this.registerError({ errCode: "seek-not-supported" });
|
|
2575
|
+
return;
|
|
2576
|
+
}
|
|
2577
|
+
const { width, x } = currentTarget.getBoundingClientRect();
|
|
2578
|
+
const ratio = (clientX - x) / width;
|
|
2579
|
+
if (ratio > 1 || ratio < 0) return;
|
|
2580
|
+
const currentTime = ratio * element.duration;
|
|
2581
|
+
this.setSecondsElapsed(currentTime);
|
|
2582
|
+
element.currentTime = currentTime;
|
|
2583
|
+
}, 16);
|
|
2584
|
+
this.registerError = (params) => {
|
|
2585
|
+
defaultRegisterAudioPlayerError(params);
|
|
2586
|
+
this.plugins.forEach(({ onError }) => onError?.({ player: this, ...params }));
|
|
2587
|
+
};
|
|
2588
|
+
this.requestRemoval = () => {
|
|
2589
|
+
this._disposed = true;
|
|
2590
|
+
this.cancelScheduledRemoval();
|
|
2591
|
+
this.clearPendingLoadedMeta();
|
|
2592
|
+
this.clearMetadataProbe();
|
|
2593
|
+
this._restoringPosition = false;
|
|
2594
|
+
this.releaseElement({ resetState: true });
|
|
2595
|
+
this.unsubscribeEventListeners?.();
|
|
2596
|
+
this.unsubscribeEventListeners = null;
|
|
2597
|
+
this.plugins.forEach(({ onRemove }) => onRemove?.({ player: this }));
|
|
2598
|
+
this._pool.deregister(this.id);
|
|
2599
|
+
};
|
|
2600
|
+
this.cancelScheduledRemoval = () => {
|
|
2601
|
+
clearTimeout(this._removalTimeout);
|
|
2602
|
+
this._removalTimeout = void 0;
|
|
2603
|
+
};
|
|
2604
|
+
this.scheduleRemoval = (ms = 0) => {
|
|
2605
|
+
this.cancelScheduledRemoval();
|
|
2606
|
+
this._removalTimeout = setTimeout(() => {
|
|
2607
|
+
if (this.disposed) return;
|
|
2608
|
+
this.requestRemoval();
|
|
2609
|
+
}, ms);
|
|
2610
|
+
};
|
|
2611
|
+
this.releaseElementForHandoff = () => {
|
|
2612
|
+
if (!this.elementRef) return;
|
|
2613
|
+
this.releaseElement({ resetState: false });
|
|
2614
|
+
this.unsubscribeEventListeners?.();
|
|
2615
|
+
this.unsubscribeEventListeners = null;
|
|
2616
|
+
};
|
|
2617
|
+
this.registerSubscriptions = () => {
|
|
2618
|
+
this.unsubscribeEventListeners?.();
|
|
2619
|
+
const audioElement = this.elementRef;
|
|
2620
|
+
if (!audioElement) return;
|
|
2621
|
+
const handleEnded = () => {
|
|
2622
|
+
if (audioElement) {
|
|
2623
|
+
this.updateDurationFromElement(audioElement);
|
|
2624
|
+
}
|
|
2625
|
+
this.stop();
|
|
2626
|
+
};
|
|
2627
|
+
const handleError = (e) => {
|
|
2628
|
+
const audio = e.currentTarget;
|
|
2629
|
+
const state = { isPlaying: false };
|
|
2630
|
+
if (!audio?.error?.code) {
|
|
2631
|
+
this.state.partialNext(state);
|
|
2632
|
+
return;
|
|
2633
|
+
}
|
|
2634
|
+
if (audio.error.code === 4) {
|
|
2635
|
+
state.canPlayRecord = false;
|
|
2636
|
+
this.state.partialNext(state);
|
|
2637
|
+
}
|
|
2638
|
+
const errorMsg = [
|
|
2639
|
+
void 0,
|
|
2640
|
+
"MEDIA_ERR_ABORTED: fetch aborted by user",
|
|
2641
|
+
"MEDIA_ERR_NETWORK: network failed while fetching",
|
|
2642
|
+
"MEDIA_ERR_DECODE: audio fetched but couldn’t decode",
|
|
2643
|
+
"MEDIA_ERR_SRC_NOT_SUPPORTED: source not supported"
|
|
2644
|
+
][audio?.error?.code];
|
|
2645
|
+
if (!errorMsg) return;
|
|
2646
|
+
defaultRegisterAudioPlayerError({ error: new Error(errorMsg + ` (${audio.src})`) });
|
|
2647
|
+
};
|
|
2648
|
+
const handleTimeupdate = () => {
|
|
2649
|
+
const t = audioElement?.currentTime ?? 0;
|
|
2650
|
+
if (this._restoringPosition && t === 0) return;
|
|
2651
|
+
if (!this.isPlaying && t === 0 && this.secondsElapsed > 0) return;
|
|
2652
|
+
this.setSecondsElapsed(t);
|
|
2653
|
+
};
|
|
2654
|
+
const handleLoadedMetadata = () => {
|
|
2655
|
+
if (audioElement) {
|
|
2656
|
+
this.updateDurationFromElement(audioElement);
|
|
2657
|
+
}
|
|
2658
|
+
};
|
|
2659
|
+
audioElement.addEventListener("ended", handleEnded);
|
|
2660
|
+
audioElement.addEventListener("error", handleError);
|
|
2661
|
+
audioElement.addEventListener("loadedmetadata", handleLoadedMetadata);
|
|
2662
|
+
audioElement.addEventListener("timeupdate", handleTimeupdate);
|
|
2663
|
+
this.unsubscribeEventListeners = () => {
|
|
2664
|
+
audioElement.pause();
|
|
2665
|
+
audioElement.removeEventListener("ended", handleEnded);
|
|
2666
|
+
audioElement.removeEventListener("error", handleError);
|
|
2667
|
+
audioElement.removeEventListener("loadedmetadata", handleLoadedMetadata);
|
|
2668
|
+
audioElement.removeEventListener("timeupdate", handleTimeupdate);
|
|
2669
|
+
};
|
|
2670
|
+
};
|
|
2671
|
+
this._data = {
|
|
2672
|
+
durationSeconds,
|
|
2673
|
+
fileSize,
|
|
2674
|
+
id,
|
|
2675
|
+
mimeType,
|
|
2676
|
+
src,
|
|
2677
|
+
title,
|
|
2678
|
+
waveformData
|
|
2679
|
+
};
|
|
2680
|
+
this._pool = pool;
|
|
2681
|
+
this.setPlugins(() => plugins ?? []);
|
|
2682
|
+
const playbackRates = customPlaybackRates?.length ? customPlaybackRates : DEFAULT_PLAYBACK_RATES;
|
|
2683
|
+
const canPlayRecord = mimeType ? !!new Audio().canPlayType(mimeType) : true;
|
|
2684
|
+
this.state = new streamChat.StateStore({
|
|
2685
|
+
canPlayRecord,
|
|
2686
|
+
currentPlaybackRate: playbackRates[0],
|
|
2687
|
+
durationSeconds,
|
|
2688
|
+
elementRef: null,
|
|
2689
|
+
isPlaying: false,
|
|
2690
|
+
playbackError: null,
|
|
2691
|
+
playbackRates,
|
|
2692
|
+
progressPercent: 0,
|
|
2693
|
+
secondsElapsed: 0
|
|
2694
|
+
});
|
|
2695
|
+
this.plugins.forEach((p) => p.onInit?.({ player: this }));
|
|
2696
|
+
this.preloadMetadata();
|
|
2740
2697
|
}
|
|
2741
|
-
|
|
2742
|
-
|
|
2698
|
+
get plugins() {
|
|
2699
|
+
return Array.from(this._plugins.values());
|
|
2743
2700
|
}
|
|
2744
|
-
|
|
2745
|
-
|
|
2701
|
+
get canPlayRecord() {
|
|
2702
|
+
return this.state.getLatestValue().canPlayRecord;
|
|
2746
2703
|
}
|
|
2747
|
-
|
|
2748
|
-
|
|
2704
|
+
get elementRef() {
|
|
2705
|
+
return this.state.getLatestValue().elementRef;
|
|
2749
2706
|
}
|
|
2750
|
-
|
|
2751
|
-
|
|
2707
|
+
get isPlaying() {
|
|
2708
|
+
return this.state.getLatestValue().isPlaying;
|
|
2752
2709
|
}
|
|
2753
|
-
|
|
2754
|
-
|
|
2710
|
+
get currentPlaybackRate() {
|
|
2711
|
+
return this.state.getLatestValue().currentPlaybackRate;
|
|
2755
2712
|
}
|
|
2756
|
-
|
|
2757
|
-
|
|
2713
|
+
get playbackRates() {
|
|
2714
|
+
return this.state.getLatestValue().playbackRates;
|
|
2758
2715
|
}
|
|
2759
|
-
|
|
2760
|
-
|
|
2716
|
+
get durationSeconds() {
|
|
2717
|
+
return this.state.getLatestValue().durationSeconds;
|
|
2761
2718
|
}
|
|
2762
|
-
|
|
2763
|
-
|
|
2719
|
+
get fileSize() {
|
|
2720
|
+
return this._data.fileSize;
|
|
2764
2721
|
}
|
|
2765
|
-
|
|
2766
|
-
|
|
2722
|
+
get id() {
|
|
2723
|
+
return this._data.id;
|
|
2767
2724
|
}
|
|
2768
|
-
|
|
2769
|
-
|
|
2725
|
+
get src() {
|
|
2726
|
+
return this._data.src;
|
|
2770
2727
|
}
|
|
2771
|
-
|
|
2772
|
-
|
|
2728
|
+
get mimeType() {
|
|
2729
|
+
return this._data.mimeType;
|
|
2773
2730
|
}
|
|
2774
|
-
|
|
2775
|
-
|
|
2731
|
+
get title() {
|
|
2732
|
+
return this._data.title;
|
|
2776
2733
|
}
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
const ACTIONS_NOT_WORKING_IN_THREAD = [
|
|
2780
|
-
MESSAGE_ACTIONS.pin,
|
|
2781
|
-
MESSAGE_ACTIONS.reply,
|
|
2782
|
-
MESSAGE_ACTIONS.markUnread
|
|
2783
|
-
];
|
|
2784
|
-
function areMessagesEqual(prevMessage, nextMessage) {
|
|
2785
|
-
const areBaseMessagesEqual = (prevMessage2, nextMessage2) => prevMessage2.deleted_at === nextMessage2.deleted_at && prevMessage2.latest_reactions?.length === nextMessage2.latest_reactions?.length && prevMessage2.own_reactions?.length === nextMessage2.own_reactions?.length && prevMessage2.pinned === nextMessage2.pinned && prevMessage2.reply_count === nextMessage2.reply_count && prevMessage2.show_in_channel === nextMessage2.show_in_channel && prevMessage2.status === nextMessage2.status && prevMessage2.text === nextMessage2.text && prevMessage2.type === nextMessage2.type && prevMessage2.updated_at === nextMessage2.updated_at && prevMessage2.user?.updated_at === nextMessage2.user?.updated_at;
|
|
2786
|
-
return areBaseMessagesEqual(prevMessage, nextMessage) && Boolean(prevMessage.quoted_message) === Boolean(nextMessage.quoted_message) && (!prevMessage.quoted_message && !nextMessage.quoted_message || areBaseMessagesEqual(
|
|
2787
|
-
prevMessage.quoted_message,
|
|
2788
|
-
nextMessage.quoted_message
|
|
2789
|
-
));
|
|
2790
|
-
}
|
|
2791
|
-
const areMessagePropsEqual = (prevProps, nextProps) => {
|
|
2792
|
-
const { message: prevMessage, Message: prevMessageUI } = prevProps;
|
|
2793
|
-
const { message: nextMessage, Message: nextMessageUI } = nextProps;
|
|
2794
|
-
if (prevMessageUI !== nextMessageUI) return false;
|
|
2795
|
-
if (nextProps.showDetailedReactions !== prevProps.showDetailedReactions) {
|
|
2796
|
-
return false;
|
|
2734
|
+
get waveformData() {
|
|
2735
|
+
return this._data.waveformData;
|
|
2797
2736
|
}
|
|
2798
|
-
|
|
2799
|
-
return
|
|
2737
|
+
get secondsElapsed() {
|
|
2738
|
+
return this.state.getLatestValue().secondsElapsed;
|
|
2800
2739
|
}
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
const deepEqualProps = deepequal(nextProps.messageActions, prevProps.messageActions) && deepequal(nextProps.readBy, prevProps.readBy) && deepequal(nextProps.deliveredTo, prevProps.deliveredTo) && deepequal(nextProps.highlighted, prevProps.highlighted) && deepequal(nextProps.groupStyles, prevProps.groupStyles) && // last 3 messages can have different group styles
|
|
2804
|
-
deepequal(nextProps.mutes, prevProps.mutes) && deepequal(nextProps.lastReceivedId, prevProps.lastReceivedId);
|
|
2805
|
-
if (!deepEqualProps) return false;
|
|
2806
|
-
return prevProps.messageListRect === nextProps.messageListRect;
|
|
2807
|
-
};
|
|
2808
|
-
const areMessageUIPropsEqual = (prevProps, nextProps) => {
|
|
2809
|
-
const { lastReceivedId: prevLastReceivedId, message: prevMessage } = prevProps;
|
|
2810
|
-
const { lastReceivedId: nextLastReceivedId, message: nextMessage } = nextProps;
|
|
2811
|
-
if (prevProps.highlighted !== nextProps.highlighted) return false;
|
|
2812
|
-
if (prevProps.threadList !== nextProps.threadList) return false;
|
|
2813
|
-
if (prevProps.endOfGroup !== nextProps.endOfGroup) return false;
|
|
2814
|
-
if (prevProps.mutes?.length !== nextProps.mutes?.length) return false;
|
|
2815
|
-
if (prevProps.readBy?.length !== nextProps.readBy?.length) return false;
|
|
2816
|
-
if (prevProps.deliveredTo?.length !== nextProps.deliveredTo?.length) return false;
|
|
2817
|
-
if (prevProps.groupStyles !== nextProps.groupStyles) return false;
|
|
2818
|
-
if (prevProps.showDetailedReactions !== nextProps.showDetailedReactions) {
|
|
2819
|
-
return false;
|
|
2740
|
+
get progressPercent() {
|
|
2741
|
+
return this.state.getLatestValue().progressPercent;
|
|
2820
2742
|
}
|
|
2821
|
-
|
|
2822
|
-
return
|
|
2743
|
+
get disposed() {
|
|
2744
|
+
return this._disposed;
|
|
2823
2745
|
}
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
const
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2746
|
+
ensureElementRef() {
|
|
2747
|
+
if (this._disposed) {
|
|
2748
|
+
throw new Error("AudioPlayer is disposed");
|
|
2749
|
+
}
|
|
2750
|
+
if (!this.elementRef) {
|
|
2751
|
+
const el = this._pool.acquireElement({
|
|
2752
|
+
ownerId: this.id,
|
|
2753
|
+
src: this.src
|
|
2754
|
+
});
|
|
2755
|
+
this.setRef(el);
|
|
2756
|
+
}
|
|
2757
|
+
return this.elementRef;
|
|
2834
2758
|
}
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2759
|
+
setDescriptor(descriptor) {
|
|
2760
|
+
const previousSrc = this.src;
|
|
2761
|
+
this._data = { ...this._data, ...descriptor };
|
|
2762
|
+
if (descriptor.src !== previousSrc && this.elementRef) {
|
|
2763
|
+
this.elementRef.src = descriptor.src;
|
|
2764
|
+
}
|
|
2765
|
+
if (descriptor.src && descriptor.src !== previousSrc) {
|
|
2766
|
+
this.clearMetadataProbe();
|
|
2767
|
+
if (descriptor.durationSeconds == null) {
|
|
2768
|
+
this.setDurationSeconds(void 0);
|
|
2769
|
+
this.preloadMetadata();
|
|
2770
|
+
} else {
|
|
2771
|
+
this.setDurationSeconds(descriptor.durationSeconds);
|
|
2772
|
+
}
|
|
2773
|
+
return;
|
|
2774
|
+
}
|
|
2775
|
+
if (descriptor.durationSeconds != null) {
|
|
2776
|
+
this.setDurationSeconds(descriptor.durationSeconds);
|
|
2777
|
+
}
|
|
2840
2778
|
}
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2779
|
+
releaseElement({ resetState }) {
|
|
2780
|
+
this.clearPendingLoadedMeta();
|
|
2781
|
+
this.clearMetadataProbe();
|
|
2782
|
+
this._restoringPosition = false;
|
|
2783
|
+
if (resetState) {
|
|
2784
|
+
this.stop();
|
|
2785
|
+
} else {
|
|
2786
|
+
this.state.partialNext({ isPlaying: false });
|
|
2787
|
+
if (this.elementRef) {
|
|
2788
|
+
try {
|
|
2789
|
+
this.elementRef.pause();
|
|
2790
|
+
} catch {
|
|
2791
|
+
}
|
|
2792
|
+
}
|
|
2793
|
+
}
|
|
2794
|
+
if (this.elementRef) {
|
|
2795
|
+
this._pool.releaseElement(this.id);
|
|
2796
|
+
this.setRef(null);
|
|
2797
|
+
}
|
|
2850
2798
|
}
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2799
|
+
setPlugins(setter) {
|
|
2800
|
+
this._plugins = setter(this.plugins).reduce((acc, plugin) => {
|
|
2801
|
+
if (plugin.id) {
|
|
2802
|
+
acc.set(plugin.id, plugin);
|
|
2803
|
+
}
|
|
2804
|
+
return acc;
|
|
2805
|
+
}, /* @__PURE__ */ new Map());
|
|
2855
2806
|
}
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
} else if (slicedArr.length === 2) {
|
|
2862
|
-
outStr = t("{{ firstUser }} and {{ secondUser }}", {
|
|
2863
|
-
firstUser: slicedArr[0],
|
|
2864
|
-
secondUser: slicedArr[1]
|
|
2807
|
+
}
|
|
2808
|
+
class AudioPlayerPool {
|
|
2809
|
+
constructor(config) {
|
|
2810
|
+
this.state = new streamChat.StateStore({
|
|
2811
|
+
activeAudioPlayer: null
|
|
2865
2812
|
});
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2813
|
+
this.pool = /* @__PURE__ */ new Map();
|
|
2814
|
+
this.audios = /* @__PURE__ */ new Map();
|
|
2815
|
+
this.sharedAudio = null;
|
|
2816
|
+
this.sharedOwnerId = null;
|
|
2817
|
+
this.getOrAdd = (params) => {
|
|
2818
|
+
const { playbackRates, plugins, ...descriptor } = params;
|
|
2819
|
+
let player = this.pool.get(params.id);
|
|
2820
|
+
if (player) {
|
|
2821
|
+
if (!player.disposed) {
|
|
2822
|
+
player.setDescriptor(descriptor);
|
|
2823
|
+
return player;
|
|
2824
|
+
}
|
|
2825
|
+
this.deregister(params.id);
|
|
2826
|
+
}
|
|
2827
|
+
player = new AudioPlayer({
|
|
2828
|
+
playbackRates,
|
|
2829
|
+
plugins,
|
|
2830
|
+
...descriptor,
|
|
2831
|
+
pool: this
|
|
2872
2832
|
});
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2833
|
+
this.pool.set(params.id, player);
|
|
2834
|
+
return player;
|
|
2835
|
+
};
|
|
2836
|
+
this.acquireElement = ({ ownerId, src }) => {
|
|
2837
|
+
if (!this.allowConcurrentPlayback) {
|
|
2838
|
+
if (!this.sharedAudio) {
|
|
2839
|
+
this.sharedAudio = new Audio();
|
|
2840
|
+
}
|
|
2841
|
+
if (this.sharedOwnerId && this.sharedOwnerId !== ownerId) {
|
|
2842
|
+
const previous = this.pool.get(this.sharedOwnerId);
|
|
2843
|
+
previous?.pause();
|
|
2844
|
+
previous?.releaseElementForHandoff();
|
|
2845
|
+
}
|
|
2846
|
+
this.sharedOwnerId = ownerId;
|
|
2847
|
+
if (this.sharedAudio.src !== src) {
|
|
2848
|
+
this.sharedAudio.src = src;
|
|
2849
|
+
}
|
|
2850
|
+
return this.sharedAudio;
|
|
2851
|
+
}
|
|
2852
|
+
let audio = this.audios.get(ownerId);
|
|
2853
|
+
if (!audio) {
|
|
2854
|
+
audio = new Audio();
|
|
2855
|
+
this.audios.set(ownerId, audio);
|
|
2856
|
+
}
|
|
2857
|
+
if (audio.src !== src) {
|
|
2858
|
+
audio.src = src;
|
|
2859
|
+
}
|
|
2860
|
+
return audio;
|
|
2861
|
+
};
|
|
2862
|
+
this.releaseElement = (ownerId) => {
|
|
2863
|
+
if (!this.allowConcurrentPlayback) {
|
|
2864
|
+
if (this.sharedOwnerId !== ownerId) return;
|
|
2865
|
+
const el2 = this.sharedAudio;
|
|
2866
|
+
if (el2) {
|
|
2867
|
+
try {
|
|
2868
|
+
el2.pause();
|
|
2869
|
+
} catch {
|
|
2870
|
+
}
|
|
2871
|
+
el2.removeAttribute("src");
|
|
2872
|
+
el2.load();
|
|
2873
|
+
}
|
|
2874
|
+
this.sharedOwnerId = null;
|
|
2875
|
+
return;
|
|
2876
|
+
}
|
|
2877
|
+
const el = this.audios.get(ownerId);
|
|
2878
|
+
if (!el) return;
|
|
2879
|
+
try {
|
|
2880
|
+
el.pause();
|
|
2881
|
+
} catch {
|
|
2882
|
+
}
|
|
2883
|
+
el.removeAttribute("src");
|
|
2884
|
+
el.load();
|
|
2885
|
+
this.audios.delete(ownerId);
|
|
2886
|
+
};
|
|
2887
|
+
this.setActiveAudioPlayer = (activeAudioPlayer) => {
|
|
2888
|
+
if (this.allowConcurrentPlayback) return;
|
|
2889
|
+
this.state.partialNext({ activeAudioPlayer });
|
|
2890
|
+
};
|
|
2891
|
+
this.remove = (id) => {
|
|
2892
|
+
const player = this.pool.get(id);
|
|
2893
|
+
if (!player) return;
|
|
2894
|
+
player.requestRemoval();
|
|
2895
|
+
};
|
|
2896
|
+
this.clear = () => {
|
|
2897
|
+
this.players.forEach((player) => {
|
|
2898
|
+
this.remove(player.id);
|
|
2899
|
+
});
|
|
2900
|
+
};
|
|
2901
|
+
this.registerSubscriptions = () => {
|
|
2902
|
+
this.players.forEach((p) => {
|
|
2903
|
+
if (p.elementRef) {
|
|
2904
|
+
p.registerSubscriptions();
|
|
2905
|
+
}
|
|
2906
|
+
});
|
|
2907
|
+
};
|
|
2908
|
+
this.allowConcurrentPlayback = !!config?.allowConcurrentPlayback;
|
|
2909
|
+
}
|
|
2910
|
+
get players() {
|
|
2911
|
+
return Array.from(this.pool.values());
|
|
2912
|
+
}
|
|
2913
|
+
get activeAudioPlayer() {
|
|
2914
|
+
return this.state.getLatestValue().activeAudioPlayer;
|
|
2915
|
+
}
|
|
2916
|
+
/** Removes the AudioPlayer instance from the pool of players */
|
|
2917
|
+
deregister(id) {
|
|
2918
|
+
if (this.pool.has(id)) {
|
|
2919
|
+
this.pool.delete(id);
|
|
2920
|
+
}
|
|
2921
|
+
if (this.activeAudioPlayer?.id === id) {
|
|
2922
|
+
this.setActiveAudioPlayer(null);
|
|
2923
|
+
}
|
|
2924
|
+
}
|
|
2925
|
+
}
|
|
2926
|
+
const SEEK_NOT_SUPPORTED_NOTIFICATION_DEBOUNCE_INTERVAL_MS = 1e3;
|
|
2927
|
+
const audioPlayerNotificationsPluginFactory = ({
|
|
2928
|
+
addNotification,
|
|
2929
|
+
panel = "channel",
|
|
2930
|
+
t
|
|
2931
|
+
}) => {
|
|
2932
|
+
const errors = {
|
|
2933
|
+
"failed-to-start": new Error(t("Failed to play the recording")),
|
|
2934
|
+
"not-playable": new Error(
|
|
2935
|
+
t("Recording format is not supported and cannot be reproduced")
|
|
2936
|
+
),
|
|
2937
|
+
"seek-not-supported": new Error(t("Cannot seek in the recording"))
|
|
2938
|
+
};
|
|
2939
|
+
let lastSeekNotSupportedNotificationAt;
|
|
2940
|
+
return {
|
|
2941
|
+
id: "AudioPlayerNotificationsPlugin",
|
|
2942
|
+
onError: ({ errCode, error: e }) => {
|
|
2943
|
+
if (errCode === "seek-not-supported") {
|
|
2944
|
+
const now = Date.now();
|
|
2945
|
+
if (typeof lastSeekNotSupportedNotificationAt === "number" && now - lastSeekNotSupportedNotificationAt < SEEK_NOT_SUPPORTED_NOTIFICATION_DEBOUNCE_INTERVAL_MS) {
|
|
2946
|
+
return;
|
|
2947
|
+
}
|
|
2948
|
+
lastSeekNotSupportedNotificationAt = now;
|
|
2949
|
+
}
|
|
2950
|
+
const error = (errCode && errors[errCode]) ?? e ?? new Error(t("Error reproducing the recording"));
|
|
2951
|
+
addNotification({
|
|
2952
|
+
emitter: "AudioPlayer",
|
|
2953
|
+
error,
|
|
2954
|
+
message: error.message,
|
|
2955
|
+
severity: "error",
|
|
2956
|
+
targetPanels: [panel],
|
|
2957
|
+
type: "browser:audio:playback:error"
|
|
2877
2958
|
});
|
|
2878
2959
|
}
|
|
2879
|
-
}
|
|
2880
|
-
return outStr;
|
|
2960
|
+
};
|
|
2881
2961
|
};
|
|
2882
|
-
const
|
|
2883
|
-
|
|
2884
|
-
|
|
2962
|
+
const AudioPlayerContext = React.createContext({
|
|
2963
|
+
audioPlayers: null
|
|
2964
|
+
});
|
|
2965
|
+
const WithAudioPlayback = ({
|
|
2966
|
+
allowConcurrentPlayback,
|
|
2967
|
+
children
|
|
2968
|
+
}) => {
|
|
2969
|
+
const [audioPlayers] = React.useState(() => new AudioPlayerPool({ allowConcurrentPlayback }));
|
|
2970
|
+
React.useEffect(
|
|
2971
|
+
() => () => {
|
|
2972
|
+
audioPlayers.clear();
|
|
2973
|
+
},
|
|
2974
|
+
[audioPlayers]
|
|
2975
|
+
);
|
|
2976
|
+
return /* @__PURE__ */ jsxRuntime.jsx(AudioPlayerContext.Provider, { value: { audioPlayers }, children });
|
|
2885
2977
|
};
|
|
2886
|
-
const
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2978
|
+
const makeAudioPlayerId = ({ requester, src }) => `${requester ?? "requester-unknown"}:${src}`;
|
|
2979
|
+
const useAudioPlayer = ({
|
|
2980
|
+
durationSeconds,
|
|
2981
|
+
fileSize,
|
|
2982
|
+
mimeType,
|
|
2983
|
+
playbackRates,
|
|
2984
|
+
plugins,
|
|
2985
|
+
requester = "",
|
|
2986
|
+
src,
|
|
2987
|
+
title,
|
|
2988
|
+
waveformData
|
|
2989
|
+
}) => {
|
|
2990
|
+
const { addNotification } = useNotificationApi();
|
|
2991
|
+
const panel = useNotificationTarget();
|
|
2992
|
+
const { t } = useTranslationContext();
|
|
2993
|
+
const { audioPlayers } = React.useContext(AudioPlayerContext);
|
|
2994
|
+
const audioPlayer = src && audioPlayers ? audioPlayers.getOrAdd({
|
|
2995
|
+
durationSeconds,
|
|
2996
|
+
fileSize,
|
|
2997
|
+
id: makeAudioPlayerId({ requester, src }),
|
|
2998
|
+
mimeType,
|
|
2999
|
+
playbackRates,
|
|
3000
|
+
plugins,
|
|
3001
|
+
src,
|
|
3002
|
+
title,
|
|
3003
|
+
waveformData
|
|
3004
|
+
}) : void 0;
|
|
3005
|
+
React.useEffect(() => {
|
|
3006
|
+
if (!audioPlayer) return;
|
|
3007
|
+
const notificationsPlugin = audioPlayerNotificationsPluginFactory({
|
|
3008
|
+
addNotification,
|
|
3009
|
+
panel,
|
|
3010
|
+
t
|
|
3011
|
+
});
|
|
3012
|
+
audioPlayer.setPlugins((currentPlugins) => [
|
|
3013
|
+
...currentPlugins.filter((plugin) => plugin.id !== notificationsPlugin.id),
|
|
3014
|
+
notificationsPlugin
|
|
3015
|
+
]);
|
|
3016
|
+
}, [addNotification, audioPlayer, panel, t]);
|
|
3017
|
+
return audioPlayer;
|
|
3018
|
+
};
|
|
3019
|
+
const activeAudioPlayerSelector = ({ activeAudioPlayer }) => ({
|
|
3020
|
+
activeAudioPlayer
|
|
3021
|
+
});
|
|
3022
|
+
const useActiveAudioPlayer = () => {
|
|
3023
|
+
const { audioPlayers } = React.useContext(AudioPlayerContext);
|
|
3024
|
+
const { activeAudioPlayer } = useStateStore(audioPlayers?.state, activeAudioPlayerSelector) ?? {};
|
|
3025
|
+
return activeAudioPlayer;
|
|
2891
3026
|
};
|
|
2892
|
-
const isMessageErrorRetryable = (message) => message.status === "failed" && message.error?.status !== 403;
|
|
2893
|
-
const isNetworkSendFailure = (message) => message.status === "failed" && message.error?.status === 0;
|
|
2894
|
-
const isMessageBounced = (message) => message.type === "error" && (message.moderation_details?.action === "MESSAGE_RESPONSE_ACTION_BOUNCE" || message.moderation?.action === "bounce");
|
|
2895
|
-
const isMessageBlocked = (message) => message.shadowed || message.type === "error" && (message.moderation_details?.action === "MESSAGE_RESPONSE_ACTION_REMOVE" || message.moderation?.action === "remove");
|
|
2896
|
-
const isMessageDeleted = (message) => Boolean(message.deleted_at || message.type === "deleted" || message.deleted_for_me);
|
|
2897
|
-
const isMessageEdited = (message) => !!message.message_text_updated_at;
|
|
2898
|
-
const hasResizeObserver = typeof window !== "undefined" && "ResizeObserver" in window;
|
|
2899
|
-
function autoMiddlewareFor(p) {
|
|
2900
|
-
if (!String(p).startsWith("auto")) return null;
|
|
2901
|
-
const alignment = p === "auto-start" ? "start" : p === "auto-end" ? "end" : void 0;
|
|
2902
|
-
return react.autoPlacement({ alignment });
|
|
2903
|
-
}
|
|
2904
|
-
function toOffsetMw(opt) {
|
|
2905
|
-
if (opt == null) return null;
|
|
2906
|
-
if (Array.isArray(opt)) {
|
|
2907
|
-
const [crossAxis, mainAxis] = opt;
|
|
2908
|
-
return react.offset({ crossAxis, mainAxis });
|
|
2909
|
-
}
|
|
2910
|
-
if (typeof opt === "number") return react.offset(opt);
|
|
2911
|
-
return react.offset(opt);
|
|
2912
|
-
}
|
|
2913
|
-
function usePopoverPosition({
|
|
2914
|
-
allowFlip = true,
|
|
2915
|
-
allowShift = true,
|
|
2916
|
-
autoUpdateOptions,
|
|
2917
|
-
fitAvailableSpace = false,
|
|
2918
|
-
freeze = false,
|
|
2919
|
-
offset,
|
|
2920
|
-
placement = "bottom-start",
|
|
2921
|
-
shiftOptions
|
|
2922
|
-
}) {
|
|
2923
|
-
const autoMw = autoMiddlewareFor(placement);
|
|
2924
|
-
const offsetMiddleware = toOffsetMw(offset);
|
|
2925
|
-
const isSidePlacement = placement.startsWith("left") || placement.startsWith("right");
|
|
2926
|
-
const mergedShiftOptions = shiftOptions ? { padding: 8, ...shiftOptions } : { padding: 8 };
|
|
2927
|
-
const middleware = [
|
|
2928
|
-
// offset first (mirrors common Popper setups)
|
|
2929
|
-
...offsetMiddleware ? [offsetMiddleware] : [],
|
|
2930
|
-
// choose between autoPlacement (Popper's "auto*") OR flip()
|
|
2931
|
-
// only allow flip when not explicitly 'left*' or 'right*'
|
|
2932
|
-
...autoMw ? [autoMw] : allowFlip && !isSidePlacement ? [react.flip()] : [],
|
|
2933
|
-
// viewport collision adjustments
|
|
2934
|
-
...allowShift ? [react.shift(mergedShiftOptions)] : [],
|
|
2935
|
-
// optional size constraining
|
|
2936
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
2937
|
-
...fitAvailableSpace ? [react.size({ apply: () => {
|
|
2938
|
-
} })] : []
|
|
2939
|
-
];
|
|
2940
|
-
const seedPlacement = String(placement).startsWith("auto") ? "bottom" : placement;
|
|
2941
|
-
return react.useFloating({
|
|
2942
|
-
middleware,
|
|
2943
|
-
placement: seedPlacement,
|
|
2944
|
-
strategy: "fixed",
|
|
2945
|
-
whileElementsMounted: freeze ? void 0 : (reference, floating, update) => react.autoUpdate(reference, floating, update, {
|
|
2946
|
-
ancestorResize: true,
|
|
2947
|
-
ancestorScroll: true,
|
|
2948
|
-
animationFrame: false,
|
|
2949
|
-
elementResize: hasResizeObserver,
|
|
2950
|
-
...autoUpdateOptions
|
|
2951
|
-
})
|
|
2952
|
-
});
|
|
2953
|
-
}
|
|
2954
|
-
const LegacyThreadContext = React.createContext({ legacyThread: void 0 });
|
|
2955
|
-
const useLegacyThreadContext = () => React.useContext(LegacyThreadContext);
|
|
2956
3027
|
const cooldownTimerStateSelector = (state) => ({
|
|
2957
3028
|
isCooldownActive: !!state.cooldownRemaining
|
|
2958
3029
|
});
|
|
@@ -3440,10 +3511,10 @@ const UnMemoizedChannel = (props) => {
|
|
|
3440
3511
|
if (channelsQueryState.queryInProgress === "reload" && LoadingIndicator) {
|
|
3441
3512
|
return /* @__PURE__ */ jsxRuntime.jsx(ChannelContainer, { children: /* @__PURE__ */ jsxRuntime.jsx(LoadingIndicator, {}) });
|
|
3442
3513
|
}
|
|
3443
|
-
if (channelsQueryState.error && LoadingErrorIndicator2) {
|
|
3514
|
+
if (channelsQueryState.error && !channel && LoadingErrorIndicator2) {
|
|
3444
3515
|
return /* @__PURE__ */ jsxRuntime.jsx(ChannelContainer, { children: /* @__PURE__ */ jsxRuntime.jsx(LoadingErrorIndicator2, { error: channelsQueryState.error }) });
|
|
3445
3516
|
}
|
|
3446
|
-
if (channelsQueryState.error) {
|
|
3517
|
+
if (channelsQueryState.error && !channel) {
|
|
3447
3518
|
return /* @__PURE__ */ jsxRuntime.jsx(ChannelContainer, {});
|
|
3448
3519
|
}
|
|
3449
3520
|
if (!channel?.cid) {
|
|
@@ -4122,7 +4193,7 @@ const ChannelInner = (props) => {
|
|
|
4122
4193
|
imageAttachmentSizeHandler: props.imageAttachmentSizeHandler || getImageAttachmentConfiguration,
|
|
4123
4194
|
mutes,
|
|
4124
4195
|
notifications: [],
|
|
4125
|
-
shouldGenerateVideoThumbnail: props.shouldGenerateVideoThumbnail
|
|
4196
|
+
shouldGenerateVideoThumbnail: props.shouldGenerateVideoThumbnail ?? true,
|
|
4126
4197
|
videoAttachmentSizeHandler: props.videoAttachmentSizeHandler || getVideoAttachmentConfiguration,
|
|
4127
4198
|
watcher_count: state.watcherCount
|
|
4128
4199
|
});
|
|
@@ -4200,7 +4271,31 @@ const UnreadCountBadge = ({
|
|
|
4200
4271
|
}
|
|
4201
4272
|
)
|
|
4202
4273
|
] });
|
|
4274
|
+
const DEFAULT_CHAT_VIEW_A11Y_CONTEXT_VALUE = {
|
|
4275
|
+
chatViewPanelIds: {
|
|
4276
|
+
channels: "str-chat__chat-view-panel-channels",
|
|
4277
|
+
threads: "str-chat__chat-view-panel-threads"
|
|
4278
|
+
},
|
|
4279
|
+
chatViewTabIds: {
|
|
4280
|
+
channels: "str-chat__chat-view-tab-channels",
|
|
4281
|
+
threads: "str-chat__chat-view-tab-threads"
|
|
4282
|
+
}
|
|
4283
|
+
};
|
|
4284
|
+
const createChatViewA11yContextValue = (chatViewId) => ({
|
|
4285
|
+
// Keep IDs unique per ChatView instance so ARIA references do not collide.
|
|
4286
|
+
chatViewPanelIds: {
|
|
4287
|
+
channels: `str-chat__chat-view-${chatViewId}-panel-channels`,
|
|
4288
|
+
threads: `str-chat__chat-view-${chatViewId}-panel-threads`
|
|
4289
|
+
},
|
|
4290
|
+
chatViewTabIds: {
|
|
4291
|
+
channels: `str-chat__chat-view-${chatViewId}-tab-channels`,
|
|
4292
|
+
threads: `str-chat__chat-view-${chatViewId}-tab-threads`
|
|
4293
|
+
}
|
|
4294
|
+
});
|
|
4203
4295
|
const ChatViewContext = React.createContext(void 0);
|
|
4296
|
+
const ChatViewA11yContext = React.createContext(
|
|
4297
|
+
DEFAULT_CHAT_VIEW_A11Y_CONTEXT_VALUE
|
|
4298
|
+
);
|
|
4204
4299
|
const useChatViewContext = () => {
|
|
4205
4300
|
const value = React.useContext(ChatViewContext);
|
|
4206
4301
|
if (!value) {
|
|
@@ -4211,16 +4306,33 @@ const useChatViewContext = () => {
|
|
|
4211
4306
|
}
|
|
4212
4307
|
return value;
|
|
4213
4308
|
};
|
|
4309
|
+
const useChatViewA11yContext = () => React.useContext(ChatViewA11yContext);
|
|
4214
4310
|
const ChatView = ({ children }) => {
|
|
4215
4311
|
const [activeChatView, setActiveChatView] = React.useState("channels");
|
|
4312
|
+
const chatViewId = React.useId().replace(/:/g, "");
|
|
4216
4313
|
const { theme } = useChatContext();
|
|
4314
|
+
const a11yValue = React.useMemo(
|
|
4315
|
+
() => createChatViewA11yContextValue(chatViewId),
|
|
4316
|
+
[chatViewId]
|
|
4317
|
+
);
|
|
4217
4318
|
const value = React.useMemo(() => ({ activeChatView, setActiveChatView }), [activeChatView]);
|
|
4218
|
-
return /* @__PURE__ */ jsxRuntime.jsx(ChatViewContext.Provider, { value, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: clsx("str-chat", theme, "str-chat__chat-view"), children }) });
|
|
4319
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ChatViewA11yContext.Provider, { value: a11yValue, children: /* @__PURE__ */ jsxRuntime.jsx(ChatViewContext.Provider, { value, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: clsx("str-chat", theme, "str-chat__chat-view"), children }) }) });
|
|
4219
4320
|
};
|
|
4220
4321
|
const ChannelsView = ({ children }) => {
|
|
4221
4322
|
const { activeChatView } = useChatViewContext();
|
|
4222
|
-
|
|
4223
|
-
|
|
4323
|
+
const { chatViewPanelIds, chatViewTabIds } = useChatViewA11yContext();
|
|
4324
|
+
const isActive = activeChatView === "channels";
|
|
4325
|
+
if (!isActive) return null;
|
|
4326
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4327
|
+
"div",
|
|
4328
|
+
{
|
|
4329
|
+
"aria-labelledby": chatViewTabIds.channels,
|
|
4330
|
+
className: "str-chat__chat-view__channels",
|
|
4331
|
+
id: chatViewPanelIds.channels,
|
|
4332
|
+
role: "tabpanel",
|
|
4333
|
+
children
|
|
4334
|
+
}
|
|
4335
|
+
);
|
|
4224
4336
|
};
|
|
4225
4337
|
const ThreadsViewContext = React.createContext({
|
|
4226
4338
|
activeThread: void 0,
|
|
@@ -4229,10 +4341,21 @@ const ThreadsViewContext = React.createContext({
|
|
|
4229
4341
|
const useThreadsViewContext = () => React.useContext(ThreadsViewContext);
|
|
4230
4342
|
const ThreadsView = ({ children }) => {
|
|
4231
4343
|
const { activeChatView } = useChatViewContext();
|
|
4344
|
+
const { chatViewPanelIds, chatViewTabIds } = useChatViewA11yContext();
|
|
4232
4345
|
const [activeThread, setActiveThread] = React.useState(void 0);
|
|
4233
4346
|
const value = React.useMemo(() => ({ activeThread, setActiveThread }), [activeThread]);
|
|
4234
|
-
|
|
4235
|
-
|
|
4347
|
+
const isActive = activeChatView === "threads";
|
|
4348
|
+
if (!isActive) return null;
|
|
4349
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ThreadsViewContext.Provider, { value, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4350
|
+
"div",
|
|
4351
|
+
{
|
|
4352
|
+
"aria-labelledby": chatViewTabIds.threads,
|
|
4353
|
+
className: "str-chat__chat-view__threads",
|
|
4354
|
+
id: chatViewPanelIds.threads,
|
|
4355
|
+
role: "tabpanel",
|
|
4356
|
+
children
|
|
4357
|
+
}
|
|
4358
|
+
) });
|
|
4236
4359
|
};
|
|
4237
4360
|
const useActiveThread = ({ activeThread }) => {
|
|
4238
4361
|
React.useEffect(() => {
|
|
@@ -4328,17 +4451,22 @@ const ChatViewChannelsSelectorButton = ({
|
|
|
4328
4451
|
iconOnly = true
|
|
4329
4452
|
}) => {
|
|
4330
4453
|
const { activeChatView, setActiveChatView } = useChatViewContext();
|
|
4454
|
+
const { chatViewPanelIds, chatViewTabIds } = useChatViewA11yContext();
|
|
4331
4455
|
const { t } = useTranslationContext();
|
|
4332
4456
|
const isActive = activeChatView === "channels";
|
|
4333
4457
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4334
4458
|
ChatViewSelectorButton,
|
|
4335
4459
|
{
|
|
4336
4460
|
ActiveIcon: IconMessageBubbleFill,
|
|
4461
|
+
"aria-controls": chatViewPanelIds.channels,
|
|
4337
4462
|
"aria-selected": isActive,
|
|
4338
4463
|
Icon: IconMessageBubble,
|
|
4339
4464
|
iconOnly,
|
|
4465
|
+
id: chatViewTabIds.channels,
|
|
4340
4466
|
isActive,
|
|
4467
|
+
onClick: () => setActiveChatView("channels"),
|
|
4341
4468
|
onPointerDown: () => setActiveChatView("channels"),
|
|
4469
|
+
tabIndex: 0,
|
|
4342
4470
|
text: t("Channels")
|
|
4343
4471
|
}
|
|
4344
4472
|
);
|
|
@@ -4354,17 +4482,22 @@ const ChatViewThreadsSelectorButton = ({
|
|
|
4354
4482
|
unreadThreadCount: 0
|
|
4355
4483
|
};
|
|
4356
4484
|
const { activeChatView, setActiveChatView } = useChatViewContext();
|
|
4485
|
+
const { chatViewPanelIds, chatViewTabIds } = useChatViewA11yContext();
|
|
4357
4486
|
const { t } = useTranslationContext();
|
|
4358
4487
|
const isActive = activeChatView === "threads";
|
|
4359
4488
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4360
4489
|
ChatViewSelectorButton,
|
|
4361
4490
|
{
|
|
4362
4491
|
ActiveIcon: IconThreadFill,
|
|
4492
|
+
"aria-controls": chatViewPanelIds.threads,
|
|
4363
4493
|
"aria-selected": isActive,
|
|
4364
4494
|
Icon: IconThread,
|
|
4365
4495
|
iconOnly,
|
|
4496
|
+
id: chatViewTabIds.threads,
|
|
4366
4497
|
isActive,
|
|
4498
|
+
onClick: () => setActiveChatView("threads"),
|
|
4367
4499
|
onPointerDown: () => setActiveChatView("threads"),
|
|
4500
|
+
tabIndex: 0,
|
|
4368
4501
|
text: t("Threads"),
|
|
4369
4502
|
children: /* @__PURE__ */ jsxRuntime.jsx(UnreadCountBadge, { count: unreadThreadCount, position: "top-right", children: isActive ? /* @__PURE__ */ jsxRuntime.jsx(IconThreadFill, {}) : /* @__PURE__ */ jsxRuntime.jsx(IconThread, {}) })
|
|
4370
4503
|
}
|
|
@@ -4383,7 +4516,18 @@ const defaultChatViewSelectorItemSet = [
|
|
|
4383
4516
|
const ChatViewSelector = ({
|
|
4384
4517
|
iconOnly = true,
|
|
4385
4518
|
itemSet = defaultChatViewSelectorItemSet
|
|
4386
|
-
}) =>
|
|
4519
|
+
}) => {
|
|
4520
|
+
const { t } = useTranslationContext();
|
|
4521
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4522
|
+
"div",
|
|
4523
|
+
{
|
|
4524
|
+
"aria-label": t("aria/Chat view tabs"),
|
|
4525
|
+
className: "str-chat__chat-view__selector",
|
|
4526
|
+
role: "tablist",
|
|
4527
|
+
children: itemSet.map(({ Component, type }) => /* @__PURE__ */ jsxRuntime.jsx(Component, { iconOnly }, type))
|
|
4528
|
+
}
|
|
4529
|
+
);
|
|
4530
|
+
};
|
|
4387
4531
|
ChatView.Channels = ChannelsView;
|
|
4388
4532
|
ChatView.Threads = ThreadsView;
|
|
4389
4533
|
ChatView.ThreadAdapter = ThreadAdapter;
|
|
@@ -4509,71 +4653,6 @@ const useNotificationApi = () => {
|
|
|
4509
4653
|
startNotificationTimeout
|
|
4510
4654
|
};
|
|
4511
4655
|
};
|
|
4512
|
-
const AudioPlayerContext = React.createContext({
|
|
4513
|
-
audioPlayers: null
|
|
4514
|
-
});
|
|
4515
|
-
const WithAudioPlayback = ({
|
|
4516
|
-
allowConcurrentPlayback,
|
|
4517
|
-
children
|
|
4518
|
-
}) => {
|
|
4519
|
-
const [audioPlayers] = React.useState(() => new AudioPlayerPool({ allowConcurrentPlayback }));
|
|
4520
|
-
React.useEffect(
|
|
4521
|
-
() => () => {
|
|
4522
|
-
audioPlayers.clear();
|
|
4523
|
-
},
|
|
4524
|
-
[audioPlayers]
|
|
4525
|
-
);
|
|
4526
|
-
return /* @__PURE__ */ jsxRuntime.jsx(AudioPlayerContext.Provider, { value: { audioPlayers }, children });
|
|
4527
|
-
};
|
|
4528
|
-
const makeAudioPlayerId = ({ requester, src }) => `${requester ?? "requester-unknown"}:${src}`;
|
|
4529
|
-
const useAudioPlayer = ({
|
|
4530
|
-
durationSeconds,
|
|
4531
|
-
fileSize,
|
|
4532
|
-
mimeType,
|
|
4533
|
-
playbackRates,
|
|
4534
|
-
plugins,
|
|
4535
|
-
requester = "",
|
|
4536
|
-
src,
|
|
4537
|
-
title,
|
|
4538
|
-
waveformData
|
|
4539
|
-
}) => {
|
|
4540
|
-
const { addNotification } = useNotificationApi();
|
|
4541
|
-
const panel = useNotificationTarget();
|
|
4542
|
-
const { t } = useTranslationContext();
|
|
4543
|
-
const { audioPlayers } = React.useContext(AudioPlayerContext);
|
|
4544
|
-
const audioPlayer = src && audioPlayers ? audioPlayers.getOrAdd({
|
|
4545
|
-
durationSeconds,
|
|
4546
|
-
fileSize,
|
|
4547
|
-
id: makeAudioPlayerId({ requester, src }),
|
|
4548
|
-
mimeType,
|
|
4549
|
-
playbackRates,
|
|
4550
|
-
plugins,
|
|
4551
|
-
src,
|
|
4552
|
-
title,
|
|
4553
|
-
waveformData
|
|
4554
|
-
}) : void 0;
|
|
4555
|
-
React.useEffect(() => {
|
|
4556
|
-
if (!audioPlayer) return;
|
|
4557
|
-
const notificationsPlugin = audioPlayerNotificationsPluginFactory({
|
|
4558
|
-
addNotification,
|
|
4559
|
-
panel,
|
|
4560
|
-
t
|
|
4561
|
-
});
|
|
4562
|
-
audioPlayer.setPlugins((currentPlugins) => [
|
|
4563
|
-
...currentPlugins.filter((plugin) => plugin.id !== notificationsPlugin.id),
|
|
4564
|
-
notificationsPlugin
|
|
4565
|
-
]);
|
|
4566
|
-
}, [addNotification, audioPlayer, panel, t]);
|
|
4567
|
-
return audioPlayer;
|
|
4568
|
-
};
|
|
4569
|
-
const activeAudioPlayerSelector = ({ activeAudioPlayer }) => ({
|
|
4570
|
-
activeAudioPlayer
|
|
4571
|
-
});
|
|
4572
|
-
const useActiveAudioPlayer = () => {
|
|
4573
|
-
const { audioPlayers } = React.useContext(AudioPlayerContext);
|
|
4574
|
-
const { activeAudioPlayer } = useStateStore(audioPlayers?.state, activeAudioPlayerSelector) ?? {};
|
|
4575
|
-
return activeAudioPlayer;
|
|
4576
|
-
};
|
|
4577
4656
|
exports.ACTIONS_NOT_WORKING_IN_THREAD = ACTIONS_NOT_WORKING_IN_THREAD;
|
|
4578
4657
|
exports.AudioPlayer = AudioPlayer;
|
|
4579
4658
|
exports.Button = Button;
|
|
@@ -4773,4 +4852,4 @@ exports.useThreadsViewContext = useThreadsViewContext;
|
|
|
4773
4852
|
exports.useTranslationContext = useTranslationContext;
|
|
4774
4853
|
exports.useTypingContext = useTypingContext;
|
|
4775
4854
|
exports.validateAndGetMessage = validateAndGetMessage;
|
|
4776
|
-
//# sourceMappingURL=
|
|
4855
|
+
//# sourceMappingURL=useNotificationApi.f2c7704d.js.map
|