stream-chat-react 14.10.0 → 14.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/README.md +20 -1
  2. package/dist/cjs/{useNotificationApi.bf76a16b.js → NotificationList.6abbee1c.js} +4935 -1232
  3. package/dist/cjs/NotificationList.6abbee1c.js.map +1 -0
  4. package/dist/cjs/{ReactPlayerWrapper.60a93742.js → ReactPlayerWrapper.a94a0cd1.js} +3 -3
  5. package/dist/cjs/{ReactPlayerWrapper.60a93742.js.map → ReactPlayerWrapper.a94a0cd1.js.map} +1 -1
  6. package/dist/cjs/channel-detail.js +263 -200
  7. package/dist/cjs/channel-detail.js.map +1 -1
  8. package/dist/cjs/emojis.js +31 -15
  9. package/dist/cjs/emojis.js.map +1 -1
  10. package/dist/cjs/index.js +2098 -7648
  11. package/dist/cjs/index.js.map +1 -1
  12. package/dist/cjs/useChannelHeaderOnlineStatus.7e17671e.js +961 -0
  13. package/dist/cjs/useChannelHeaderOnlineStatus.7e17671e.js.map +1 -0
  14. package/dist/cjs/useInertWhenHidden.22151beb.js +6426 -0
  15. package/dist/cjs/useInertWhenHidden.22151beb.js.map +1 -0
  16. package/dist/es/{useNotificationApi.ed6bff88.mjs → NotificationList.db01a56d.mjs} +4556 -1258
  17. package/dist/es/NotificationList.db01a56d.mjs.map +1 -0
  18. package/dist/es/channel-detail.mjs +86 -23
  19. package/dist/es/channel-detail.mjs.map +1 -1
  20. package/dist/es/emojis.mjs +25 -8
  21. package/dist/es/emojis.mjs.map +1 -1
  22. package/dist/es/index.mjs +1033 -6583
  23. package/dist/es/index.mjs.map +1 -1
  24. package/dist/es/useChannelHeaderOnlineStatus.a9357343.mjs +771 -0
  25. package/dist/es/useChannelHeaderOnlineStatus.a9357343.mjs.map +1 -0
  26. package/dist/es/useInertWhenHidden.3d5fbdba.mjs +5765 -0
  27. package/dist/es/useInertWhenHidden.3d5fbdba.mjs.map +1 -0
  28. package/dist/types/components/Attachment/Geolocation.d.ts.map +1 -1
  29. package/dist/types/components/Attachment/LinkPreview/Card.d.ts.map +1 -1
  30. package/dist/types/components/Attachment/LinkPreview/CardAudio.d.ts.map +1 -1
  31. package/dist/types/components/Attachment/ModalGallery.d.ts.map +1 -1
  32. package/dist/types/components/Attachment/UnsupportedAttachment.d.ts.map +1 -1
  33. package/dist/types/components/Attachment/VisibilityDisclaimer.d.ts.map +1 -1
  34. package/dist/types/components/Attachment/components/DownloadButton.d.ts.map +1 -1
  35. package/dist/types/components/Avatar/Avatar.d.ts +5 -1
  36. package/dist/types/components/Avatar/Avatar.d.ts.map +1 -1
  37. package/dist/types/components/Badge/Badge.d.ts.map +1 -1
  38. package/dist/types/components/Badge/MediaBadge.d.ts.map +1 -1
  39. package/dist/types/components/BaseImage/ImagePlaceholder.d.ts.map +1 -1
  40. package/dist/types/components/Button/PlayButton.d.ts.map +1 -1
  41. package/dist/types/components/Channel/Channel.d.ts.map +1 -1
  42. package/dist/types/components/ChannelListItem/ChannelListItem.d.ts.map +1 -1
  43. package/dist/types/components/ChannelListItem/ChannelListItemActionButtons.defaults.d.ts.map +1 -1
  44. package/dist/types/components/ChannelListItem/ChannelListItemUI.d.ts.map +1 -1
  45. package/dist/types/components/ChannelListItem/hooks/useMessageDeliveryStatus.d.ts.map +1 -1
  46. package/dist/types/components/ChatView/ChatView.d.ts.map +1 -1
  47. package/dist/types/components/Dialog/components/Callout.d.ts.map +1 -1
  48. package/dist/types/components/Dialog/components/ContextMenu.d.ts +4 -0
  49. package/dist/types/components/Dialog/components/ContextMenu.d.ts.map +1 -1
  50. package/dist/types/components/Dialog/components/Prompt.d.ts.map +1 -1
  51. package/dist/types/components/Dialog/components/Viewer.d.ts.map +1 -1
  52. package/dist/types/components/EmptyStateIndicator/EmptyStateIndicator.d.ts.map +1 -1
  53. package/dist/types/components/Form/NumericInput.d.ts.map +1 -1
  54. package/dist/types/components/Form/TextInput.d.ts.map +1 -1
  55. package/dist/types/components/Gallery/GalleryHeader.d.ts.map +1 -1
  56. package/dist/types/components/Gallery/GalleryUI.d.ts.map +1 -1
  57. package/dist/types/components/Icons/index.d.ts +1 -0
  58. package/dist/types/components/Icons/index.d.ts.map +1 -1
  59. package/dist/types/components/Icons/slots.d.ts +10 -0
  60. package/dist/types/components/Icons/slots.d.ts.map +1 -0
  61. package/dist/types/components/Loading/LoadingIndicator.d.ts +2 -2
  62. package/dist/types/components/Loading/LoadingIndicator.d.ts.map +1 -1
  63. package/dist/types/components/Location/ShareLocationDialog.d.ts.map +1 -1
  64. package/dist/types/components/MediaRecorder/AudioRecorder/AudioRecorderRecordingControls.d.ts.map +1 -1
  65. package/dist/types/components/MediaRecorder/AudioRecorder/AudioRecordingButtonWithNotification.d.ts.map +1 -1
  66. package/dist/types/components/MediaRecorder/AudioRecorder/AudioRecordingPlayback.d.ts.map +1 -1
  67. package/dist/types/components/MediaRecorder/AudioRecorder/AudioRecordingPreview.d.ts.map +1 -1
  68. package/dist/types/components/Message/MessageAlsoSentInChannelIndicator.d.ts.map +1 -1
  69. package/dist/types/components/Message/MessageDeletedBubble.d.ts.map +1 -1
  70. package/dist/types/components/Message/MessageStatus.d.ts.map +1 -1
  71. package/dist/types/components/Message/MessageTranslationIndicator.d.ts.map +1 -1
  72. package/dist/types/components/Message/PinIndicator.d.ts.map +1 -1
  73. package/dist/types/components/Message/ReminderNotification.d.ts.map +1 -1
  74. package/dist/types/components/MessageActions/DownloadSubmenu.d.ts.map +1 -1
  75. package/dist/types/components/MessageActions/MessageActions.defaults.d.ts.map +1 -1
  76. package/dist/types/components/MessageActions/RemindMeSubmenu.d.ts.map +1 -1
  77. package/dist/types/components/MessageBounce/MessageBouncePrompt.d.ts.map +1 -1
  78. package/dist/types/components/MessageComposer/AttachmentPreviewList/AudioAttachmentPreview.d.ts.map +1 -1
  79. package/dist/types/components/MessageComposer/AttachmentPreviewList/FileAttachmentPreview.d.ts.map +1 -1
  80. package/dist/types/components/MessageComposer/AttachmentPreviewList/GeolocationPreview.d.ts.map +1 -1
  81. package/dist/types/components/MessageComposer/AttachmentPreviewList/MediaAttachmentPreview.d.ts.map +1 -1
  82. package/dist/types/components/MessageComposer/AttachmentPreviewList/UnsupportedAttachmentPreview.d.ts.map +1 -1
  83. package/dist/types/components/MessageComposer/AttachmentSelector/AttachmentSelector.d.ts.map +1 -1
  84. package/dist/types/components/MessageComposer/AttachmentSelector/CommandsMenu.d.ts.map +1 -1
  85. package/dist/types/components/MessageComposer/CommandChip.d.ts.map +1 -1
  86. package/dist/types/components/MessageComposer/LinkPreviewList.d.ts.map +1 -1
  87. package/dist/types/components/MessageComposer/MessageComposer.d.ts +10 -1
  88. package/dist/types/components/MessageComposer/MessageComposer.d.ts.map +1 -1
  89. package/dist/types/components/MessageComposer/MessageComposerActions.d.ts.map +1 -1
  90. package/dist/types/components/MessageComposer/QuotedMessagePreview.d.ts.map +1 -1
  91. package/dist/types/components/MessageComposer/RemoveAttachmentPreviewButton.d.ts.map +1 -1
  92. package/dist/types/components/MessageComposer/SendButton.d.ts.map +1 -1
  93. package/dist/types/components/MessageComposer/SendToChannelCheckbox.d.ts.map +1 -1
  94. package/dist/types/components/MessageComposer/WithDragAndDropUpload.d.ts.map +1 -1
  95. package/dist/types/components/MessageComposer/hooks/useMessageComposerCommands.d.ts.map +1 -1
  96. package/dist/types/components/MessageComposer/hooks/useMessageComposerController.d.ts.map +1 -1
  97. package/dist/types/components/MessageList/ScrollToLatestMessageButton.d.ts.map +1 -1
  98. package/dist/types/components/MessageList/UnreadMessagesNotification.d.ts.map +1 -1
  99. package/dist/types/components/MessageList/UnreadMessagesSeparator.d.ts.map +1 -1
  100. package/dist/types/components/MessageList/hooks/useMarkRead.d.ts.map +1 -1
  101. package/dist/types/components/Modal/CloseButtonOnModalOverlay.d.ts.map +1 -1
  102. package/dist/types/components/Notifications/Notification.d.ts.map +1 -1
  103. package/dist/types/components/Poll/PollActions/PollResults/PollOptionWithVotesHeader.d.ts.map +1 -1
  104. package/dist/types/components/Poll/PollCreationDialog/OptionFieldSet.d.ts.map +1 -1
  105. package/dist/types/components/Poll/PollCreationDialog/PollCreationDialogControls.d.ts.map +1 -1
  106. package/dist/types/components/Poll/PollCreationDialog/PollOptionReorderHandle.d.ts.map +1 -1
  107. package/dist/types/components/Reactions/MessageReactionsDetail.d.ts.map +1 -1
  108. package/dist/types/components/Reactions/ReactionSelector.d.ts.map +1 -1
  109. package/dist/types/components/Reactions/ReactionSelectorWithButton.d.ts +6 -1
  110. package/dist/types/components/Reactions/ReactionSelectorWithButton.d.ts.map +1 -1
  111. package/dist/types/components/SummarizedMessagePreview/SummarizedMessagePreview.d.ts.map +1 -1
  112. package/dist/types/components/TextareaComposer/SuggestionList/MentionItem/BroadcastMentionItem.d.ts.map +1 -1
  113. package/dist/types/components/TextareaComposer/SuggestionList/MentionItem/RoleItem.d.ts.map +1 -1
  114. package/dist/types/components/TextareaComposer/SuggestionList/MentionItem/UserGroupItem.d.ts.map +1 -1
  115. package/dist/types/components/Thread/ThreadHeader.d.ts.map +1 -1
  116. package/dist/types/components/Threads/ThreadList/ThreadListEmptyPlaceholder.d.ts.map +1 -1
  117. package/dist/types/components/Threads/ThreadList/ThreadListUnseenThreadsBanner.d.ts.map +1 -1
  118. package/dist/types/components/VideoPlayer/VideoThumbnail.d.ts.map +1 -1
  119. package/dist/types/context/ComponentContext.d.ts +3 -0
  120. package/dist/types/context/ComponentContext.d.ts.map +1 -1
  121. package/dist/types/context/WithComponents.d.ts.map +1 -1
  122. package/dist/types/context/index.d.ts +1 -0
  123. package/dist/types/context/index.d.ts.map +1 -1
  124. package/dist/types/context/useComponentContextIcons.d.ts +16 -0
  125. package/dist/types/context/useComponentContextIcons.d.ts.map +1 -0
  126. package/dist/types/plugins/ChannelDetail/ChannelDetail.d.ts.map +1 -1
  127. package/dist/types/plugins/ChannelDetail/ChannelDetailEmptyList.d.ts.map +1 -1
  128. package/dist/types/plugins/ChannelDetail/ChannelDetailSearchInput.d.ts.map +1 -1
  129. package/dist/types/plugins/ChannelDetail/SectionNavigator/SectionNavigatorHeader.d.ts.map +1 -1
  130. package/dist/types/plugins/ChannelDetail/Views/ChannelFilesView/ChannelFilesEmptyList.d.ts.map +1 -1
  131. package/dist/types/plugins/ChannelDetail/Views/ChannelManagementView/ChannelManagementActions.defaults.d.ts.map +1 -1
  132. package/dist/types/plugins/ChannelDetail/Views/ChannelManagementView/ChannelManagementView.d.ts.map +1 -1
  133. package/dist/types/plugins/ChannelDetail/Views/ChannelMediaView/ChannelMediaEmptyList.d.ts.map +1 -1
  134. package/dist/types/plugins/ChannelDetail/Views/ChannelMediaView/ChannelMediaView.d.ts.map +1 -1
  135. package/dist/types/plugins/ChannelDetail/Views/ChannelMemberDetailView/ChannelMemberActions.defaults.d.ts.map +1 -1
  136. package/dist/types/plugins/ChannelDetail/Views/ChannelMembersView/ChannelMembersAddView.d.ts.map +1 -1
  137. package/dist/types/plugins/ChannelDetail/Views/ChannelMembersView/ChannelMembersBrowseView.d.ts.map +1 -1
  138. package/dist/types/plugins/ChannelDetail/Views/ChannelMembersView/ChannelMembersHeaderActions.defaults.d.ts.map +1 -1
  139. package/dist/types/plugins/ChannelDetail/Views/PinnedMessagesView/PinnedMessagesEmptyList.d.ts.map +1 -1
  140. package/dist/types/plugins/Emojis/EmojiPicker.d.ts +6 -1
  141. package/dist/types/plugins/Emojis/EmojiPicker.d.ts.map +1 -1
  142. package/dist/types/plugins/Emojis/Picker.d.ts +7 -0
  143. package/dist/types/plugins/Emojis/Picker.d.ts.map +1 -0
  144. package/dist/types/utils/getChannelConfig.d.ts +8 -0
  145. package/dist/types/utils/getChannelConfig.d.ts.map +1 -0
  146. package/package.json +3 -9
  147. package/AI.md +0 -423
  148. package/dist/cjs/useChannelHeaderOnlineStatus.6ace991c.js +0 -4485
  149. package/dist/cjs/useChannelHeaderOnlineStatus.6ace991c.js.map +0 -1
  150. package/dist/cjs/useMessageComposerController.f8f20e3d.js +0 -99
  151. package/dist/cjs/useMessageComposerController.f8f20e3d.js.map +0 -1
  152. package/dist/cjs/useNotificationApi.bf76a16b.js.map +0 -1
  153. package/dist/es/useChannelHeaderOnlineStatus.d6065c22.mjs +0 -3899
  154. package/dist/es/useChannelHeaderOnlineStatus.d6065c22.mjs.map +0 -1
  155. package/dist/es/useMessageComposerController.d50f6168.mjs +0 -69
  156. package/dist/es/useMessageComposerController.d50f6168.mjs.map +0 -1
  157. package/dist/es/useNotificationApi.ed6bff88.mjs.map +0 -1
@@ -0,0 +1,961 @@
1
+ const require_NotificationList = require("./NotificationList.6abbee1c.js");
2
+ let react = require("react");
3
+ react = require_NotificationList.__toESM(react);
4
+ let react_jsx_runtime = require("react/jsx-runtime");
5
+ let clsx = require("clsx");
6
+ clsx = require_NotificationList.__toESM(clsx);
7
+ let use_sync_external_store_shim = require("use-sync-external-store/shim");
8
+ let unist_util_visit = require("unist-util-visit");
9
+ let react_markdown = require("react-markdown");
10
+ react_markdown = require_NotificationList.__toESM(react_markdown);
11
+ let remark_gfm = require("remark-gfm");
12
+ remark_gfm = require_NotificationList.__toESM(remark_gfm);
13
+ let mdast_util_to_string = require("mdast-util-to-string");
14
+ let remark_parse = require("remark-parse");
15
+ remark_parse = require_NotificationList.__toESM(remark_parse);
16
+ let unified = require("unified");
17
+ //#region src/context/MessageTranslationViewContext.tsx
18
+ /**
19
+ * Message translation view context: user-specific state for whether each message
20
+ * shows original text or a translation.
21
+ *
22
+ * ## Spec
23
+ *
24
+ * - **State**: Per message list (channel vs thread), we store a map
25
+ * `messageId → 'original' | 'translated'`. Default for messages with `message.i18n`
26
+ * is `'translated'`; otherwise `'original'`.
27
+ *
28
+ * - **Provider placement**: The provider is tied to the **message list**, not the channel.
29
+ * It is rendered inside `MessageList` and `VirtualizedMessageList`. That way the
30
+ * main channel list and the thread list each have their own translation view state
31
+ * (e.g. Thread.tsx gets correct behavior without sharing channel state).
32
+ *
33
+ * - **Multiple translations**: `message.i18n` can contain multiple languages, e.g.:
34
+ * `{ en_text: "Good morning", fr_text: "Bonjour", it_text: "Buongiorno", language: "en" }`.
35
+ * Which translation is shown is determined by the app’s **user language**
36
+ * (`useTranslationContext().userLanguage`). We use `message.i18n[userLanguage + '_text']`;
37
+ * if missing, we fall back to `message.text`. Only one translation is shown at a time.
38
+ *
39
+ * - **Source language**: When present, `message.i18n.language` is the original/source
40
+ * language of `message.text`. It can be used for the indicator label, e.g.
41
+ * "Translated from English · View original".
42
+ *
43
+ * - **Invariants**: The original message content, layout, grouping, and order stay
44
+ * unchanged. Removing or toggling translation only changes the annotation and which
45
+ * text is displayed. "View original" / "View translation" switch the displayed
46
+ * text and update the annotation (e.g. "Original · View translation" when showing
47
+ * original).
48
+ *
49
+ * - **Translation indicator visibility**: The translation indicator (e.g. "Translated ·
50
+ * View original") is **not** shown when the currently viewed text already corresponds
51
+ * to `userLanguage` — for example when viewing original and the original text is the
52
+ * user-language version (i.e. `getTranslatedMessageText({ language: userLanguage, message })`
53
+ * equals `message.text`). In that case there is no meaningful original/translated choice,
54
+ * so the indicator is hidden.
55
+ */
56
+ /**
57
+ * Returns the translated message text for a given language from `message.i18n`, or
58
+ * undefined if not present. Used to resolve which of the multiple translations to show.
59
+ */
60
+ var getTranslatedMessageText = ({ language, message }) => message?.i18n?.[`${language}_text`];
61
+ var defaultContextValue = {
62
+ getTranslationView: (_messageId, hasI18n) => hasI18n ? "translated" : "original",
63
+ setTranslationView: () => {}
64
+ };
65
+ var MessageTranslationViewContext = (0, react.createContext)(defaultContextValue);
66
+ var MessageTranslationViewProvider = ({ children }) => {
67
+ const [viewByMessageId, setViewByMessageId] = (0, react.useState)({});
68
+ const setTranslationView = (0, react.useCallback)((messageId, view) => {
69
+ setViewByMessageId((prev) => ({
70
+ ...prev,
71
+ [messageId]: view
72
+ }));
73
+ }, []);
74
+ const getTranslationView = (0, react.useCallback)((messageId, hasI18n) => viewByMessageId[messageId] ?? (hasI18n ? "translated" : "original"), [viewByMessageId]);
75
+ const stableValue = react.default.useMemo(() => ({
76
+ getTranslationView,
77
+ setTranslationView
78
+ }), [getTranslationView, setTranslationView]);
79
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MessageTranslationViewContext.Provider, {
80
+ value: stableValue,
81
+ children
82
+ });
83
+ };
84
+ var useMessageTranslationViewContext = () => {
85
+ return (0, react.useContext)(MessageTranslationViewContext) ?? defaultContextValue;
86
+ };
87
+ //#endregion
88
+ //#region src/utils/useStableCallback.ts
89
+ /**
90
+ * A utility hook implementing a stable callback. It takes in an unstable method that
91
+ * is supposed to be invoked somewhere deeper in the DOM tree without making it
92
+ * change its reference every time the parent component rerenders. It will also return
93
+ * the value of the callback if it does return one.
94
+ * A common use-case would be having a function whose invocation depends on state
95
+ * somewhere high up in the DOM tree and wanting to use the same function deeper
96
+ * down, for example in a leaf node and simply using useCallback results in
97
+ * cascading dependency hell. If we wrap it in useStableCallback, we would be able
98
+ * to:
99
+ * - Use the same function as a dependency of another hook (since it is stable)
100
+ * - Still invoke it and get the latest state
101
+ *
102
+ * **Caveats:**
103
+ * - Never wrap a function that is supposed to return a React.ReactElement in
104
+ * useStableCallback, since React will not know that the DOM needs to be updated
105
+ * whenever the callback value changes (for example, renderItem from FlatList must
106
+ * never be wrapped in this hook)
107
+ * - Always prefer using a standard useCallback/stable function wherever possible
108
+ * (the purpose of useStableCallback is to bridge the gap between top level contexts
109
+ * and cascading rereders in downstream components - **not** as an escape hatch)
110
+ * @param callback - the callback we want to stabilize
111
+ */
112
+ var useStableCallback = (callback) => {
113
+ const ref = (0, react.useRef)(callback);
114
+ ref.current = callback;
115
+ return (0, react.useCallback)((...args) => ref.current(...args), []);
116
+ };
117
+ //#endregion
118
+ //#region src/components/Dialog/components/Alert.tsx
119
+ var Root = (0, react.forwardRef)(function AlertRoot({ children, className, ...props }, ref) {
120
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
121
+ ...props,
122
+ className: (0, clsx.default)("str-chat__alert-root", className),
123
+ ref,
124
+ children
125
+ });
126
+ });
127
+ var Header = (0, react.forwardRef)(function AlertHeader({ children, className, description, descriptionId, Icon, title, titleId, ...props }, ref) {
128
+ const { dialogId } = require_NotificationList.useModalContext();
129
+ const { descriptionId: derivedDescriptionId, titleId: derivedTitleId } = require_NotificationList.useAriaIdentifiers(dialogId);
130
+ const resolvedTitleId = titleId ?? derivedTitleId;
131
+ const resolvedDescriptionId = descriptionId ?? derivedDescriptionId;
132
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
133
+ ...props,
134
+ className: (0, clsx.default)("str-chat__alert-header", className),
135
+ ref,
136
+ children: title ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [Icon && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, {}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
137
+ className: "str-chat__alert-header__copy",
138
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
139
+ className: "str-chat__alert-header__title",
140
+ id: resolvedTitleId,
141
+ children: title
142
+ }), description && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
143
+ className: "str-chat__alert-header__description",
144
+ id: resolvedDescriptionId,
145
+ children: description
146
+ })]
147
+ })] }) : children
148
+ });
149
+ });
150
+ var Alert = {
151
+ Actions: (0, react.forwardRef)(function AlertActions({ children, className, ...props }, ref) {
152
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
153
+ ...props,
154
+ className: (0, clsx.default)("str-chat__alert-actions", className),
155
+ ref,
156
+ children
157
+ });
158
+ }),
159
+ Header,
160
+ Root
161
+ };
162
+ //#endregion
163
+ //#region src/components/Badge/Badge.tsx
164
+ /**
165
+ * Compact pill/circle badge for counts and labels.
166
+ * Uses design tokens: --badge-bg-*, --badge-text-*, --badge-border.
167
+ */
168
+ var Badge = ({ children, className, size = "md", variant = "default", ...spanProps }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
169
+ ...spanProps,
170
+ className: (0, clsx.default)("str-chat__badge", `str-chat__badge--variant-${variant}`, { [`str-chat__badge--size-${size}`]: size }, className),
171
+ children
172
+ });
173
+ var ErrorBadge = ({ className, size = "sm", ...rest }) => {
174
+ const { IconExclamationMarkFill } = require_NotificationList.useComponentContextIcons();
175
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Badge, {
176
+ ...rest,
177
+ className,
178
+ size,
179
+ variant: "error",
180
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconExclamationMarkFill, {})
181
+ });
182
+ };
183
+ //#endregion
184
+ //#region src/components/Avatar/ChannelAvatar.tsx
185
+ var ChannelAvatar = ({ displayMembers, imageUrl, size, userName, ...sharedProps }) => {
186
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GroupAvatar, {
187
+ displayMembers: (0, react.useMemo)(() => {
188
+ if (!imageUrl && displayMembers && displayMembers.length > 0) return displayMembers;
189
+ return [{
190
+ imageUrl,
191
+ userName
192
+ }];
193
+ }, [
194
+ displayMembers,
195
+ imageUrl,
196
+ userName
197
+ ]),
198
+ size,
199
+ ...sharedProps
200
+ });
201
+ };
202
+ //#endregion
203
+ //#region src/components/Avatar/GroupAvatar.tsx
204
+ /**
205
+ * Avatar component to display multiple users' avatars in a group.
206
+ * Renders a single Avatar if fewer than 2 members. Otherwise, renders up to 2 avatars (when overflowCount is set) or 4, plus an optional +N badge.
207
+ */
208
+ var GroupAvatar = ({ badgeSize, className, displayMembers = [], isOnline, size, ...rest }) => {
209
+ const displayMembersToRender = (0, react.useMemo)(() => displayMembers.length > 4 ? displayMembers.slice(0, 2) : displayMembers, [displayMembers]);
210
+ const overflowCount = displayMembers.length - displayMembersToRender.length;
211
+ if (displayMembers.length < 2) {
212
+ const firstUser = displayMembers[0];
213
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_NotificationList.Avatar, {
214
+ imageUrl: firstUser?.imageUrl,
215
+ isOnline,
216
+ size,
217
+ userName: firstUser?.userName,
218
+ ...rest
219
+ });
220
+ }
221
+ let avatarSize = null;
222
+ if (size === "2xl") avatarSize = "lg";
223
+ else if (size === "xl") avatarSize = "md";
224
+ else if (size === "lg") avatarSize = "sm";
225
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
226
+ className: (0, clsx.default)("str-chat__avatar-group", {
227
+ "str-chat__avatar-group--offline": typeof isOnline === "boolean" && !isOnline,
228
+ "str-chat__avatar-group--online": typeof isOnline === "boolean" && isOnline,
229
+ [`str-chat__avatar-group--size-${size}`]: typeof size === "string"
230
+ }, className),
231
+ "data-testid": "group-avatar",
232
+ role: "button",
233
+ ...rest,
234
+ children: [displayMembersToRender.map(({ id, imageUrl, userName }, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_NotificationList.Avatar, {
235
+ imageUrl,
236
+ size: avatarSize,
237
+ userName
238
+ }, id || `${userName}-${imageUrl}-${index}`)), typeof overflowCount === "number" && overflowCount > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Badge, {
239
+ className: "str-chat__avatar-group__count-badge",
240
+ "data-testid": "group-avatar-count-badge",
241
+ size: badgeSize,
242
+ variant: "counter",
243
+ children: ["+", overflowCount]
244
+ })]
245
+ });
246
+ };
247
+ //#endregion
248
+ //#region src/components/Message/renderText/remarkPlugins/htmlToTextPlugin.ts
249
+ var visitor = (node) => {
250
+ if (node.type !== "html") return;
251
+ node.type = "text";
252
+ };
253
+ var transform = (tree) => {
254
+ (0, unist_util_visit.visit)(tree, visitor);
255
+ };
256
+ var htmlToTextPlugin = () => transform;
257
+ //#endregion
258
+ //#region src/components/Message/renderText/remarkPlugins/imageToLink.ts
259
+ var text = (value) => ({
260
+ type: "text",
261
+ value
262
+ });
263
+ /**
264
+ * Converts image Markdown links (![Minion](https://octodex.github.com/images/minion.png))
265
+ * to HTML <a href={url}>{url | title | alt}</a>
266
+ *
267
+ * By default, the anchor text content is the image url so that image preview can be generated / enriched on the server.
268
+ * @param getTextLabelFrom
269
+ */
270
+ function imageToLink({ getTextLabelFrom = "url" } = {}) {
271
+ return (tree) => {
272
+ const visitor = (node, index, parent) => {
273
+ if (parent == null || index == null) return;
274
+ const link = {
275
+ children: [text(node[getTextLabelFrom] ?? node.url)],
276
+ title: node.title ?? node.alt ?? node.url,
277
+ type: "link",
278
+ url: node.url
279
+ };
280
+ parent.children.splice(index, 1, link);
281
+ return [unist_util_visit.SKIP, index + 1];
282
+ };
283
+ (0, unist_util_visit.visit)(tree, "image", visitor);
284
+ };
285
+ }
286
+ //#endregion
287
+ //#region src/components/Message/renderText/remarkPlugins/plusPlusToEmphasis.ts
288
+ /**
289
+ * \S → first char must be non-whitespace
290
+ * (?:...)?→ optional middle+closing when length > 1
291
+ * [\s\S]*?→ anything (including newlines), lazy
292
+ * final \S→ last char non-whitespace (only required when there’s more than 1)
293
+ *
294
+ * Matches:
295
+ * ++a++
296
+ * Does not match:
297
+ * ++++
298
+ * ++ ++
299
+ */
300
+ var INS_REGEX = /\+\+(\S(?:[\s\S]*?\S)?)\+\+/g;
301
+ var IGNORE_NODE_TYPES = /* @__PURE__ */ new Set([
302
+ "code",
303
+ "inlineCode",
304
+ "link",
305
+ "linkReference",
306
+ "definition",
307
+ "math",
308
+ "inlineMath"
309
+ ]);
310
+ /**
311
+ * Converts MD "++Some text++" to inserted text element rendered in HTML as <ins>Some text</ins>
312
+ * https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/ins
313
+ */
314
+ var plusPlusToEmphasis = () => {
315
+ const visitor = (node, index, parent) => {
316
+ if (IGNORE_NODE_TYPES.has(node.type)) return unist_util_visit.SKIP;
317
+ if (node.type !== "text" || parent == null || typeof index !== "number") return;
318
+ const value = node.value;
319
+ INS_REGEX.lastIndex = 0;
320
+ let match;
321
+ let last = 0;
322
+ const out = [];
323
+ while (match = INS_REGEX.exec(value)) {
324
+ const [full, inner] = match;
325
+ const start = match.index;
326
+ if (start > last) out.push({
327
+ type: "text",
328
+ value: value.slice(last, start)
329
+ });
330
+ out.push({
331
+ children: [{
332
+ type: "text",
333
+ value: inner
334
+ }],
335
+ data: { hName: "ins" },
336
+ type: "emphasis"
337
+ });
338
+ last = start + full.length;
339
+ }
340
+ if (out.length === 0) return;
341
+ if (last < value.length) out.push({
342
+ type: "text",
343
+ value: value.slice(last)
344
+ });
345
+ parent.children.splice(index, 1, ...out);
346
+ return [unist_util_visit.SKIP, index + out.length];
347
+ };
348
+ return (tree) => (0, unist_util_visit.visit)(tree, visitor);
349
+ };
350
+ //#endregion
351
+ //#region src/components/Form/Checkbox.tsx
352
+ var Checkbox = ({ checked, ...props }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
353
+ ...props,
354
+ className: (0, clsx.default)("str-chat__checkmark str-chat__checkbox", {
355
+ "str-chat__checkbox--checked": checked,
356
+ "str-chat__checkmark--checked": checked
357
+ })
358
+ });
359
+ var Checkmark = Checkbox;
360
+ //#endregion
361
+ //#region src/components/ChannelListItem/utils.tsx
362
+ var remarkPlugins = [
363
+ htmlToTextPlugin,
364
+ [remark_gfm.default, { singleTilde: false }],
365
+ plusPlusToEmphasis,
366
+ imageToLink
367
+ ];
368
+ var renderPreviewText = (text) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_markdown.default, {
369
+ remarkPlugins,
370
+ skipHtml: true,
371
+ children: text
372
+ });
373
+ var createPlainTextProcessor = () => (0, unified.unified)().use(remark_parse.default).use(remarkPlugins);
374
+ var plainTextProcessor;
375
+ var stripMarkdownToText = (text) => {
376
+ try {
377
+ const processor = plainTextProcessor ?? (plainTextProcessor = createPlainTextProcessor());
378
+ return (0, mdast_util_to_string.toString)(processor.runSync(processor.parse(text))) || text;
379
+ } catch {
380
+ return text;
381
+ }
382
+ };
383
+ var getLatestPollVote = (latestVotesByOption) => {
384
+ let latestVote;
385
+ for (const optionVotes of Object.values(latestVotesByOption)) optionVotes.forEach((vote) => {
386
+ if (latestVote && new Date(latestVote.updated_at) >= new Date(vote.created_at)) return;
387
+ latestVote = vote;
388
+ });
389
+ return latestVote;
390
+ };
391
+ /**
392
+ * Resolves the channel's latest-message preview once: the localized DISPLAY string, a `kind`
393
+ * discriminant, and the bits announcements need (poll question, attachment type). Single source of
394
+ * truth for the display variant ({@link getLatestMessagePreview}) and the announcement variant
395
+ * ({@link getLatestMessagePreviewText}), so the translation lookup and branching run once per call.
396
+ */
397
+ var getLatestMessagePreviewParts = (channel, t, userLanguage = "en", latestMessageArg) => {
398
+ const latestMessage = latestMessageArg ?? channel.state.latestMessages[channel.state.latestMessages.length - 1];
399
+ const previewTextToRender = getTranslatedMessageText({
400
+ language: userLanguage,
401
+ message: latestMessage
402
+ }) || latestMessage?.text;
403
+ const poll = latestMessage?.poll;
404
+ if (!latestMessage) return {
405
+ isUserMessageText: false,
406
+ kind: "empty",
407
+ latestMessage,
408
+ text: t("Nothing yet...")
409
+ };
410
+ if (require_NotificationList.isMessageDeleted(latestMessage)) return {
411
+ isUserMessageText: false,
412
+ kind: "deleted",
413
+ latestMessage,
414
+ text: t("Message deleted")
415
+ };
416
+ if (poll) if (!poll.vote_count) {
417
+ const createdBy = poll.created_by?.id === channel.getClient().userID ? t("You") : poll.created_by?.name ?? t("Poll");
418
+ return {
419
+ isUserMessageText: false,
420
+ kind: "poll",
421
+ latestMessage,
422
+ pollName: poll.name,
423
+ text: t("📊 {{createdBy}} created: {{ pollName}}", {
424
+ createdBy,
425
+ pollName: poll.name
426
+ })
427
+ };
428
+ } else {
429
+ const latestVote = getLatestPollVote(poll.latest_votes_by_option);
430
+ const option = latestVote && poll.options.find((opt) => opt.id === latestVote.option_id);
431
+ if (option && latestVote) return {
432
+ isUserMessageText: false,
433
+ kind: "poll",
434
+ latestMessage,
435
+ pollName: poll.name,
436
+ text: t("📊 {{votedBy}} voted: {{pollOptionText}}", {
437
+ pollOptionText: option.text,
438
+ votedBy: latestVote?.user?.id === channel.getClient().userID ? t("You") : latestVote.user?.name ?? t("Poll")
439
+ })
440
+ };
441
+ }
442
+ if (previewTextToRender) return {
443
+ isUserMessageText: true,
444
+ kind: "text",
445
+ latestMessage,
446
+ text: previewTextToRender
447
+ };
448
+ if (latestMessage.command) return {
449
+ isUserMessageText: false,
450
+ kind: "command",
451
+ latestMessage,
452
+ text: `/${latestMessage.command}`
453
+ };
454
+ if (latestMessage.attachments?.length) return {
455
+ isUserMessageText: false,
456
+ kind: "attachment",
457
+ latestMessage,
458
+ text: t("🏙 Attachment...")
459
+ };
460
+ if (latestMessage.shared_location) return {
461
+ isUserMessageText: false,
462
+ kind: "location",
463
+ latestMessage,
464
+ text: t("📍Shared location")
465
+ };
466
+ return {
467
+ isUserMessageText: false,
468
+ kind: "text",
469
+ latestMessage,
470
+ text: t("Empty message...")
471
+ };
472
+ };
473
+ /**
474
+ * Maps a known attachment `type` to a localized, human-readable word (e.g. "image" → "Image"). The
475
+ * cases are literal `t('aria/…')` calls so `i18next-cli` extracts them. Unknown/custom types return
476
+ * `undefined`, so the announcement falls back to a generic "Attachment".
477
+ */
478
+ var getAttachmentTypeLabel = (type, t) => {
479
+ switch (type) {
480
+ case "audio": return t("aria/audio");
481
+ case "file": return t("aria/file");
482
+ case "giphy": return t("aria/GIF");
483
+ case "image": return t("aria/image");
484
+ case "video": return t("aria/video");
485
+ case "voiceRecording": return t("aria/voice message");
486
+ default: return;
487
+ }
488
+ };
489
+ /**
490
+ * The text announced for the channel's latest message (for an accessible name / live region).
491
+ * Non-text content gets a concise, screen-reader-friendly phrasing that may differ from the visible
492
+ * preview: a poll announces its question, an attachment its type, a shared location and a deleted
493
+ * message a plain phrase. User-message text is stripped of markdown so the words are read, not the
494
+ * syntax (AI-generated text is returned verbatim, matching the display path).
495
+ */
496
+ var getLatestMessagePreviewText = (channel, t, userLanguage = "en", isMessageAIGenerated, latestMessage) => {
497
+ const { isUserMessageText, kind, latestMessage: resolvedLatestMessage, pollName, text } = getLatestMessagePreviewParts(channel, t, userLanguage, latestMessage);
498
+ switch (kind) {
499
+ case "poll": return t("aria/Poll: {{ pollName }}", { pollName: pollName ?? "" });
500
+ case "attachment": {
501
+ const realAttachments = resolvedLatestMessage?.attachments?.filter((attachment) => !attachment.og_scrape_url) ?? [];
502
+ if (realAttachments.length > 1) return t("aria/Message with attachments");
503
+ const typeLabel = getAttachmentTypeLabel(realAttachments[0]?.type, t);
504
+ return typeLabel ? t("aria/Attachment {{ attachmentType }}", { attachmentType: typeLabel }) : t("aria/Attachment");
505
+ }
506
+ case "location": return t("aria/Shared location");
507
+ case "empty": return t("aria/There are no messages in this chat.");
508
+ case "text": return isUserMessageText && resolvedLatestMessage && !isMessageAIGenerated?.(resolvedLatestMessage) ? stripMarkdownToText(text) : text;
509
+ default: return text;
510
+ }
511
+ };
512
+ var getLatestMessagePreview = (channel, t, userLanguage = "en", isMessageAIGenerated, latestMessage) => {
513
+ const { isUserMessageText, latestMessage: resolvedLatestMessage, text } = getLatestMessagePreviewParts(channel, t, userLanguage, latestMessage);
514
+ return isUserMessageText && resolvedLatestMessage && !isMessageAIGenerated?.(resolvedLatestMessage) ? renderPreviewText(text) : text;
515
+ };
516
+ /**
517
+ * Channel display image: channel.data.image, or for DM (2 members) the other member's user.image.
518
+ */
519
+ var getChannelDisplayImage = (channel, currentUserId) => {
520
+ const data = channel.data;
521
+ if (data?.image && typeof data.image === "string") return data.image;
522
+ const memberList = Object.values(channel.state.members);
523
+ if (memberList.length === 2) {
524
+ const image = memberList.find((m) => m.user?.id !== currentUserId)?.user?.image;
525
+ if (image && typeof image === "string") return image;
526
+ }
527
+ };
528
+ var getGroupChannelDisplayInfo = (channel) => {
529
+ const members = Object.values(channel.state.members);
530
+ if (members.length <= 2) return;
531
+ const memberList = [];
532
+ for (const member of members) {
533
+ const { user } = member;
534
+ if (!user?.name && !user?.image) continue;
535
+ memberList.push(require_NotificationList.extractDisplayInfo(member));
536
+ }
537
+ return { members: memberList };
538
+ };
539
+ //#endregion
540
+ //#region src/components/ChannelListItem/hooks/useChannelDisplayName.ts
541
+ /**
542
+ * 1. channel.data.name
543
+ * 2. DM (exactly 2 members): other member's name, then directMessageLabel
544
+ * 3. Group (3+ members): comma-separated list of 2 other members' names (no ellipsis)
545
+ * 4. undefined otherwise
546
+ */
547
+ function computeChannelDisplayName(channel, directMessageLabel, currentUserId) {
548
+ const data = channel.data;
549
+ if (data?.name && typeof data.name === "string") return data.name;
550
+ const memberList = Object.values(channel.state.members);
551
+ const otherMembers = memberList.filter((m) => m.user?.id !== currentUserId);
552
+ if (memberList.length === 2 && otherMembers.length === 1) return otherMembers[0].user?.name || directMessageLabel;
553
+ if (otherMembers.length >= 2) {
554
+ const names = otherMembers.map((m) => m.user?.name).filter(Boolean).slice(0, 2);
555
+ if (names.length > 0) return names.join(", ");
556
+ }
557
+ }
558
+ /**
559
+ * Channel display name with translation context.
560
+ * 1. channel.data.name
561
+ * 2. DM (exactly 2 members): other member's name, then translated "Direct message"
562
+ * 3. Group (3+ members): comma-separated list of 2 other members' names (no ellipsis)
563
+ * 4. undefined otherwise
564
+ */
565
+ var useChannelDisplayName = (channel) => {
566
+ const { client } = require_NotificationList.useChatContext("useChannelDisplayName");
567
+ const { t } = require_NotificationList.useTranslationContext("useChannelDisplayName");
568
+ const directMessageLabel = t("Direct message");
569
+ const [displayName, setDisplayName] = (0, react.useState)(() => channel ? computeChannelDisplayName(channel, directMessageLabel, client.userID ?? void 0) : void 0);
570
+ (0, react.useEffect)(() => {
571
+ if (!channel) {
572
+ setDisplayName(void 0);
573
+ return;
574
+ }
575
+ const updateDisplayName = () => setDisplayName(computeChannelDisplayName(channel, directMessageLabel, client.userID ?? void 0));
576
+ updateDisplayName();
577
+ client.on("user.updated", updateDisplayName);
578
+ return () => {
579
+ client.off("user.updated", updateDisplayName);
580
+ };
581
+ }, [
582
+ channel,
583
+ channel?.data,
584
+ client,
585
+ directMessageLabel
586
+ ]);
587
+ return displayName;
588
+ };
589
+ //#endregion
590
+ //#region src/components/ChannelListItem/hooks/useChannelPreviewInfo.ts
591
+ var emptyGroupInfo = {
592
+ members: [],
593
+ overflowCount: void 0
594
+ };
595
+ var useChannelPreviewInfo = (props) => {
596
+ const { channel, overrideImage, overrideTitle } = props;
597
+ const { client } = require_NotificationList.useChatContext();
598
+ const channelDisplayName = useChannelDisplayName(channel);
599
+ const displayTitle = overrideTitle ?? channelDisplayName;
600
+ const [displayImage, setDisplayImage] = (0, react.useState)(() => channel ? overrideImage ?? getChannelDisplayImage(channel, client.userID ?? void 0) : void 0);
601
+ const [groupChannelDisplayInfo, setGroupChannelDisplayInfo] = (0, react.useState)(() => channel ? getGroupChannelDisplayInfo(channel) ?? emptyGroupInfo : emptyGroupInfo);
602
+ (0, react.useEffect)(() => {
603
+ if (!channel) return;
604
+ if (overrideImage) return;
605
+ const updateInfo = () => {
606
+ setDisplayImage(getChannelDisplayImage(channel, client.userID ?? void 0));
607
+ setGroupChannelDisplayInfo(getGroupChannelDisplayInfo(channel) ?? emptyGroupInfo);
608
+ };
609
+ updateInfo();
610
+ const { unsubscribe: unsubscribeChannelUpdated } = channel.on("channel.updated", updateInfo);
611
+ const { unsubscribe: unsubscribeUserUpdated } = client.on("user.updated", updateInfo);
612
+ return () => {
613
+ unsubscribeChannelUpdated();
614
+ unsubscribeUserUpdated();
615
+ };
616
+ }, [
617
+ channel,
618
+ channel?.data,
619
+ client,
620
+ overrideImage
621
+ ]);
622
+ return (0, react.useMemo)(() => ({
623
+ displayImage: overrideImage ?? displayImage,
624
+ displayTitle,
625
+ groupChannelDisplayInfo
626
+ }), [
627
+ displayImage,
628
+ displayTitle,
629
+ groupChannelDisplayInfo,
630
+ overrideImage
631
+ ]);
632
+ };
633
+ //#endregion
634
+ //#region src/utils/isDmChannel.ts
635
+ var isDmChannel = ({ channel, ownUserId }) => {
636
+ const memberCount = channel.data?.member_count ?? 0;
637
+ return memberCount === 1 || memberCount === 2 && !!ownUserId && Object.values(channel.state?.members ?? {}).some(({ user }) => user?.id === ownUserId);
638
+ };
639
+ //#endregion
640
+ //#region src/components/ChannelList/hooks/useSelectedChannelState.ts
641
+ var noop = () => {};
642
+ function useSelectedChannelState({ channel, selector, stateChangeEventKeys = ["all"] }) {
643
+ return (0, use_sync_external_store_shim.useSyncExternalStore)((0, react.useCallback)((onStoreChange) => {
644
+ if (!channel) return noop;
645
+ const subscriptions = stateChangeEventKeys.map((et) => channel.on(et, () => {
646
+ onStoreChange(selector(channel));
647
+ }));
648
+ return () => subscriptions.forEach((subscription) => subscription.unsubscribe());
649
+ }, [
650
+ channel,
651
+ selector,
652
+ stateChangeEventKeys
653
+ ]), (0, react.useCallback)(() => {
654
+ if (!channel) return void 0;
655
+ return selector(channel);
656
+ }, [channel, selector]));
657
+ }
658
+ //#endregion
659
+ //#region src/components/ChannelList/hooks/useChannelMembershipState.ts
660
+ var selector = (c) => c.state.membership;
661
+ var keys = ["member.updated"];
662
+ function useChannelMembershipState(channel) {
663
+ return useSelectedChannelState({
664
+ channel,
665
+ selector,
666
+ stateChangeEventKeys: keys
667
+ });
668
+ }
669
+ //#endregion
670
+ //#region src/components/ChannelListItem/hooks/useIsChannelMuted.ts
671
+ /**
672
+ * `channel.muteStatus()` throws in two cases:
673
+ * - the channel has not been initialized yet (i.e. `.watch()`/`.query()` has not
674
+ * resolved) - the ChannelList can briefly hold such channels, e.g. a
675
+ * `message.new` for a channel that has not been watched yet (#2474);
676
+ * - the channel is disconnected (e.g. after `client.disconnectUser()`), in which
677
+ * case `channel.getClient()` throws even though the channel stays initialized
678
+ * (#2393 failure class).
679
+ * Guard against both to avoid crashing the whole app.
680
+ */
681
+ var getMuteStatus = (channel) => channel.initialized && !channel.disconnected ? channel.muteStatus() : {
682
+ createdAt: null,
683
+ expiresAt: null,
684
+ muted: false
685
+ };
686
+ var useIsChannelMuted = (channel) => {
687
+ const { client } = require_NotificationList.useChatContext("useIsChannelMuted");
688
+ const [muted, setMuted] = (0, react.useState)(() => getMuteStatus(channel));
689
+ (0, react.useEffect)(() => {
690
+ const handleEvent = () => {
691
+ setMuted(getMuteStatus(channel));
692
+ };
693
+ return client.on("notification.channel_mutes_updated", handleEvent).unsubscribe;
694
+ }, [channel, client]);
695
+ return muted;
696
+ };
697
+ //#endregion
698
+ //#region src/components/ChannelListItem/hooks/useIsUserMuted.ts
699
+ var useIsUserMuted = (targetUserId) => {
700
+ const { mutes } = require_NotificationList.useChatContext();
701
+ return (0, react.useMemo)(() => !!targetUserId && mutes.some((mute) => mute.target.id === targetUserId), [mutes, targetUserId]);
702
+ };
703
+ //#endregion
704
+ //#region src/components/ChannelHeader/hooks/useChannelHasMembersOnline.ts
705
+ var getOtherWatchers = (watchers, ownUserId) => {
706
+ const next = Object.assign({}, watchers ?? {});
707
+ if (ownUserId) delete next[ownUserId];
708
+ return next;
709
+ };
710
+ var useChannelHasMembersOnline = ({ channel: channelOverride, enabled = true } = {}) => {
711
+ const { channel: contextChannel } = require_NotificationList.useChannelStateContext();
712
+ const { client } = require_NotificationList.useChatContext();
713
+ const channel = channelOverride ?? contextChannel;
714
+ const ownUserId = client.user?.id;
715
+ const [watchers, setWatchers] = (0, react.useState)(() => getOtherWatchers(channel?.state?.watchers, ownUserId));
716
+ (0, react.useEffect)(() => {
717
+ setWatchers(getOtherWatchers(channel?.state?.watchers, ownUserId));
718
+ }, [channel, ownUserId]);
719
+ (0, react.useEffect)(() => {
720
+ if (!enabled || !channel) return;
721
+ const startSubscription = channel.on("user.watching.start", (event) => {
722
+ setWatchers((prev) => {
723
+ if (!event.user?.id || event.user.id === ownUserId) return prev;
724
+ if (prev[event.user.id]) return prev;
725
+ return Object.assign({ [event.user.id]: event.user }, prev);
726
+ });
727
+ });
728
+ const stopSubscription = channel.on("user.watching.stop", (event) => {
729
+ setWatchers((prev) => {
730
+ if (!event.user?.id || !prev[event.user.id]) return prev;
731
+ const next = Object.assign({}, prev);
732
+ delete next[event.user.id];
733
+ return next;
734
+ });
735
+ });
736
+ return () => {
737
+ startSubscription.unsubscribe();
738
+ stopSubscription.unsubscribe();
739
+ };
740
+ }, [
741
+ channel,
742
+ enabled,
743
+ ownUserId
744
+ ]);
745
+ if (!enabled) return false;
746
+ return Object.keys(watchers).length > 0;
747
+ };
748
+ //#endregion
749
+ //#region src/components/ChannelHeader/hooks/useChannelHeaderOnlineStatus.ts
750
+ /**
751
+ * Returns the channel header online status text (e.g. "Online", "Offline", or "X members, Y online").
752
+ * Returns null when the channel has no members (nothing to show).
753
+ */
754
+ function useChannelHeaderOnlineStatus({ channel: channelOverride, watcherCount: watcherCountOverride } = {}) {
755
+ const { t } = require_NotificationList.useTranslationContext();
756
+ const { client } = require_NotificationList.useChatContext();
757
+ const { channel: contextChannel, watcherCount: contextWatcherCount = 0 } = require_NotificationList.useChannelStateContext();
758
+ const channel = channelOverride ?? contextChannel;
759
+ const watcherCount = watcherCountOverride ?? contextWatcherCount;
760
+ const { member_count: memberCount = 0 } = channel?.data || {};
761
+ const isDirectMessagingChannel = isDmChannel({
762
+ channel,
763
+ ownUserId: client.user?.id
764
+ });
765
+ const hasMembersOnline = useChannelHasMembersOnline({
766
+ channel,
767
+ enabled: isDirectMessagingChannel
768
+ });
769
+ if (!memberCount) return null;
770
+ if (isDirectMessagingChannel) return hasMembersOnline ? t("Online") : t("Offline");
771
+ return `${t("{{ memberCount }} members", { memberCount })} · ${t("{{ watcherCount }} online", { watcherCount })}`;
772
+ }
773
+ //#endregion
774
+ Object.defineProperty(exports, "Alert", {
775
+ enumerable: true,
776
+ get: function() {
777
+ return Alert;
778
+ }
779
+ });
780
+ Object.defineProperty(exports, "Badge", {
781
+ enumerable: true,
782
+ get: function() {
783
+ return Badge;
784
+ }
785
+ });
786
+ Object.defineProperty(exports, "ChannelAvatar", {
787
+ enumerable: true,
788
+ get: function() {
789
+ return ChannelAvatar;
790
+ }
791
+ });
792
+ Object.defineProperty(exports, "Checkbox", {
793
+ enumerable: true,
794
+ get: function() {
795
+ return Checkbox;
796
+ }
797
+ });
798
+ Object.defineProperty(exports, "Checkmark", {
799
+ enumerable: true,
800
+ get: function() {
801
+ return Checkmark;
802
+ }
803
+ });
804
+ Object.defineProperty(exports, "ErrorBadge", {
805
+ enumerable: true,
806
+ get: function() {
807
+ return ErrorBadge;
808
+ }
809
+ });
810
+ Object.defineProperty(exports, "GroupAvatar", {
811
+ enumerable: true,
812
+ get: function() {
813
+ return GroupAvatar;
814
+ }
815
+ });
816
+ Object.defineProperty(exports, "Header", {
817
+ enumerable: true,
818
+ get: function() {
819
+ return Header;
820
+ }
821
+ });
822
+ Object.defineProperty(exports, "MessageTranslationViewContext", {
823
+ enumerable: true,
824
+ get: function() {
825
+ return MessageTranslationViewContext;
826
+ }
827
+ });
828
+ Object.defineProperty(exports, "MessageTranslationViewProvider", {
829
+ enumerable: true,
830
+ get: function() {
831
+ return MessageTranslationViewProvider;
832
+ }
833
+ });
834
+ Object.defineProperty(exports, "Root", {
835
+ enumerable: true,
836
+ get: function() {
837
+ return Root;
838
+ }
839
+ });
840
+ Object.defineProperty(exports, "getChannelDisplayImage", {
841
+ enumerable: true,
842
+ get: function() {
843
+ return getChannelDisplayImage;
844
+ }
845
+ });
846
+ Object.defineProperty(exports, "getGroupChannelDisplayInfo", {
847
+ enumerable: true,
848
+ get: function() {
849
+ return getGroupChannelDisplayInfo;
850
+ }
851
+ });
852
+ Object.defineProperty(exports, "getLatestMessagePreview", {
853
+ enumerable: true,
854
+ get: function() {
855
+ return getLatestMessagePreview;
856
+ }
857
+ });
858
+ Object.defineProperty(exports, "getLatestMessagePreviewText", {
859
+ enumerable: true,
860
+ get: function() {
861
+ return getLatestMessagePreviewText;
862
+ }
863
+ });
864
+ Object.defineProperty(exports, "getTranslatedMessageText", {
865
+ enumerable: true,
866
+ get: function() {
867
+ return getTranslatedMessageText;
868
+ }
869
+ });
870
+ Object.defineProperty(exports, "htmlToTextPlugin", {
871
+ enumerable: true,
872
+ get: function() {
873
+ return htmlToTextPlugin;
874
+ }
875
+ });
876
+ Object.defineProperty(exports, "imageToLink", {
877
+ enumerable: true,
878
+ get: function() {
879
+ return imageToLink;
880
+ }
881
+ });
882
+ Object.defineProperty(exports, "isDmChannel", {
883
+ enumerable: true,
884
+ get: function() {
885
+ return isDmChannel;
886
+ }
887
+ });
888
+ Object.defineProperty(exports, "plusPlusToEmphasis", {
889
+ enumerable: true,
890
+ get: function() {
891
+ return plusPlusToEmphasis;
892
+ }
893
+ });
894
+ Object.defineProperty(exports, "renderPreviewText", {
895
+ enumerable: true,
896
+ get: function() {
897
+ return renderPreviewText;
898
+ }
899
+ });
900
+ Object.defineProperty(exports, "useChannelDisplayName", {
901
+ enumerable: true,
902
+ get: function() {
903
+ return useChannelDisplayName;
904
+ }
905
+ });
906
+ Object.defineProperty(exports, "useChannelHasMembersOnline", {
907
+ enumerable: true,
908
+ get: function() {
909
+ return useChannelHasMembersOnline;
910
+ }
911
+ });
912
+ Object.defineProperty(exports, "useChannelHeaderOnlineStatus", {
913
+ enumerable: true,
914
+ get: function() {
915
+ return useChannelHeaderOnlineStatus;
916
+ }
917
+ });
918
+ Object.defineProperty(exports, "useChannelMembershipState", {
919
+ enumerable: true,
920
+ get: function() {
921
+ return useChannelMembershipState;
922
+ }
923
+ });
924
+ Object.defineProperty(exports, "useChannelPreviewInfo", {
925
+ enumerable: true,
926
+ get: function() {
927
+ return useChannelPreviewInfo;
928
+ }
929
+ });
930
+ Object.defineProperty(exports, "useIsChannelMuted", {
931
+ enumerable: true,
932
+ get: function() {
933
+ return useIsChannelMuted;
934
+ }
935
+ });
936
+ Object.defineProperty(exports, "useIsUserMuted", {
937
+ enumerable: true,
938
+ get: function() {
939
+ return useIsUserMuted;
940
+ }
941
+ });
942
+ Object.defineProperty(exports, "useMessageTranslationViewContext", {
943
+ enumerable: true,
944
+ get: function() {
945
+ return useMessageTranslationViewContext;
946
+ }
947
+ });
948
+ Object.defineProperty(exports, "useSelectedChannelState", {
949
+ enumerable: true,
950
+ get: function() {
951
+ return useSelectedChannelState;
952
+ }
953
+ });
954
+ Object.defineProperty(exports, "useStableCallback", {
955
+ enumerable: true,
956
+ get: function() {
957
+ return useStableCallback;
958
+ }
959
+ });
960
+
961
+ //# sourceMappingURL=useChannelHeaderOnlineStatus.7e17671e.js.map