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.
- package/dist/components/Channel/Channel.d.ts +1 -1
- package/dist/components/Channel/Channel.js +2 -0
- package/dist/components/ChatAutoComplete/ChatAutoComplete.d.ts +1 -1
- package/dist/components/Message/MessageOptions.js +1 -1
- package/dist/components/Message/MessageSimple.js +5 -2
- package/dist/components/Message/utils.d.ts +1 -1
- package/dist/components/MessageActions/MessageActions.d.ts +2 -1
- package/dist/components/MessageActions/MessageActions.js +1 -1
- package/dist/components/Reactions/ReactionSelectorWithButton.d.ts +1 -2
- package/dist/components/Reactions/ReactionSelectorWithButton.js +2 -2
- package/dist/components/Threads/hooks/useThreadManagerState.js +1 -1
- package/dist/context/ComponentContext.d.ts +7 -1
- package/dist/experimental/MessageActions/MessageActions.d.ts +17 -0
- package/dist/experimental/MessageActions/MessageActions.js +48 -0
- package/dist/experimental/MessageActions/defaults.d.ts +5 -0
- package/dist/experimental/MessageActions/defaults.js +93 -0
- package/dist/experimental/MessageActions/hooks/index.d.ts +2 -0
- package/dist/experimental/MessageActions/hooks/index.js +2 -0
- package/dist/experimental/MessageActions/hooks/useBaseMessageActionSetFilter.d.ts +8 -0
- package/dist/experimental/MessageActions/hooks/useBaseMessageActionSetFilter.js +57 -0
- package/dist/experimental/MessageActions/hooks/useSplitMessageActionSet.d.ts +5 -0
- package/dist/experimental/MessageActions/hooks/useSplitMessageActionSet.js +12 -0
- package/dist/experimental/MessageActions/index.d.ts +3 -0
- package/dist/experimental/MessageActions/index.js +3 -0
- package/dist/experimental/index.browser.cjs +1091 -0
- package/dist/experimental/index.browser.cjs.map +7 -0
- package/dist/experimental/index.d.ts +1 -0
- package/dist/experimental/index.js +1 -0
- package/dist/experimental/index.node.cjs +1099 -0
- package/dist/experimental/index.node.cjs.map +7 -0
- package/dist/i18n/Streami18n.d.ts +1 -0
- package/dist/i18n/de.json +1 -0
- package/dist/i18n/en.json +1 -0
- package/dist/i18n/es.json +1 -0
- package/dist/i18n/fr.json +1 -0
- package/dist/i18n/hi.json +1 -0
- package/dist/i18n/it.json +1 -0
- package/dist/i18n/ja.json +1 -0
- package/dist/i18n/ko.json +1 -0
- package/dist/i18n/nl.json +1 -0
- package/dist/i18n/pt.json +1 -0
- package/dist/i18n/ru.json +1 -0
- package/dist/i18n/tr.json +1 -0
- package/dist/index.browser.cjs +23 -6
- package/dist/index.browser.cjs.map +3 -3
- package/dist/index.node.cjs +24 -6
- package/dist/index.node.cjs.map +3 -3
- 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
|