stream-chat-react 12.3.0 → 12.4.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 (48) hide show
  1. package/dist/components/Channel/Channel.d.ts +1 -1
  2. package/dist/components/Channel/Channel.js +2 -0
  3. package/dist/components/ChatAutoComplete/ChatAutoComplete.d.ts +1 -1
  4. package/dist/components/Message/MessageOptions.js +1 -1
  5. package/dist/components/Message/MessageSimple.js +5 -2
  6. package/dist/components/Message/utils.d.ts +1 -1
  7. package/dist/components/MessageActions/MessageActions.d.ts +2 -1
  8. package/dist/components/MessageActions/MessageActions.js +1 -1
  9. package/dist/components/Reactions/ReactionSelectorWithButton.d.ts +1 -2
  10. package/dist/components/Reactions/ReactionSelectorWithButton.js +2 -2
  11. package/dist/components/Threads/hooks/useThreadManagerState.js +1 -1
  12. package/dist/context/ComponentContext.d.ts +7 -1
  13. package/dist/experimental/MessageActions/MessageActions.d.ts +17 -0
  14. package/dist/experimental/MessageActions/MessageActions.js +48 -0
  15. package/dist/experimental/MessageActions/defaults.d.ts +5 -0
  16. package/dist/experimental/MessageActions/defaults.js +93 -0
  17. package/dist/experimental/MessageActions/hooks/index.d.ts +2 -0
  18. package/dist/experimental/MessageActions/hooks/index.js +2 -0
  19. package/dist/experimental/MessageActions/hooks/useBaseMessageActionSetFilter.d.ts +8 -0
  20. package/dist/experimental/MessageActions/hooks/useBaseMessageActionSetFilter.js +57 -0
  21. package/dist/experimental/MessageActions/hooks/useSplitMessageActionSet.d.ts +5 -0
  22. package/dist/experimental/MessageActions/hooks/useSplitMessageActionSet.js +12 -0
  23. package/dist/experimental/MessageActions/index.d.ts +3 -0
  24. package/dist/experimental/MessageActions/index.js +3 -0
  25. package/dist/experimental/index.browser.cjs +1091 -0
  26. package/dist/experimental/index.browser.cjs.map +7 -0
  27. package/dist/experimental/index.d.ts +1 -0
  28. package/dist/experimental/index.js +1 -0
  29. package/dist/experimental/index.node.cjs +1099 -0
  30. package/dist/experimental/index.node.cjs.map +7 -0
  31. package/dist/i18n/Streami18n.d.ts +1 -0
  32. package/dist/i18n/de.json +1 -0
  33. package/dist/i18n/en.json +1 -0
  34. package/dist/i18n/es.json +1 -0
  35. package/dist/i18n/fr.json +1 -0
  36. package/dist/i18n/hi.json +1 -0
  37. package/dist/i18n/it.json +1 -0
  38. package/dist/i18n/ja.json +1 -0
  39. package/dist/i18n/ko.json +1 -0
  40. package/dist/i18n/nl.json +1 -0
  41. package/dist/i18n/pt.json +1 -0
  42. package/dist/i18n/ru.json +1 -0
  43. package/dist/i18n/tr.json +1 -0
  44. package/dist/index.browser.cjs +23 -6
  45. package/dist/index.browser.cjs.map +3 -3
  46. package/dist/index.node.cjs +24 -6
  47. package/dist/index.node.cjs.map +3 -3
  48. package/package.json +16 -1
@@ -0,0 +1,1091 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/experimental/index.ts
31
+ var experimental_exports = {};
32
+ __export(experimental_exports, {
33
+ DefaultDropdownActionButton: () => DefaultDropdownActionButton,
34
+ MessageActions: () => MessageActions,
35
+ defaultMessageActionSet: () => defaultMessageActionSet,
36
+ useBaseMessageActionSetFilter: () => useBaseMessageActionSetFilter,
37
+ useSplitMessageActionSet: () => useSplitMessageActionSet
38
+ });
39
+ module.exports = __toCommonJS(experimental_exports);
40
+
41
+ // src/experimental/MessageActions/MessageActions.tsx
42
+ var import_clsx5 = __toESM(require("clsx"));
43
+ var import_react24 = __toESM(require("react"));
44
+
45
+ // src/context/ChannelActionContext.tsx
46
+ var import_react = __toESM(require("react"));
47
+ var ChannelActionContext = import_react.default.createContext(
48
+ void 0
49
+ );
50
+ var useChannelActionContext = (componentName) => {
51
+ const contextValue = (0, import_react.useContext)(ChannelActionContext);
52
+ if (!contextValue) {
53
+ console.warn(
54
+ `The useChannelActionContext hook was called outside of the ChannelActionContext provider. Make sure this hook is called within a child of the Channel component. The errored call is located in the ${componentName} component.`
55
+ );
56
+ return {};
57
+ }
58
+ return contextValue;
59
+ };
60
+
61
+ // src/context/ChannelStateContext.tsx
62
+ var import_react2 = __toESM(require("react"));
63
+ var ChannelStateContext = import_react2.default.createContext(
64
+ void 0
65
+ );
66
+ var useChannelStateContext = (componentName) => {
67
+ const contextValue = (0, import_react2.useContext)(ChannelStateContext);
68
+ if (!contextValue) {
69
+ console.warn(
70
+ `The useChannelStateContext hook was called outside of the ChannelStateContext provider. Make sure this hook is called within a child of the Channel component. The errored call is located in the ${componentName} component.`
71
+ );
72
+ return {};
73
+ }
74
+ return contextValue;
75
+ };
76
+
77
+ // src/context/ChatContext.tsx
78
+ var import_react3 = __toESM(require("react"));
79
+ var ChatContext = import_react3.default.createContext(void 0);
80
+ var useChatContext = (componentName) => {
81
+ const contextValue = (0, import_react3.useContext)(ChatContext);
82
+ if (!contextValue) {
83
+ console.warn(
84
+ `The useChatContext hook was called outside of the ChatContext provider. Make sure this hook is called within a child of the Chat component. The errored call is located in the ${componentName} component.`
85
+ );
86
+ return {};
87
+ }
88
+ return contextValue;
89
+ };
90
+
91
+ // src/context/ComponentContext.tsx
92
+ var import_react4 = __toESM(require("react"));
93
+ var ComponentContext = import_react4.default.createContext({});
94
+ var useComponentContext = (_componentName) => (0, import_react4.useContext)(ComponentContext);
95
+
96
+ // src/context/DialogManagerContext.tsx
97
+ var import_react8 = __toESM(require("react"));
98
+
99
+ // src/components/Dialog/DialogPortal.tsx
100
+ var import_react7 = __toESM(require("react"));
101
+ var import_react_dom = require("react-dom");
102
+
103
+ // src/components/Dialog/hooks/useDialog.ts
104
+ var import_react6 = require("react");
105
+
106
+ // src/store/hooks/useStateStore.ts
107
+ var import_react5 = require("react");
108
+ function useStateStore(store, selector) {
109
+ const [state, setState] = (0, import_react5.useState)(() => {
110
+ if (!store) return void 0;
111
+ return selector(store.getLatestValue());
112
+ });
113
+ (0, import_react5.useEffect)(() => {
114
+ if (!store) return;
115
+ const unsubscribe = store.subscribeWithSelector(selector, setState);
116
+ return unsubscribe;
117
+ }, [store, selector]);
118
+ return state;
119
+ }
120
+
121
+ // src/components/Dialog/hooks/useDialog.ts
122
+ var useDialog = ({ id }) => {
123
+ const { dialogManager } = useDialogManager();
124
+ (0, import_react6.useEffect)(
125
+ () => () => {
126
+ dialogManager.remove(id);
127
+ },
128
+ [dialogManager, id]
129
+ );
130
+ return dialogManager.getOrCreate({ id });
131
+ };
132
+ var useDialogIsOpen = (id) => {
133
+ const { dialogManager } = useDialogManager();
134
+ const dialogIsOpenSelector = (0, import_react6.useCallback)(
135
+ ({ dialogsById }) => ({ isOpen: !!dialogsById[id]?.isOpen }),
136
+ [id]
137
+ );
138
+ return useStateStore(dialogManager.state, dialogIsOpenSelector).isOpen;
139
+ };
140
+
141
+ // src/components/Dialog/DialogPortal.tsx
142
+ var DialogPortalEntry = ({
143
+ children,
144
+ dialogId
145
+ }) => {
146
+ const { dialogManager } = useDialogManager();
147
+ const dialogIsOpen = useDialogIsOpen(dialogId);
148
+ const [portalDestination, setPortalDestination] = (0, import_react7.useState)(null);
149
+ (0, import_react7.useLayoutEffect)(() => {
150
+ const destination = document.querySelector(
151
+ `div[data-str-chat__portal-id="${dialogManager.id}"]`
152
+ );
153
+ if (!destination) return;
154
+ setPortalDestination(destination);
155
+ }, [dialogManager, dialogIsOpen]);
156
+ if (!portalDestination) return null;
157
+ return (0, import_react_dom.createPortal)(children, portalDestination);
158
+ };
159
+
160
+ // src/context/DialogManagerContext.tsx
161
+ var DialogManagerProviderContext = import_react8.default.createContext(void 0);
162
+ var useDialogManager = () => {
163
+ const value = (0, import_react8.useContext)(DialogManagerProviderContext);
164
+ return value;
165
+ };
166
+
167
+ // src/context/MessageContext.tsx
168
+ var import_react9 = __toESM(require("react"));
169
+ var MessageContext = import_react9.default.createContext(void 0);
170
+ var useMessageContext = (_componentName) => {
171
+ const contextValue = (0, import_react9.useContext)(MessageContext);
172
+ if (!contextValue) {
173
+ return {};
174
+ }
175
+ return contextValue;
176
+ };
177
+
178
+ // src/context/TranslationContext.tsx
179
+ var import_react10 = __toESM(require("react"));
180
+ var import_dayjs2 = __toESM(require("dayjs"));
181
+ var import_calendar = __toESM(require("dayjs/plugin/calendar"));
182
+ var import_localizedFormat = __toESM(require("dayjs/plugin/localizedFormat"));
183
+
184
+ // src/i18n/utils.ts
185
+ var import_dayjs = __toESM(require("dayjs"));
186
+ var defaultTranslatorFunction = (key) => key;
187
+ var defaultDateTimeParser = (input) => (0, import_dayjs.default)(input);
188
+
189
+ // src/context/TranslationContext.tsx
190
+ import_dayjs2.default.extend(import_calendar.default);
191
+ import_dayjs2.default.extend(import_localizedFormat.default);
192
+ var TranslationContext = import_react10.default.createContext({
193
+ t: defaultTranslatorFunction,
194
+ tDateTimeParser: defaultDateTimeParser,
195
+ userLanguage: "en"
196
+ });
197
+ var useTranslationContext = (componentName) => {
198
+ const contextValue = (0, import_react10.useContext)(TranslationContext);
199
+ if (!contextValue) {
200
+ console.warn(
201
+ `The useTranslationContext hook was called outside of the TranslationContext provider. Make sure this hook is called within a child of the Chat component. The errored call is located in the ${componentName} component.`
202
+ );
203
+ return {};
204
+ }
205
+ return contextValue;
206
+ };
207
+
208
+ // src/components/Avatar/Avatar.tsx
209
+ var import_clsx = __toESM(require("clsx"));
210
+ var import_react12 = __toESM(require("react"));
211
+
212
+ // src/components/Threads/icons.tsx
213
+ var import_react11 = __toESM(require("react"));
214
+ var Icon = {
215
+ MessageBubble: (props) => /* @__PURE__ */ import_react11.default.createElement(
216
+ "svg",
217
+ {
218
+ className: "str-chat__icon str-chat__icon--message-bubble",
219
+ fill: "none",
220
+ height: "14",
221
+ viewBox: "0 0 14 14",
222
+ width: "14",
223
+ xmlns: "http://www.w3.org/2000/svg",
224
+ ...props
225
+ },
226
+ /* @__PURE__ */ import_react11.default.createElement(
227
+ "path",
228
+ {
229
+ d: "M1.66659 1.66665H12.3333V9.66665H2.44659L1.66659 10.4466V1.66665ZM1.66659 0.333313C0.933252 0.333313 0.339919 0.933313 0.339919 1.66665L0.333252 13.6666L2.99992 11H12.3333C13.0666 11 13.6666 10.4 13.6666 9.66665V1.66665C13.6666 0.933313 13.0666 0.333313 12.3333 0.333313H1.66659ZM2.99992 6.99998H10.9999V8.33331H2.99992V6.99998ZM2.99992 4.99998H10.9999V6.33331H2.99992V4.99998ZM2.99992 2.99998H10.9999V4.33331H2.99992V2.99998Z",
230
+ fill: "currentColor"
231
+ }
232
+ )
233
+ ),
234
+ MessageBubbleEmpty: (props) => /* @__PURE__ */ import_react11.default.createElement(
235
+ "svg",
236
+ {
237
+ className: "str-chat__icon str-chat__icon--message-bubble-empty",
238
+ fill: "none",
239
+ height: "20",
240
+ viewBox: "0 0 20 20",
241
+ width: "20",
242
+ xmlns: "http://www.w3.org/2000/svg",
243
+ ...props
244
+ },
245
+ /* @__PURE__ */ import_react11.default.createElement(
246
+ "path",
247
+ {
248
+ d: "M18 0H2C0.9 0 0 0.9 0 2V20L4 16H18C19.1 16 20 15.1 20 14V2C20 0.9 19.1 0 18 0ZM18 14H4L2 16V2H18V14Z",
249
+ fill: "currentColor"
250
+ }
251
+ )
252
+ ),
253
+ Reload: (props) => /* @__PURE__ */ import_react11.default.createElement(
254
+ "svg",
255
+ {
256
+ className: "str-chat__icon str-chat__icon--reload",
257
+ fill: "none",
258
+ height: "22",
259
+ viewBox: "0 0 16 22",
260
+ width: "16",
261
+ xmlns: "http://www.w3.org/2000/svg",
262
+ ...props
263
+ },
264
+ /* @__PURE__ */ import_react11.default.createElement(
265
+ "path",
266
+ {
267
+ d: "M8 3V0L4 4L8 8V5C11.31 5 14 7.69 14 11C14 12.01 13.75 12.97 13.3 13.8L14.76 15.26C15.54 14.03 16 12.57 16 11C16 6.58 12.42 3 8 3ZM8 17C4.69 17 2 14.31 2 11C2 9.99 2.25 9.03 2.7 8.2L1.24 6.74C0.46 7.97 0 9.43 0 11C0 15.42 3.58 19 8 19V22L12 18L8 14V17Z",
268
+ fill: "currentColor"
269
+ }
270
+ )
271
+ ),
272
+ User: (props) => /* @__PURE__ */ import_react11.default.createElement(
273
+ "svg",
274
+ {
275
+ className: "str-chat__icon str-chat__icon--user",
276
+ fill: "none",
277
+ height: "16",
278
+ viewBox: "0 0 16 16",
279
+ width: "16",
280
+ xmlns: "http://www.w3.org/2000/svg",
281
+ ...props
282
+ },
283
+ /* @__PURE__ */ import_react11.default.createElement(
284
+ "path",
285
+ {
286
+ d: "M8 2C9.1 2 10 2.9 10 4C10 5.1 9.1 6 8 6C6.9 6 6 5.1 6 4C6 2.9 6.9 2 8 2ZM8 12C10.7 12 13.8 13.29 14 14H2C2.23 13.28 5.31 12 8 12ZM8 0C5.79 0 4 1.79 4 4C4 6.21 5.79 8 8 8C10.21 8 12 6.21 12 4C12 1.79 10.21 0 8 0ZM8 10C5.33 10 0 11.34 0 14V16H16V14C16 11.34 10.67 10 8 10Z",
287
+ fill: "currentColor"
288
+ }
289
+ )
290
+ )
291
+ };
292
+
293
+ // src/utils/getWholeChar.ts
294
+ var getWholeChar = (str, i) => {
295
+ const code = str.charCodeAt(i);
296
+ if (Number.isNaN(code)) return "";
297
+ if (code < 55296 || code > 57343) return str.charAt(i);
298
+ if (55296 <= code && code <= 56319) {
299
+ if (str.length <= i + 1) {
300
+ throw "High surrogate without following low surrogate";
301
+ }
302
+ const next = str.charCodeAt(i + 1);
303
+ if (56320 > next || next > 57343) {
304
+ throw "High surrogate without following low surrogate";
305
+ }
306
+ return str.charAt(i) + str.charAt(i + 1);
307
+ }
308
+ if (i === 0) {
309
+ throw "Low surrogate without preceding high surrogate";
310
+ }
311
+ const prev = str.charCodeAt(i - 1);
312
+ if (55296 > prev || prev > 56319) {
313
+ throw "Low surrogate without preceding high surrogate";
314
+ }
315
+ return "";
316
+ };
317
+
318
+ // src/components/Avatar/Avatar.tsx
319
+ var Avatar = (props) => {
320
+ const {
321
+ className,
322
+ image,
323
+ name,
324
+ onClick = () => void 0,
325
+ onMouseOver = () => void 0
326
+ } = props;
327
+ const [error, setError] = (0, import_react12.useState)(false);
328
+ (0, import_react12.useEffect)(() => {
329
+ setError(false);
330
+ }, [image]);
331
+ const nameStr = name?.toString() || "";
332
+ const initials = getWholeChar(nameStr, 0);
333
+ const showImage = image && !error;
334
+ return /* @__PURE__ */ import_react12.default.createElement(
335
+ "div",
336
+ {
337
+ className: (0, import_clsx.default)(`str-chat__avatar str-chat__message-sender-avatar`, className, {
338
+ ["str-chat__avatar--multiple-letters"]: initials.length > 1,
339
+ ["str-chat__avatar--no-letters"]: !initials.length,
340
+ ["str-chat__avatar--one-letter"]: initials.length === 1
341
+ }),
342
+ "data-testid": "avatar",
343
+ onClick,
344
+ onMouseOver,
345
+ role: "button",
346
+ title: name
347
+ },
348
+ showImage ? /* @__PURE__ */ import_react12.default.createElement(
349
+ "img",
350
+ {
351
+ alt: initials,
352
+ className: "str-chat__avatar-image",
353
+ "data-testid": "avatar-img",
354
+ onError: () => setError(true),
355
+ src: image
356
+ }
357
+ ) : /* @__PURE__ */ import_react12.default.createElement(import_react12.default.Fragment, null, !!initials.length && /* @__PURE__ */ import_react12.default.createElement("div", { className: (0, import_clsx.default)("str-chat__avatar-fallback"), "data-testid": "avatar-fallback" }, initials), !initials.length && /* @__PURE__ */ import_react12.default.createElement(Icon.User, null))
358
+ );
359
+ };
360
+
361
+ // src/components/Message/utils.tsx
362
+ var import_react_fast_compare = __toESM(require("react-fast-compare"));
363
+ var import_emoji_regex = __toESM(require("emoji-regex"));
364
+ var isUserMuted = (message, mutes) => {
365
+ if (!mutes || !message) return false;
366
+ const userMuted = mutes.filter((el) => el.target.id === message.user?.id);
367
+ return !!userMuted.length;
368
+ };
369
+ var MESSAGE_ACTIONS = {
370
+ delete: "delete",
371
+ edit: "edit",
372
+ flag: "flag",
373
+ markUnread: "markUnread",
374
+ mute: "mute",
375
+ pin: "pin",
376
+ quote: "quote",
377
+ react: "react",
378
+ reply: "reply"
379
+ };
380
+ var ACTIONS_NOT_WORKING_IN_THREAD = [
381
+ MESSAGE_ACTIONS.pin,
382
+ MESSAGE_ACTIONS.reply,
383
+ MESSAGE_ACTIONS.markUnread
384
+ ];
385
+
386
+ // src/components/Message/hooks/useUserRole.ts
387
+ var useUserRole = (message, onlySenderCanEdit, disableQuotedMessages) => {
388
+ const { channel, channelCapabilities = {} } = useChannelStateContext(
389
+ "useUserRole"
390
+ );
391
+ const { client } = useChatContext("useUserRole");
392
+ const isAdmin = client.user?.role === "admin" || channel.state.membership.role === "admin";
393
+ const isOwner = channel.state.membership.role === "owner";
394
+ const isModerator = client.user?.role === "channel_moderator" || channel.state.membership.role === "channel_moderator" || channel.state.membership.role === "moderator" || channel.state.membership.is_moderator === true || channel.state.membership.channel_role === "channel_moderator";
395
+ const isMyMessage = client.userID === message.user?.id;
396
+ const canEdit = !onlySenderCanEdit && channelCapabilities["update-any-message"] || isMyMessage && channelCapabilities["update-own-message"];
397
+ const canDelete = channelCapabilities["delete-any-message"] || isMyMessage && channelCapabilities["delete-own-message"];
398
+ const canFlag = !isMyMessage && channelCapabilities["flag-message"];
399
+ const canMarkUnread = channelCapabilities["read-events"];
400
+ const canMute = !isMyMessage && channelCapabilities["mute-channel"];
401
+ const canQuote = !disableQuotedMessages && channelCapabilities["quote-message"];
402
+ const canReact = channelCapabilities["send-reaction"];
403
+ const canReply = channelCapabilities["send-reply"];
404
+ return {
405
+ canDelete,
406
+ canEdit,
407
+ canFlag,
408
+ canMarkUnread,
409
+ canMute,
410
+ canQuote,
411
+ canReact,
412
+ canReply,
413
+ isAdmin,
414
+ isModerator,
415
+ isMyMessage,
416
+ isOwner
417
+ };
418
+ };
419
+
420
+ // src/components/Message/icons.tsx
421
+ var import_react13 = __toESM(require("react"));
422
+ var ActionsIcon = ({ className = "" }) => /* @__PURE__ */ import_react13.default.createElement(
423
+ "svg",
424
+ {
425
+ className,
426
+ height: "4",
427
+ viewBox: "0 0 11 4",
428
+ width: "11",
429
+ xmlns: "http://www.w3.org/2000/svg"
430
+ },
431
+ /* @__PURE__ */ import_react13.default.createElement(
432
+ "path",
433
+ {
434
+ d: "M1.5 3a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm4 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm4 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3z",
435
+ fillRule: "nonzero"
436
+ }
437
+ )
438
+ );
439
+ var ReactionIcon = ({ className = "" }) => /* @__PURE__ */ import_react13.default.createElement(
440
+ "svg",
441
+ {
442
+ className,
443
+ height: "12",
444
+ viewBox: "0 0 12 12",
445
+ width: "12",
446
+ xmlns: "http://www.w3.org/2000/svg"
447
+ },
448
+ /* @__PURE__ */ import_react13.default.createElement("g", { clipRule: "evenodd", fillRule: "evenodd" }, /* @__PURE__ */ import_react13.default.createElement("path", { d: "M6 1.2C3.3 1.2 1.2 3.3 1.2 6c0 2.7 2.1 4.8 4.8 4.8 2.7 0 4.8-2.1 4.8-4.8 0-2.7-2.1-4.8-4.8-4.8zM0 6c0-3.3 2.7-6 6-6s6 2.7 6 6-2.7 6-6 6-6-2.7-6-6z" }), /* @__PURE__ */ import_react13.default.createElement("path", { d: "M5.4 4.5c0 .5-.4.9-.9.9s-.9-.4-.9-.9.4-.9.9-.9.9.4.9.9zM8.4 4.5c0 .5-.4.9-.9.9s-.9-.4-.9-.9.4-.9.9-.9.9.4.9.9zM3.3 6.7c.3-.2.6-.1.8.1.3.4.8.9 1.5 1 .6.2 1.4.1 2.4-1 .2-.2.6-.3.8 0 .2.2.3.6 0 .8-1.1 1.3-2.4 1.7-3.5 1.5-1-.2-1.8-.9-2.2-1.5-.2-.3-.1-.7.2-.9z" }))
449
+ );
450
+ var ThreadIcon = ({ className = "" }) => /* @__PURE__ */ import_react13.default.createElement("svg", { className, height: "10", width: "14", xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ import_react13.default.createElement(
451
+ "path",
452
+ {
453
+ d: "M8.516 3c4.78 0 4.972 6.5 4.972 6.5-1.6-2.906-2.847-3.184-4.972-3.184v2.872L3.772 4.994 8.516.5V3zM.484 5l4.5-4.237v1.78L2.416 5l2.568 2.125v1.828L.484 5z",
454
+ fillRule: "evenodd"
455
+ }
456
+ ));
457
+
458
+ // src/components/MessageActions/MessageActions.tsx
459
+ var import_clsx3 = __toESM(require("clsx"));
460
+ var import_react15 = __toESM(require("react"));
461
+
462
+ // src/components/Dialog/DialogAnchor.tsx
463
+ var import_clsx2 = __toESM(require("clsx"));
464
+ var import_react14 = __toESM(require("react"));
465
+ var import_focus = require("@react-aria/focus");
466
+ var import_react_popper = require("react-popper");
467
+ function useDialogAnchor({
468
+ open,
469
+ placement,
470
+ referenceElement
471
+ }) {
472
+ const [popperElement, setPopperElement] = (0, import_react14.useState)(null);
473
+ const { attributes, styles, update } = (0, import_react_popper.usePopper)(referenceElement, popperElement, {
474
+ modifiers: [
475
+ {
476
+ name: "eventListeners",
477
+ options: {
478
+ // It's not safe to update popper position on resize and scroll, since popper's
479
+ // reference element might not be visible at the time.
480
+ resize: false,
481
+ scroll: false
482
+ }
483
+ }
484
+ ],
485
+ placement
486
+ });
487
+ (0, import_react14.useEffect)(() => {
488
+ if (open && popperElement) {
489
+ update?.();
490
+ }
491
+ }, [open, popperElement, update]);
492
+ if (popperElement && !open) {
493
+ setPopperElement(null);
494
+ }
495
+ return {
496
+ attributes,
497
+ setPopperElement,
498
+ styles
499
+ };
500
+ }
501
+ var DialogAnchor = ({
502
+ children,
503
+ className,
504
+ focus = true,
505
+ id,
506
+ placement = "auto",
507
+ referenceElement = null,
508
+ trapFocus,
509
+ ...restDivProps
510
+ }) => {
511
+ const dialog = useDialog({ id });
512
+ const open = useDialogIsOpen(id);
513
+ const { attributes, setPopperElement, styles } = useDialogAnchor({
514
+ open,
515
+ placement,
516
+ referenceElement
517
+ });
518
+ (0, import_react14.useEffect)(() => {
519
+ if (!open) return;
520
+ const hideOnEscape = (event) => {
521
+ if (event.key !== "Escape") return;
522
+ dialog?.close();
523
+ };
524
+ document.addEventListener("keyup", hideOnEscape);
525
+ return () => {
526
+ document.removeEventListener("keyup", hideOnEscape);
527
+ };
528
+ }, [dialog, open]);
529
+ if (!open) {
530
+ return null;
531
+ }
532
+ return /* @__PURE__ */ import_react14.default.createElement(DialogPortalEntry, { dialogId: id }, /* @__PURE__ */ import_react14.default.createElement(import_focus.FocusScope, { autoFocus: focus, contain: trapFocus, restoreFocus: true }, /* @__PURE__ */ import_react14.default.createElement(
533
+ "div",
534
+ {
535
+ ...restDivProps,
536
+ ...attributes.popper,
537
+ className: (0, import_clsx2.default)("str-chat__dialog-contents", className),
538
+ "data-testid": "str-chat__dialog-contents",
539
+ ref: setPopperElement,
540
+ style: styles.popper,
541
+ tabIndex: 0
542
+ },
543
+ children
544
+ )));
545
+ };
546
+
547
+ // src/components/MessageActions/MessageActions.tsx
548
+ var MessageActionsWrapper = (props) => {
549
+ const { children, customWrapperClass, inline, toggleOpen } = props;
550
+ const defaultWrapperClass = (0, import_clsx3.default)(
551
+ "str-chat__message-simple__actions__action",
552
+ "str-chat__message-simple__actions__action--options",
553
+ "str-chat__message-actions-container"
554
+ );
555
+ const wrapperProps = {
556
+ className: customWrapperClass || defaultWrapperClass,
557
+ "data-testid": "message-actions",
558
+ onClick: toggleOpen
559
+ };
560
+ if (inline) return /* @__PURE__ */ import_react15.default.createElement("span", { ...wrapperProps }, children);
561
+ return /* @__PURE__ */ import_react15.default.createElement("div", { ...wrapperProps }, children);
562
+ };
563
+
564
+ // src/components/Reactions/ReactionSelectorWithButton.tsx
565
+ var import_react20 = __toESM(require("react"));
566
+
567
+ // src/components/Reactions/ReactionSelector.tsx
568
+ var import_react19 = __toESM(require("react"));
569
+ var import_clsx4 = __toESM(require("clsx"));
570
+
571
+ // src/components/Reactions/reactionOptions.tsx
572
+ var import_react18 = __toESM(require("react"));
573
+
574
+ // src/components/Reactions/StreamEmoji.tsx
575
+ var import_react17 = __toESM(require("react"));
576
+
577
+ // src/components/Reactions/SpriteImage.tsx
578
+ var import_react16 = __toESM(require("react"));
579
+
580
+ // src/components/Reactions/utils/utils.ts
581
+ var isMutableRef = (ref) => {
582
+ if (ref) {
583
+ return ref.current !== void 0;
584
+ }
585
+ return false;
586
+ };
587
+ var getImageDimensions = (source) => new Promise((resolve, reject) => {
588
+ const image = new Image();
589
+ image.addEventListener(
590
+ "load",
591
+ () => {
592
+ resolve([image.width, image.height]);
593
+ },
594
+ { once: true }
595
+ );
596
+ image.addEventListener("error", () => reject(`Couldn't load image from ${source}`), {
597
+ once: true
598
+ });
599
+ image.src = source;
600
+ });
601
+
602
+ // src/components/Reactions/SpriteImage.tsx
603
+ var SpriteImage = ({
604
+ columns,
605
+ fallback,
606
+ height,
607
+ position,
608
+ rows,
609
+ spriteUrl,
610
+ style,
611
+ width
612
+ }) => {
613
+ const [[spriteWidth, spriteHeight], setSpriteDimensions] = (0, import_react16.useState)([0, 0]);
614
+ (0, import_react16.useEffect)(() => {
615
+ getImageDimensions(spriteUrl).then(setSpriteDimensions).catch(console.error);
616
+ }, [spriteUrl]);
617
+ const [x, y] = position;
618
+ if (!spriteHeight || !spriteWidth) return /* @__PURE__ */ import_react16.default.createElement(import_react16.default.Fragment, null, fallback);
619
+ return /* @__PURE__ */ import_react16.default.createElement(
620
+ "div",
621
+ {
622
+ "data-testid": "sprite-image",
623
+ style: {
624
+ ...style,
625
+ "--str-chat__sprite-image-resize-ratio": "var(--str-chat__sprite-image-resize-ratio-x, var(--str-chat__sprite-image-resize-ratio-y, 1))",
626
+ "--str-chat__sprite-image-resize-ratio-x": "calc(var(--str-chat__sprite-image-width) / var(--str-chat__sprite-item-width))",
627
+ "--str-chat__sprite-image-resize-ratio-y": "calc(var(--str-chat__sprite-image-height) / var(--str-chat__sprite-item-height))",
628
+ "--str-chat__sprite-item-height": `${spriteHeight / rows}`,
629
+ "--str-chat__sprite-item-width": `${spriteWidth / columns}`,
630
+ ...Number.isFinite(height) ? { "--str-chat__sprite-image-height": `${height}px` } : {},
631
+ ...Number.isFinite(width) ? { "--str-chat__sprite-image-width": `${width}px` } : {},
632
+ backgroundImage: `url('${spriteUrl}')`,
633
+ backgroundPosition: `${x * (100 / (columns - 1))}% ${y * (100 / (rows - 1))}%`,
634
+ backgroundSize: `${columns * 100}% ${rows * 100}%`,
635
+ height: "var(--str-chat__sprite-image-height, calc(var(--str-chat__sprite-item-height) * var(--str-chat__sprite-image-resize-ratio)))",
636
+ width: "var(--str-chat__sprite-image-width, calc(var(--str-chat__sprite-item-width) * var(--str-chat__sprite-image-resize-ratio)))"
637
+ }
638
+ }
639
+ );
640
+ };
641
+
642
+ // src/components/Reactions/StreamEmoji.tsx
643
+ var StreamSpriteEmojiPositions = {
644
+ angry: [1, 1],
645
+ haha: [1, 0],
646
+ like: [0, 0],
647
+ love: [1, 2],
648
+ sad: [0, 1],
649
+ wow: [0, 2]
650
+ };
651
+ var STREAM_SPRITE_URL = "https://getstream.imgix.net/images/emoji-sprite.png";
652
+ var StreamEmoji = ({
653
+ fallback,
654
+ type
655
+ }) => {
656
+ const position = StreamSpriteEmojiPositions[type];
657
+ return /* @__PURE__ */ import_react17.default.createElement(
658
+ SpriteImage,
659
+ {
660
+ columns: 2,
661
+ fallback,
662
+ position,
663
+ rows: 3,
664
+ spriteUrl: STREAM_SPRITE_URL,
665
+ style: {
666
+ "--str-chat__sprite-image-height": "var(--str-chat__stream-emoji-size, 18px)"
667
+ }
668
+ }
669
+ );
670
+ };
671
+
672
+ // src/components/Reactions/reactionOptions.tsx
673
+ var defaultReactionOptions = [
674
+ { type: "haha", Component: () => /* @__PURE__ */ import_react18.default.createElement(StreamEmoji, { fallback: "\u{1F602}", type: "haha" }), name: "Joy" },
675
+ { type: "like", Component: () => /* @__PURE__ */ import_react18.default.createElement(StreamEmoji, { fallback: "\u{1F44D}", type: "like" }), name: "Thumbs up" },
676
+ { type: "love", Component: () => /* @__PURE__ */ import_react18.default.createElement(StreamEmoji, { fallback: "\u2764\uFE0F", type: "love" }), name: "Heart" },
677
+ { type: "sad", Component: () => /* @__PURE__ */ import_react18.default.createElement(StreamEmoji, { fallback: "\u{1F614}", type: "sad" }), name: "Sad" },
678
+ { type: "wow", Component: () => /* @__PURE__ */ import_react18.default.createElement(StreamEmoji, { fallback: "\u{1F632}", type: "wow" }), name: "Astonished" }
679
+ ];
680
+
681
+ // src/components/Reactions/ReactionSelector.tsx
682
+ var UnMemoizedReactionSelector = (props) => {
683
+ const {
684
+ Avatar: propAvatar,
685
+ detailedView = true,
686
+ handleReaction: propHandleReaction,
687
+ latest_reactions: propLatestReactions,
688
+ own_reactions: propOwnReactions,
689
+ reaction_groups: propReactionGroups,
690
+ reactionOptions: propReactionOptions,
691
+ reverse = false
692
+ } = props;
693
+ const {
694
+ Avatar: contextAvatar,
695
+ reactionOptions: contextReactionOptions = defaultReactionOptions
696
+ } = useComponentContext("ReactionSelector");
697
+ const {
698
+ closeReactionSelectorOnClick,
699
+ handleReaction: contextHandleReaction,
700
+ message
701
+ } = useMessageContext("ReactionSelector");
702
+ const dialogId = `reaction-selector--${message.id}`;
703
+ const dialog = useDialog({ id: dialogId });
704
+ const reactionOptions = propReactionOptions ?? contextReactionOptions;
705
+ const Avatar2 = propAvatar || contextAvatar || Avatar;
706
+ const handleReaction = propHandleReaction || contextHandleReaction;
707
+ const latestReactions = propLatestReactions || message?.latest_reactions || [];
708
+ const ownReactions = propOwnReactions || message?.own_reactions || [];
709
+ const reactionGroups = propReactionGroups || message?.reaction_groups || {};
710
+ const [tooltipReactionType, setTooltipReactionType] = (0, import_react19.useState)(null);
711
+ const [tooltipPositions, setTooltipPositions] = (0, import_react19.useState)(null);
712
+ const rootRef = (0, import_react19.useRef)(null);
713
+ const targetRef = (0, import_react19.useRef)(null);
714
+ const tooltipRef = (0, import_react19.useRef)(null);
715
+ const showTooltip = (0, import_react19.useCallback)(
716
+ (event, reactionType) => {
717
+ targetRef.current = event.currentTarget;
718
+ setTooltipReactionType(reactionType);
719
+ },
720
+ []
721
+ );
722
+ const hideTooltip = (0, import_react19.useCallback)(() => {
723
+ setTooltipReactionType(null);
724
+ setTooltipPositions(null);
725
+ }, []);
726
+ (0, import_react19.useEffect)(() => {
727
+ if (!tooltipReactionType || !rootRef.current) return;
728
+ const tooltip = tooltipRef.current?.getBoundingClientRect();
729
+ const target = targetRef.current?.getBoundingClientRect();
730
+ const container = isMutableRef(rootRef) ? rootRef.current?.getBoundingClientRect() : null;
731
+ if (!tooltip || !target || !container) return;
732
+ const tooltipPosition = tooltip.width === container.width || tooltip.x < container.x ? 0 : target.left + target.width / 2 - container.left - tooltip.width / 2;
733
+ const arrowPosition = target.x - tooltip.x + target.width / 2 - tooltipPosition;
734
+ setTooltipPositions({
735
+ arrow: arrowPosition,
736
+ tooltip: tooltipPosition
737
+ });
738
+ }, [tooltipReactionType, rootRef]);
739
+ const getUsersPerReactionType = (type) => latestReactions.map((reaction) => {
740
+ if (reaction.type === type) {
741
+ return reaction.user?.name || reaction.user?.id;
742
+ }
743
+ return null;
744
+ }).filter(Boolean);
745
+ const iHaveReactedWithReaction = (reactionType) => ownReactions.find((reaction) => reaction.type === reactionType);
746
+ const getLatestUserForReactionType = (type) => latestReactions.find((reaction) => reaction.type === type && !!reaction.user)?.user || void 0;
747
+ return /* @__PURE__ */ import_react19.default.createElement(
748
+ "div",
749
+ {
750
+ className: (0, import_clsx4.default)(
751
+ "str-chat__reaction-selector str-chat__message-reaction-selector str-chat-react__message-reaction-selector",
752
+ {
753
+ "str-chat__reaction-selector--reverse": reverse
754
+ }
755
+ ),
756
+ "data-testid": "reaction-selector",
757
+ ref: rootRef
758
+ },
759
+ !!tooltipReactionType && detailedView && /* @__PURE__ */ import_react19.default.createElement(
760
+ "div",
761
+ {
762
+ className: "str-chat__reaction-selector-tooltip",
763
+ ref: tooltipRef,
764
+ style: {
765
+ left: tooltipPositions?.tooltip,
766
+ visibility: tooltipPositions ? "visible" : "hidden"
767
+ }
768
+ },
769
+ /* @__PURE__ */ import_react19.default.createElement("div", { className: "arrow", style: { left: tooltipPositions?.arrow } }),
770
+ getUsersPerReactionType(tooltipReactionType)?.map((user, i, users) => /* @__PURE__ */ import_react19.default.createElement("span", { className: "latest-user-username", key: `key-${i}-${user}` }, `${user}${i < users.length - 1 ? ", " : ""}`))
771
+ ),
772
+ /* @__PURE__ */ import_react19.default.createElement("ul", { className: "str-chat__message-reactions-list str-chat__message-reactions-options" }, reactionOptions.map(({ Component, name: reactionName, type: reactionType }) => {
773
+ const latestUser = getLatestUserForReactionType(reactionType);
774
+ const count = reactionGroups[reactionType]?.count ?? 0;
775
+ return /* @__PURE__ */ import_react19.default.createElement("li", { key: reactionType }, /* @__PURE__ */ import_react19.default.createElement(
776
+ "button",
777
+ {
778
+ "aria-label": `Select Reaction: ${reactionName || reactionType}`,
779
+ className: (0, import_clsx4.default)(
780
+ "str-chat__message-reactions-list-item str-chat__message-reactions-option",
781
+ {
782
+ "str-chat__message-reactions-option-selected": iHaveReactedWithReaction(
783
+ reactionType
784
+ )
785
+ }
786
+ ),
787
+ "data-testid": "select-reaction-button",
788
+ "data-text": reactionType,
789
+ onClick: (event) => {
790
+ handleReaction(reactionType, event);
791
+ if (closeReactionSelectorOnClick) {
792
+ dialog.close();
793
+ }
794
+ }
795
+ },
796
+ !!count && detailedView && /* @__PURE__ */ import_react19.default.createElement(
797
+ "div",
798
+ {
799
+ className: "latest-user str-chat__message-reactions-last-user",
800
+ onClick: hideTooltip,
801
+ onMouseEnter: (e) => showTooltip(e, reactionType),
802
+ onMouseLeave: hideTooltip
803
+ },
804
+ latestUser ? /* @__PURE__ */ import_react19.default.createElement(
805
+ Avatar2,
806
+ {
807
+ image: latestUser.image,
808
+ name: latestUser.name,
809
+ size: 20,
810
+ user: latestUser
811
+ }
812
+ ) : /* @__PURE__ */ import_react19.default.createElement("div", { className: "latest-user-not-found" })
813
+ ),
814
+ /* @__PURE__ */ import_react19.default.createElement("span", { className: "str-chat__message-reaction-emoji" }, /* @__PURE__ */ import_react19.default.createElement(Component, null)),
815
+ Boolean(count) && detailedView && /* @__PURE__ */ import_react19.default.createElement("span", { className: "str-chat__message-reactions-list-item__count" }, count || "")
816
+ ));
817
+ }))
818
+ );
819
+ };
820
+ var ReactionSelector = import_react19.default.memo(
821
+ UnMemoizedReactionSelector
822
+ );
823
+
824
+ // src/components/Reactions/ReactionSelectorWithButton.tsx
825
+ var ReactionSelectorWithButton = ({
826
+ ReactionIcon: ReactionIcon2
827
+ }) => {
828
+ const { t } = useTranslationContext("ReactionSelectorWithButton");
829
+ const { isMyMessage, message } = useMessageContext("MessageOptions");
830
+ const { ReactionSelector: ReactionSelector2 = ReactionSelector } = useComponentContext("MessageOptions");
831
+ const buttonRef = (0, import_react20.useRef)(null);
832
+ const dialogId = `reaction-selector--${message.id}`;
833
+ const dialog = useDialog({ id: dialogId });
834
+ const dialogIsOpen = useDialogIsOpen(dialogId);
835
+ return /* @__PURE__ */ import_react20.default.createElement(import_react20.default.Fragment, null, /* @__PURE__ */ import_react20.default.createElement(
836
+ DialogAnchor,
837
+ {
838
+ id: dialogId,
839
+ placement: isMyMessage() ? "top-end" : "top-start",
840
+ referenceElement: buttonRef.current,
841
+ trapFocus: true
842
+ },
843
+ /* @__PURE__ */ import_react20.default.createElement(ReactionSelector2, null)
844
+ ), /* @__PURE__ */ import_react20.default.createElement(
845
+ "button",
846
+ {
847
+ "aria-expanded": dialogIsOpen,
848
+ "aria-label": t("aria/Open Reaction Selector"),
849
+ className: "str-chat__message-reactions-button",
850
+ "data-testid": "message-reaction-action",
851
+ onClick: () => dialog?.toggle(),
852
+ ref: buttonRef
853
+ },
854
+ /* @__PURE__ */ import_react20.default.createElement(ReactionIcon2, { className: "str-chat__message-action-icon" })
855
+ ));
856
+ };
857
+
858
+ // src/experimental/MessageActions/hooks/useBaseMessageActionSetFilter.ts
859
+ var import_react21 = require("react");
860
+ var useBaseMessageActionSetFilter = (messageActionSet, disable = false) => {
861
+ const { initialMessage: isInitialMessage, message } = useMessageContext();
862
+ const {
863
+ canDelete,
864
+ canEdit,
865
+ canFlag,
866
+ canMarkUnread,
867
+ canMute,
868
+ canQuote,
869
+ canReact,
870
+ canReply
871
+ } = useUserRole(message);
872
+ const isMessageThreadReply = typeof message.parent_id === "string";
873
+ return (0, import_react21.useMemo)(() => {
874
+ if (disable) return messageActionSet;
875
+ if (isInitialMessage || // not sure whether this thing even works anymore
876
+ !message.type || message.type === "error" || message.type === "system" || message.type === "ephemeral" || message.status === "failed" || message.status === "sending")
877
+ return [];
878
+ return messageActionSet.filter(({ type }) => {
879
+ if (ACTIONS_NOT_WORKING_IN_THREAD.includes(type) && isMessageThreadReply) return false;
880
+ if (type === "delete" && !canDelete || type === "edit" && !canEdit || type === "flag" && !canFlag || type === "markUnread" && !canMarkUnread || type === "mute" && !canMute || type === "quote" && !canQuote || type === "react" && !canReact || type === "reply" && !canReply)
881
+ return false;
882
+ return true;
883
+ });
884
+ }, [
885
+ canDelete,
886
+ canEdit,
887
+ canFlag,
888
+ canMarkUnread,
889
+ canMute,
890
+ canQuote,
891
+ canReact,
892
+ canReply,
893
+ isInitialMessage,
894
+ isMessageThreadReply,
895
+ message.status,
896
+ message.type,
897
+ disable,
898
+ messageActionSet
899
+ ]);
900
+ };
901
+
902
+ // src/experimental/MessageActions/hooks/useSplitMessageActionSet.ts
903
+ var import_react22 = require("react");
904
+ var useSplitMessageActionSet = (messageActionSet) => (0, import_react22.useMemo)(() => {
905
+ const quickActionSet = [];
906
+ const dropdownActionSet = [];
907
+ for (const action of messageActionSet) {
908
+ if (action.placement === "quick") quickActionSet.push(action);
909
+ if (action.placement === "dropdown") dropdownActionSet.push(action);
910
+ }
911
+ return { dropdownActionSet, quickActionSet };
912
+ }, [messageActionSet]);
913
+
914
+ // src/experimental/MessageActions/defaults.tsx
915
+ var import_react23 = __toESM(require("react"));
916
+ var DefaultDropdownActionButton = ({
917
+ "aria-selected": ariaSelected = "false",
918
+ children,
919
+ className = "str-chat__message-actions-list-item-button",
920
+ role = "option",
921
+ ...rest
922
+ }) => /* @__PURE__ */ import_react23.default.createElement("button", { "aria-selected": ariaSelected, className, role, ...rest }, children);
923
+ var DefaultMessageActionComponents = {
924
+ dropdown: {
925
+ Quote() {
926
+ const { setQuotedMessage } = useChannelActionContext();
927
+ const { message } = useMessageContext();
928
+ const { t } = useTranslationContext();
929
+ const handleQuote = () => {
930
+ setQuotedMessage(message);
931
+ const elements = message.parent_id ? document.querySelectorAll(".str-chat__thread .str-chat__textarea__textarea") : document.getElementsByClassName("str-chat__textarea__textarea");
932
+ const textarea = elements.item(0);
933
+ if (textarea instanceof HTMLTextAreaElement) {
934
+ textarea.focus();
935
+ }
936
+ };
937
+ return /* @__PURE__ */ import_react23.default.createElement(DefaultDropdownActionButton, { onClick: handleQuote }, t("Quote"));
938
+ },
939
+ Pin() {
940
+ const { handlePin, message } = useMessageContext();
941
+ const { t } = useTranslationContext();
942
+ return /* @__PURE__ */ import_react23.default.createElement(DefaultDropdownActionButton, { onClick: handlePin }, !message.pinned ? t("Pin") : t("Unpin"));
943
+ },
944
+ MarkUnread() {
945
+ const { handleMarkUnread } = useMessageContext();
946
+ const { t } = useTranslationContext();
947
+ return /* @__PURE__ */ import_react23.default.createElement(DefaultDropdownActionButton, { onClick: handleMarkUnread }, t("Mark as unread"));
948
+ },
949
+ Flag() {
950
+ const { handleFlag } = useMessageContext();
951
+ const { t } = useTranslationContext();
952
+ return /* @__PURE__ */ import_react23.default.createElement(DefaultDropdownActionButton, { onClick: handleFlag }, t("Flag"));
953
+ },
954
+ Mute() {
955
+ const { handleMute, message } = useMessageContext();
956
+ const { mutes } = useChatContext();
957
+ const { t } = useTranslationContext();
958
+ return /* @__PURE__ */ import_react23.default.createElement(DefaultDropdownActionButton, { onClick: handleMute }, isUserMuted(message, mutes) ? t("Unmute") : t("Mute"));
959
+ },
960
+ Edit() {
961
+ const { handleEdit } = useMessageContext();
962
+ const { t } = useTranslationContext();
963
+ return /* @__PURE__ */ import_react23.default.createElement(DefaultDropdownActionButton, { onClick: handleEdit }, t("Edit Message"));
964
+ },
965
+ Delete() {
966
+ const { handleDelete } = useMessageContext();
967
+ const { t } = useTranslationContext();
968
+ return /* @__PURE__ */ import_react23.default.createElement(DefaultDropdownActionButton, { onClick: handleDelete }, t("Delete"));
969
+ }
970
+ },
971
+ quick: {
972
+ React() {
973
+ return /* @__PURE__ */ import_react23.default.createElement(ReactionSelectorWithButton, { ReactionIcon });
974
+ },
975
+ Reply() {
976
+ const { handleOpenThread } = useMessageContext();
977
+ const { t } = useTranslationContext();
978
+ return /* @__PURE__ */ import_react23.default.createElement(
979
+ "button",
980
+ {
981
+ "aria-label": t("aria/Open Thread"),
982
+ className: "str-chat__message-reply-in-thread-button",
983
+ "data-testid": "thread-action",
984
+ onClick: handleOpenThread
985
+ },
986
+ /* @__PURE__ */ import_react23.default.createElement(ThreadIcon, { className: "str-chat__message-action-icon" })
987
+ );
988
+ }
989
+ }
990
+ };
991
+ var defaultMessageActionSet = [
992
+ // { placement: 'dropdown', type: 'block' },
993
+ { Component: DefaultMessageActionComponents.quick.Reply, placement: "quick", type: "reply" },
994
+ { Component: DefaultMessageActionComponents.quick.React, placement: "quick", type: "react" },
995
+ {
996
+ Component: DefaultMessageActionComponents.dropdown.Delete,
997
+ placement: "dropdown",
998
+ type: "delete"
999
+ },
1000
+ { Component: DefaultMessageActionComponents.dropdown.Edit, placement: "dropdown", type: "edit" },
1001
+ { Component: DefaultMessageActionComponents.dropdown.Mute, placement: "dropdown", type: "mute" },
1002
+ { Component: DefaultMessageActionComponents.dropdown.Flag, placement: "dropdown", type: "flag" },
1003
+ { Component: DefaultMessageActionComponents.dropdown.Pin, placement: "dropdown", type: "pin" },
1004
+ {
1005
+ Component: DefaultMessageActionComponents.dropdown.Quote,
1006
+ placement: "dropdown",
1007
+ type: "quote"
1008
+ },
1009
+ {
1010
+ Component: DefaultMessageActionComponents.dropdown.MarkUnread,
1011
+ placement: "dropdown",
1012
+ type: "markUnread"
1013
+ }
1014
+ ];
1015
+
1016
+ // src/experimental/MessageActions/MessageActions.tsx
1017
+ var MessageActions = ({
1018
+ disableBaseMessageActionSetFilter = false,
1019
+ messageActionSet = defaultMessageActionSet
1020
+ }) => {
1021
+ const { theme } = useChatContext();
1022
+ const { isMyMessage, message } = useMessageContext();
1023
+ const { t } = useTranslationContext();
1024
+ const [actionsBoxButtonElement, setActionsBoxButtonElement] = (0, import_react24.useState)(
1025
+ null
1026
+ );
1027
+ const filteredMessageActionSet = useBaseMessageActionSetFilter(
1028
+ messageActionSet,
1029
+ disableBaseMessageActionSetFilter
1030
+ );
1031
+ const { dropdownActionSet, quickActionSet } = useSplitMessageActionSet(filteredMessageActionSet);
1032
+ const dropdownDialogId = `message-actions--${message.id}`;
1033
+ const reactionSelectorDialogId = `reaction-selector--${message.id}`;
1034
+ const dialog = useDialog({ id: dropdownDialogId });
1035
+ const dropdownDialogIsOpen = useDialogIsOpen(dropdownDialogId);
1036
+ const reactionSelectorDialogIsOpen = useDialogIsOpen(reactionSelectorDialogId);
1037
+ if (dropdownActionSet.length + quickActionSet.length === 0) {
1038
+ return null;
1039
+ }
1040
+ return /* @__PURE__ */ import_react24.default.createElement(
1041
+ "div",
1042
+ {
1043
+ className: (0, import_clsx5.default)(`str-chat__message-${theme}__actions str-chat__message-options`, {
1044
+ "str-chat__message-options--active": dropdownDialogIsOpen || reactionSelectorDialogIsOpen
1045
+ })
1046
+ },
1047
+ dropdownActionSet.length > 0 && /* @__PURE__ */ import_react24.default.createElement(MessageActionsWrapper, { inline: false, toggleOpen: dialog?.toggle }, /* @__PURE__ */ import_react24.default.createElement(
1048
+ "button",
1049
+ {
1050
+ "aria-expanded": dropdownDialogIsOpen,
1051
+ "aria-haspopup": "true",
1052
+ "aria-label": t("aria/Open Message Actions Menu"),
1053
+ className: "str-chat__message-actions-box-button",
1054
+ "data-testid": "message-actions-toggle-button",
1055
+ ref: setActionsBoxButtonElement
1056
+ },
1057
+ /* @__PURE__ */ import_react24.default.createElement(ActionsIcon, { className: "str-chat__message-action-icon" })
1058
+ ), /* @__PURE__ */ import_react24.default.createElement(
1059
+ DialogAnchor,
1060
+ {
1061
+ id: dropdownDialogId,
1062
+ placement: isMyMessage() ? "top-end" : "top-start",
1063
+ referenceElement: actionsBoxButtonElement,
1064
+ trapFocus: true
1065
+ },
1066
+ /* @__PURE__ */ import_react24.default.createElement(DropdownBox, { open: dropdownDialogIsOpen }, dropdownActionSet.map(({ Component: DropdownActionComponent, type }) => /* @__PURE__ */ import_react24.default.createElement(DropdownActionComponent, { key: type })))
1067
+ )),
1068
+ quickActionSet.map(({ Component: QuickActionComponent, type }) => /* @__PURE__ */ import_react24.default.createElement(QuickActionComponent, { key: type }))
1069
+ );
1070
+ };
1071
+ var DropdownBox = ({ children, open }) => {
1072
+ const { t } = useTranslationContext();
1073
+ return /* @__PURE__ */ import_react24.default.createElement(
1074
+ "div",
1075
+ {
1076
+ className: (0, import_clsx5.default)("str-chat__message-actions-box", {
1077
+ "str-chat__message-actions-box--open": open
1078
+ })
1079
+ },
1080
+ /* @__PURE__ */ import_react24.default.createElement(
1081
+ "div",
1082
+ {
1083
+ "aria-label": t("aria/Message Options"),
1084
+ className: "str-chat__message-actions-list",
1085
+ role: "listbox"
1086
+ },
1087
+ children
1088
+ )
1089
+ );
1090
+ };
1091
+ //# sourceMappingURL=index.browser.cjs.map