@ermis-network/ermis-chat-react 1.0.9 → 2.0.1

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 (113) hide show
  1. package/README.md +144 -0
  2. package/dist/index.cjs +8320 -3427
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.css +1277 -291
  5. package/dist/index.css.map +1 -1
  6. package/dist/index.d.mts +1131 -99
  7. package/dist/index.d.ts +1131 -99
  8. package/dist/index.mjs +8168 -3319
  9. package/dist/index.mjs.map +1 -1
  10. package/package.json +9 -4
  11. package/src/channelTypeUtils.ts +1 -1
  12. package/src/components/Avatar.tsx +2 -1
  13. package/src/components/Channel.tsx +6 -5
  14. package/src/components/ChannelActions.tsx +67 -3
  15. package/src/components/ChannelHeader.tsx +27 -37
  16. package/src/components/ChannelInfo/AddMemberModal.tsx +12 -2
  17. package/src/components/ChannelInfo/ChannelInfo.tsx +410 -187
  18. package/src/components/ChannelInfo/ChannelInfoTabs.tsx +59 -297
  19. package/src/components/ChannelInfo/ChannelSettingsPanel.tsx +30 -174
  20. package/src/components/ChannelInfo/EditChannelModal.tsx +6 -3
  21. package/src/components/ChannelInfo/MediaGridItem.tsx +215 -68
  22. package/src/components/ChannelInfo/MemberListItem.tsx +2 -3
  23. package/src/components/ChannelInfo/MessageSearchPanel.tsx +27 -126
  24. package/src/components/ChannelInfo/States.tsx +1 -1
  25. package/src/components/ChannelInfo/index.ts +3 -0
  26. package/src/components/ChannelInfo/useChannelInfoTabs.tsx +427 -0
  27. package/src/components/ChannelInfo/useChannelSettings.ts +212 -0
  28. package/src/components/ChannelInfo/useMessageSearch.tsx +141 -0
  29. package/src/components/ChannelList.tsx +247 -301
  30. package/src/components/CreateChannelModal.tsx +290 -93
  31. package/src/components/Dropdown.tsx +1 -16
  32. package/src/components/EditPreview.tsx +1 -0
  33. package/src/components/ErmisCallProvider.tsx +72 -17
  34. package/src/components/ErmisCallUI.tsx +43 -20
  35. package/src/components/FilesPreview.tsx +8 -12
  36. package/src/components/FlatTopicGroupItem.tsx +243 -0
  37. package/src/components/ForwardMessageModal.tsx +43 -81
  38. package/src/components/MediaLightbox.tsx +454 -292
  39. package/src/components/MentionSuggestions.tsx +47 -35
  40. package/src/components/MessageActionsBox.tsx +6 -1
  41. package/src/components/MessageInput.tsx +165 -17
  42. package/src/components/MessageInputDefaults.tsx +127 -1
  43. package/src/components/MessageItem.tsx +155 -43
  44. package/src/components/MessageQuickReactions.tsx +153 -23
  45. package/src/components/MessageReactions.tsx +49 -3
  46. package/src/components/MessageRenderers.tsx +1114 -445
  47. package/src/components/Panel.tsx +1 -14
  48. package/src/components/PinnedMessages.tsx +55 -15
  49. package/src/components/PreviewOverlay.tsx +24 -0
  50. package/src/components/QuotedMessagePreview.tsx +99 -8
  51. package/src/components/ReadReceipts.tsx +2 -1
  52. package/src/components/RecoveryPin/RecoveryPin.tsx +279 -0
  53. package/src/components/RecoveryPin/index.ts +19 -0
  54. package/src/components/TopicList.tsx +236 -0
  55. package/src/components/TopicModal.tsx +4 -1
  56. package/src/components/TypingIndicator.tsx +17 -8
  57. package/src/components/UserPicker.tsx +94 -16
  58. package/src/components/VirtualMessageList.tsx +419 -113
  59. package/src/context/ChatComponentsContext.tsx +14 -0
  60. package/src/context/ChatProvider.tsx +44 -14
  61. package/src/context/ErmisCallContext.tsx +4 -0
  62. package/src/hooks/useChannelCapabilities.ts +7 -4
  63. package/src/hooks/useChannelData.ts +10 -3
  64. package/src/hooks/useChannelListUpdates.ts +94 -21
  65. package/src/hooks/useChannelMessages.ts +391 -42
  66. package/src/hooks/useChannelRowUpdates.ts +36 -5
  67. package/src/hooks/useChatUser.ts +39 -0
  68. package/src/hooks/useContactChannels.ts +45 -0
  69. package/src/hooks/useContactCount.ts +50 -0
  70. package/src/hooks/useDownloadHandler.ts +36 -0
  71. package/src/hooks/useDragAndDrop.ts +79 -0
  72. package/src/hooks/useE2eeAttachmentRenderer.ts +204 -0
  73. package/src/hooks/useE2eeFileUpload.ts +38 -0
  74. package/src/hooks/useFileUpload.ts +25 -5
  75. package/src/hooks/useForwardMessage.ts +309 -0
  76. package/src/hooks/useInviteChannels.ts +88 -0
  77. package/src/hooks/useInviteCount.ts +104 -0
  78. package/src/hooks/useLoadMessages.ts +16 -4
  79. package/src/hooks/useMentions.ts +60 -7
  80. package/src/hooks/useMessageActions.ts +19 -10
  81. package/src/hooks/useMessageSend.ts +64 -12
  82. package/src/hooks/usePendingE2eeSends.ts +29 -0
  83. package/src/hooks/usePendingState.ts +21 -4
  84. package/src/hooks/usePreviewState.ts +69 -0
  85. package/src/hooks/useRecoveryPin.ts +287 -0
  86. package/src/hooks/useScrollToMessage.ts +29 -4
  87. package/src/hooks/useStickerPicker.ts +62 -0
  88. package/src/hooks/useTopicGroupUpdates.ts +235 -0
  89. package/src/index.ts +79 -6
  90. package/src/messageTypeUtils.ts +27 -1
  91. package/src/styles/_base.css +0 -1
  92. package/src/styles/_call-ui.css +59 -2
  93. package/src/styles/_channel-info.css +50 -4
  94. package/src/styles/_channel-list.css +131 -68
  95. package/src/styles/_create-channel-modal.css +10 -0
  96. package/src/styles/_forward-modal.css +16 -1
  97. package/src/styles/_media-lightbox.css +67 -2
  98. package/src/styles/_mentions.css +1 -1
  99. package/src/styles/_message-actions.css +3 -4
  100. package/src/styles/_message-bubble.css +631 -112
  101. package/src/styles/_message-input.css +139 -0
  102. package/src/styles/_message-list.css +91 -18
  103. package/src/styles/_message-quick-reactions.css +105 -32
  104. package/src/styles/_message-reactions.css +22 -32
  105. package/src/styles/_modal.css +2 -1
  106. package/src/styles/_preview-overlay.css +38 -0
  107. package/src/styles/_recovery-pin.css +97 -0
  108. package/src/styles/_tokens.css +22 -20
  109. package/src/styles/_typing-indicator.css +26 -10
  110. package/src/styles/index.css +2 -0
  111. package/src/types.ts +477 -15
  112. package/src/utils/avatarColors.ts +48 -0
  113. package/src/utils.ts +219 -16
@@ -6,25 +6,23 @@
6
6
  padding: var(--ermis-spacing-xs) var(--ermis-spacing-sm);
7
7
  border-left: 3px solid var(--ermis-accent);
8
8
  background-color: var(--ermis-quote-other-bg);
9
- border-radius: 0 var(--ermis-radius-sm) var(--ermis-radius-sm) 0;
9
+ border-radius: var(--ermis-radius-sm);
10
10
  cursor: pointer;
11
11
  max-width: 100%;
12
12
  transition: background-color 0.15s;
13
- margin-top: var(--ermis-spacing-sm);
14
13
  }
15
14
 
16
15
  .ermis-quoted-message:hover {
17
16
  background-color: var(--ermis-quote-other-bg-hover);
18
17
  }
19
18
 
20
- .ermis-quoted-message--own {
21
- border-left-color: var(--ermis-quote-own-border);
22
- background-color: var(--ermis-quote-own-bg);
23
- border-radius: var(--ermis-radius-sm);
19
+ .ermis-quoted-message--unavailable {
20
+ border-left-color: var(--ermis-text-muted);
21
+ background-color: var(--ermis-bg-hover);
24
22
  }
25
23
 
26
- .ermis-quoted-message--own:hover {
27
- background-color: var(--ermis-quote-own-bg-hover);
24
+ .ermis-quoted-message--unavailable:hover {
25
+ background-color: var(--ermis-bg-hover);
28
26
  }
29
27
 
30
28
  .ermis-quoted-message__author {
@@ -33,8 +31,8 @@
33
31
  color: var(--ermis-accent);
34
32
  }
35
33
 
36
- .ermis-quoted-message--own .ermis-quoted-message__author {
37
- color: var(--ermis-quote-own-author);
34
+ .ermis-quoted-message--unavailable .ermis-quoted-message__author {
35
+ color: var(--ermis-text-muted);
38
36
  }
39
37
 
40
38
  .ermis-quoted-message__text {
@@ -45,22 +43,25 @@
45
43
  white-space: nowrap;
46
44
  }
47
45
 
48
- .ermis-quoted-message--own .ermis-quoted-message__text {
49
- color: var(--ermis-quote-own-text);
46
+ .ermis-quoted-message--unavailable .ermis-quoted-message__text {
47
+ font-style: italic;
50
48
  }
51
49
 
52
50
  /* Light theme: same approach works since we darken the accent bg */
53
51
 
54
- /* Avatar column: fixed width for consistent alignment */
52
+ /* Avatar column: fixed width for consistent alignment + sticky for long messages */
55
53
  .ermis-message-list__item-avatar {
56
54
  flex-shrink: 0;
55
+ position: sticky;
56
+ bottom: 0;
57
+ align-self: flex-end;
57
58
  }
58
59
 
59
60
  .ermis-message-list__item-content {
60
61
  display: flex;
61
62
  flex-direction: column;
62
63
  min-width: 0;
63
- max-width: 75%;
64
+ max-width: 100%;
64
65
  gap: 2px;
65
66
  }
66
67
 
@@ -70,40 +71,54 @@
70
71
 
71
72
  .ermis-message-list__bubble-wrapper {
72
73
  display: flex;
73
- flex-wrap: wrap;
74
- flex-direction: row;
75
- align-items: center; /* Center actions vertically with the bubble */
74
+ flex-direction: column;
75
+ align-items: flex-start;
76
76
  position: relative;
77
77
  width: 100%;
78
78
  }
79
79
 
80
80
  .ermis-message-list__item--own .ermis-message-list__bubble-wrapper {
81
- flex-direction: row-reverse;
81
+ align-items: flex-end;
82
82
  }
83
83
 
84
84
  .ermis-message-list__item-user {
85
- font-size: var(--ermis-font-size-xs);
85
+ font-size: var(--ermis-font-size-sm);
86
86
  font-weight: 600;
87
87
  color: var(--ermis-accent);
88
88
  margin-bottom: 1px;
89
89
  }
90
90
 
91
- /* Timestamp inside bubble — bottom right */
91
+ .ermis-message-list__item-user--clickable {
92
+ cursor: pointer;
93
+ transition: opacity 0.2s;
94
+ }
95
+
96
+ .ermis-message-list__item-user--clickable:hover {
97
+ opacity: 0.7;
98
+ }
99
+
100
+ /* Timestamp inside bubble — inline float (WhatsApp-style) */
92
101
  .ermis-message-list__item-time {
93
- font-size: 0.625rem;
102
+ font-size: 0.6875rem;
94
103
  color: var(--ermis-text-muted);
95
- margin-left: auto;
96
- padding-left: var(--ermis-spacing-md);
97
104
  white-space: nowrap;
98
105
  line-height: 1;
99
- align-self: flex-end;
100
- padding-top: 4px;
101
- width: 100%;
102
- text-align: right;
103
106
  display: inline-flex;
104
107
  align-items: center;
105
- justify-content: flex-end;
106
- gap: 3px;
108
+ gap: 2px;
109
+ float: right;
110
+ margin-left: 6px;
111
+ margin-top: 4px;
112
+ position: relative;
113
+ }
114
+
115
+ /* Invisible spacer at end of text — ONLY when time is shown (sibling selector) */
116
+ .ermis-message-list__item-time ~ .ermis-message-list__item-text::after,
117
+ .ermis-message-list__item-time ~ * .ermis-message-list__item-text::after {
118
+ content: '';
119
+ display: inline-block;
120
+ width: 15px;
121
+ height: 0;
107
122
  }
108
123
 
109
124
  .ermis-message-list__edited-indicator {
@@ -142,27 +157,83 @@
142
157
  color: var(--ermis-color-danger);
143
158
  }
144
159
 
160
+ .ermis-attachment-upload-overlay {
161
+ position: absolute;
162
+ inset: 0;
163
+ z-index: 3;
164
+ display: inline-flex;
165
+ flex-direction: column;
166
+ align-items: center;
167
+ justify-content: center;
168
+ gap: 6px;
169
+ color: #fff;
170
+ font-size: 12px;
171
+ font-weight: 700;
172
+ line-height: 1;
173
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.36);
174
+ background: rgba(17, 24, 39, 0.34);
175
+ pointer-events: none;
176
+ }
177
+
178
+ .ermis-voice-upload-wrap {
179
+ position: relative;
180
+ }
181
+
182
+ .ermis-voice-upload-progress {
183
+ position: absolute;
184
+ top: -6px;
185
+ right: -6px;
186
+ min-width: 30px;
187
+ padding: 3px 6px;
188
+ border-radius: 999px;
189
+ background: rgba(17, 24, 39, 0.72);
190
+ color: #fff;
191
+ font-size: 11px;
192
+ font-weight: 700;
193
+ line-height: 1;
194
+ }
195
+
145
196
  .ermis-message-bubble--own .ermis-message-list__item-time {
146
- color: rgba(255, 255, 255, 0.6);
197
+ color: var(--ermis-bubble-own-text);
198
+ opacity: 0.6;
199
+ }
200
+
201
+ .ermis-message-bubble--own .ermis-message-list__item-time ~ .ermis-message-list__item-text::after,
202
+ .ermis-message-bubble--own .ermis-message-list__item-time ~ * .ermis-message-list__item-text::after {
203
+ width: 30px;
147
204
  }
148
205
 
149
206
  .ermis-message-list__item-text {
150
207
  font-size: var(--ermis-font-size-sm);
151
208
  line-height: 1.5;
152
209
  word-break: break-word;
210
+ white-space: pre-wrap;
153
211
  }
154
212
 
155
213
  /* --- Mentions --- */
156
214
  .ermis-mention {
157
215
  color: var(--ermis-accent);
158
216
  font-weight: 600;
217
+ cursor: default;
218
+ background-color: rgba(0, 122, 255, 0.1);
219
+ padding: 2px 6px;
220
+ border-radius: 4px;
221
+ margin: 0 1px;
222
+ }
223
+
224
+ .ermis-mention--clickable {
159
225
  cursor: pointer;
226
+ transition: opacity 0.2s;
227
+ }
228
+
229
+ .ermis-mention--clickable:hover {
230
+ opacity: 0.8;
160
231
  }
161
232
 
162
233
  .ermis-message-bubble--own .ermis-mention {
163
234
  color: rgba(255, 255, 255, 0.9);
164
- text-decoration: underline;
165
- text-underline-offset: 2px;
235
+ background-color: rgba(255, 255, 255, 0.2);
236
+ text-decoration: none;
166
237
  }
167
238
 
168
239
  /* Auto-detected URLs/emails in message text */
@@ -179,53 +250,143 @@
179
250
  }
180
251
 
181
252
  .ermis-message-bubble--own .ermis-text-link {
182
- color: rgba(255, 255, 255, 0.9);
253
+ color: var(--ermis-bubble-own-text);
254
+ text-decoration: underline;
183
255
  }
184
256
 
185
257
  .ermis-message-bubble--own .ermis-attachment__link-title {
186
- color: rgba(255, 255, 255, 0.9);
258
+ color: var(--ermis-bubble-own-text);
187
259
  }
188
260
 
189
261
  /* --- Message Bubble --- */
190
262
  .ermis-message-bubble {
191
263
  position: relative;
192
- display: flex;
193
- flex-wrap: wrap;
194
- align-items: flex-end;
195
- padding: var(--ermis-spacing-sm) var(--ermis-spacing-md);
264
+ display: flow-root;
265
+ /* contains floats, allowing bottom-right time alignment */
266
+ padding: 8px 10px;
196
267
  border-radius: var(--ermis-radius-lg);
197
268
  /* width: 100%; */
198
269
  word-break: break-word;
270
+ overflow: visible;
199
271
  }
200
272
 
201
273
  .ermis-message-bubble--own {
202
274
  background-color: var(--ermis-bubble-own-bg);
203
275
  color: var(--ermis-bubble-own-text);
204
- border-bottom-right-radius: var(--ermis-radius-sm);
276
+ border-color: var(--ermis-bubble-own-bg);
205
277
  }
206
278
 
207
- /* --- Override muted text inside own bubble (unreadable on accent bg in dark mode) --- */
279
+ /* Text selection inside own bubble: white bg + black text for readability */
280
+ .ermis-message-bubble--own ::selection {
281
+ background-color: rgba(255, 255, 255, 0.9);
282
+ color: #111827;
283
+ }
284
+
285
+ .ermis-message-bubble--own::selection {
286
+ background-color: rgba(255, 255, 255, 0.9);
287
+ color: #111827;
288
+ }
289
+
290
+ /* --- Override muted text inside own bubble --- */
208
291
  .ermis-message-bubble--own .ermis-attachment__file-size,
209
292
  .ermis-message-bubble--own .ermis-attachment__link-url,
210
293
  .ermis-message-bubble--own .ermis-attachment__link-description,
211
294
  .ermis-message-bubble--own .ermis-attachment__voice-duration,
212
- .ermis-message-bubble--own .ermis-message-list__forwarded-indicator,
213
- .ermis-message-bubble--own .ermis-attachment--file {
214
- color: rgba(255, 255, 255, 0.6);
295
+ .ermis-message-bubble--own .ermis-message-list__forwarded-indicator {
296
+ color: var(--ermis-bubble-own-text);
297
+ opacity: 0.8;
215
298
  }
216
299
 
217
300
  .ermis-message-bubble--own .ermis-attachment--link-preview {
218
- border-color: rgba(255, 255, 255, 0.2);
301
+ border-color: color-mix(in srgb, var(--ermis-bubble-own-text) 30%, transparent);
219
302
  }
220
303
 
221
304
  .ermis-message-bubble--own .ermis-attachment--file {
222
- background-color: rgba(255, 255, 255, 0.1);
305
+ background-color: color-mix(in srgb, var(--ermis-bubble-own-text) 10%, transparent);
306
+ color: var(--ermis-bubble-own-text);
223
307
  }
224
308
 
225
309
  .ermis-message-bubble--other {
226
310
  background-color: var(--ermis-bubble-other-bg);
227
311
  color: var(--ermis-bubble-other-text);
228
- border-bottom-left-radius: var(--ermis-radius-sm);
312
+ }
313
+
314
+ /* --- Dynamic Border Radius based on grouping --- */
315
+ /* Own messages (right side flat) */
316
+ .ermis-message-list__item--own.ermis-message-list__item--group-top .ermis-message-bubble {
317
+ border-bottom-right-radius: 4px;
318
+ }
319
+
320
+ .ermis-message-list__item--own.ermis-message-list__item--group-middle .ermis-message-bubble {
321
+ border-top-right-radius: 4px;
322
+ border-bottom-right-radius: 4px;
323
+ }
324
+
325
+ .ermis-message-list__item--own.ermis-message-list__item--group-bottom .ermis-message-bubble {
326
+ border-top-right-radius: 4px;
327
+ }
328
+
329
+ /* Other messages (left side flat) */
330
+ .ermis-message-list__item--other.ermis-message-list__item--group-top .ermis-message-bubble {
331
+ border-bottom-left-radius: 4px;
332
+ }
333
+
334
+ .ermis-message-list__item--other.ermis-message-list__item--group-middle .ermis-message-bubble {
335
+ border-top-left-radius: 4px;
336
+ border-bottom-left-radius: 4px;
337
+ }
338
+
339
+ .ermis-message-list__item--other.ermis-message-list__item--group-bottom .ermis-message-bubble {
340
+ border-top-left-radius: 4px;
341
+ border-bottom-left-radius: 0;
342
+ }
343
+
344
+ /* --- Pointed Tail (Telegram-style curved SVG) --- */
345
+ /* Tail for OTHER messages (left curved tail) — last in group */
346
+ .ermis-message-list__item--other.ermis-message-list__item--group-bottom .ermis-message-bubble::after,
347
+ .ermis-message-list__item--other.ermis-message-list__item--group-single .ermis-message-bubble::after {
348
+ content: '';
349
+ position: absolute;
350
+ bottom: 0px;
351
+ left: -9px;
352
+ width: 9px;
353
+ height: 17px;
354
+ background-color: var(--ermis-bubble-other-bg);
355
+ -webkit-mask-image: url("data:image/svg+xml,%3Csvg width='9' height='17' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M3 17h6V0c-.193 2.84-.876 5.767-2.05 8.782-.904 2.325-2.446 4.485-4.625 6.48A1 1 0 003 17z'/%3E%3C/svg%3E");
356
+ mask-image: url("data:image/svg+xml,%3Csvg width='9' height='17' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M3 17h6V0c-.193 2.84-.876 5.767-2.05 8.782-.904 2.325-2.446 4.485-4.625 6.48A1 1 0 003 17z'/%3E%3C/svg%3E");
357
+ -webkit-mask-size: 9px 17px;
358
+ mask-size: 9px 17px;
359
+ -webkit-mask-repeat: no-repeat;
360
+ mask-repeat: no-repeat;
361
+ }
362
+
363
+ /* Tail for OWN messages (right curved tail) — last in group */
364
+ .ermis-message-list__item--own.ermis-message-list__item--group-bottom .ermis-message-bubble::after,
365
+ .ermis-message-list__item--own.ermis-message-list__item--group-single .ermis-message-bubble::after {
366
+ content: '';
367
+ position: absolute;
368
+ bottom: 0px;
369
+ right: -9px;
370
+ width: 9px;
371
+ height: 17px;
372
+ background-color: var(--ermis-bubble-own-bg);
373
+ -webkit-mask-image: url("data:image/svg+xml,%3Csvg width='9' height='17' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6 17H0V0c.193 2.84.876 5.767 2.05 8.782.904 2.325 2.446 4.485 4.625 6.48A1 1 0 016 17z'/%3E%3C/svg%3E");
374
+ mask-image: url("data:image/svg+xml,%3Csvg width='9' height='17' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6 17H0V0c.193 2.84.876 5.767 2.05 8.782.904 2.325 2.446 4.485 4.625 6.48A1 1 0 016 17z'/%3E%3C/svg%3E");
375
+ -webkit-mask-size: 9px 17px;
376
+ mask-size: 9px 17px;
377
+ -webkit-mask-repeat: no-repeat;
378
+ mask-repeat: no-repeat;
379
+ }
380
+
381
+ /* Remove border-radius and border at tail corner for seamless connection */
382
+ .ermis-message-list__item--other.ermis-message-list__item--group-bottom .ermis-message-bubble,
383
+ .ermis-message-list__item--other.ermis-message-list__item--group-single .ermis-message-bubble {
384
+ border-bottom-left-radius: 0;
385
+ }
386
+
387
+ .ermis-message-list__item--own.ermis-message-list__item--group-bottom .ermis-message-bubble,
388
+ .ermis-message-list__item--own.ermis-message-list__item--group-single .ermis-message-bubble {
389
+ border-bottom-right-radius: 0;
229
390
  }
230
391
 
231
392
  /* --- System messages --- */
@@ -254,6 +415,7 @@
254
415
  border-radius: var(--ermis-radius-md);
255
416
  background-color: var(--ermis-signal-bg);
256
417
  min-width: 180px;
418
+ position: relative;
257
419
  }
258
420
 
259
421
  .ermis-signal-message__icon {
@@ -281,6 +443,8 @@
281
443
  flex-direction: column;
282
444
  gap: 1px;
283
445
  min-width: 0;
446
+ padding-right: 40px;
447
+ /* Space for timestamp */
284
448
  }
285
449
 
286
450
  .ermis-signal-message__text {
@@ -303,39 +467,26 @@
303
467
  line-height: 1.3;
304
468
  }
305
469
 
306
- /* Legacy class kept for backward compatibility */
307
- .ermis-message-list__signal-text {
308
- font-size: var(--ermis-font-size-sm);
309
- color: inherit;
310
- line-height: 1.5;
311
- word-break: break-word;
312
- }
313
-
314
- /* --- Signal message inside own bubble (accent bg) --- */
315
- .ermis-message-bubble--own .ermis-signal-message {
316
- background-color: var(--ermis-signal-own-bg);
317
- }
318
-
319
- .ermis-message-bubble--own .ermis-signal-message__icon--success {
320
- background-color: rgba(134, 239, 172, 0.2);
321
- color: var(--ermis-signal-own-success);
322
- }
323
-
324
- .ermis-message-bubble--own .ermis-signal-message__icon--missed {
325
- background-color: rgba(252, 165, 165, 0.2);
326
- color: var(--ermis-signal-own-missed);
327
- }
328
-
329
- .ermis-message-bubble--own .ermis-signal-message__text--success {
330
- color: var(--ermis-signal-own-success);
470
+ .ermis-signal-message__time {
471
+ position: absolute;
472
+ bottom: 8px;
473
+ right: 12px;
474
+ font-size: 10px;
475
+ color: var(--ermis-text-muted);
476
+ line-height: 1;
331
477
  }
332
478
 
333
- .ermis-message-bubble--own .ermis-signal-message__text--missed {
334
- color: var(--ermis-signal-own-missed);
479
+ /* --- Signal Message Overrides --- */
480
+ .ermis-message-list__item--signal .ermis-message-bubble {
481
+ background: transparent !important;
482
+ box-shadow: none !important;
483
+ padding: 0 !important;
484
+ border: none !important;
335
485
  }
336
486
 
337
- .ermis-message-bubble--own .ermis-signal-message__duration {
338
- color: var(--ermis-signal-own-duration);
487
+ /* No tail on signal messages */
488
+ .ermis-message-list__item--signal .ermis-message-bubble::after {
489
+ display: none;
339
490
  }
340
491
 
341
492
  /* --- Attachments --- */
@@ -349,11 +500,27 @@
349
500
  width: 100%;
350
501
  }
351
502
 
503
+ .ermis-message-list__item-content--has-attachments:has(.ermis-message-content--with-e2ee-attachments) {
504
+ width: fit-content;
505
+ max-width: min(86vw, 350px);
506
+ }
507
+
508
+ .ermis-message-list__item-content--has-attachments:has(.ermis-message-content--with-e2ee-attachments)
509
+ .ermis-message-bubble {
510
+ width: auto;
511
+ max-width: 100%;
512
+ }
513
+
352
514
  /* Container for messages with both text + attachments */
353
515
  .ermis-message-content--with-attachments {
354
516
  display: flex;
355
517
  flex-direction: column;
356
518
  width: 100%;
519
+ max-width: 100%;
520
+ }
521
+
522
+ .ermis-message-content--with-e2ee-attachments {
523
+ width: fit-content;
357
524
  }
358
525
 
359
526
  .ermis-message-content--with-attachments .ermis-message-list__item-text {
@@ -367,6 +534,11 @@
367
534
  gap: var(--ermis-spacing-xs);
368
535
  margin-top: var(--ermis-spacing-xs);
369
536
  width: 100%;
537
+ max-width: 100%;
538
+ }
539
+
540
+ .ermis-message-content--with-e2ee-attachments .ermis-attachment-list {
541
+ width: fit-content;
370
542
  }
371
543
 
372
544
  /* Media grid (images + videos) */
@@ -442,7 +614,8 @@
442
614
  height: 100%;
443
615
  object-fit: cover;
444
616
  filter: blur(20px);
445
- transform: scale(1.1); /* hide blur edges */
617
+ transform: scale(1.1);
618
+ /* hide blur edges */
446
619
  z-index: 1;
447
620
  }
448
621
 
@@ -463,6 +636,7 @@
463
636
  0% {
464
637
  background-position: 200% 0;
465
638
  }
639
+
466
640
  100% {
467
641
  background-position: -200% 0;
468
642
  }
@@ -609,58 +783,310 @@
609
783
  color: var(--ermis-accent);
610
784
  }
611
785
 
786
+ .ermis-attachment--e2ee {
787
+ width: min(320px, calc(100vw - 96px));
788
+ min-width: 220px;
789
+ max-width: 320px;
790
+ border: 1px solid color-mix(in srgb, var(--ermis-accent) 20%, transparent);
791
+ }
792
+
793
+ .ermis-e2ee-attachment__open {
794
+ padding: 0;
795
+ border: 0;
796
+ background: transparent;
797
+ color: inherit;
798
+ text-align: left;
799
+ cursor: pointer;
800
+ }
801
+
802
+ .ermis-e2ee-attachment__open:disabled,
803
+ .ermis-attachment__file-download:disabled {
804
+ cursor: wait;
805
+ opacity: 0.6;
806
+ }
807
+
808
+ .ermis-e2ee-attachment-media {
809
+ display: flex;
810
+ flex-direction: column;
811
+ gap: var(--ermis-spacing-xs);
812
+ width: fit-content;
813
+ max-width: min(100%, 340px);
814
+ }
815
+
816
+ .ermis-e2ee-attachment-media .ermis-attachment-aspect-box {
817
+ max-width: 100%;
818
+ }
819
+
820
+ .ermis-e2ee-attachment-placeholder {
821
+ padding: 0;
822
+ border: 0;
823
+ color: var(--ermis-text-primary);
824
+ cursor: pointer;
825
+ }
826
+
827
+ .ermis-e2ee-attachment-placeholder:disabled {
828
+ cursor: wait;
829
+ }
830
+
831
+ .ermis-e2ee-attachment-placeholder__center {
832
+ position: absolute;
833
+ inset: 0;
834
+ z-index: 3;
835
+ display: flex;
836
+ flex-direction: column;
837
+ align-items: center;
838
+ justify-content: center;
839
+ gap: 6px;
840
+ padding: var(--ermis-spacing-md);
841
+ text-align: center;
842
+ }
843
+
844
+ .ermis-e2ee-attachment-placeholder__icon {
845
+ display: flex;
846
+ align-items: center;
847
+ justify-content: center;
848
+ width: 44px;
849
+ height: 44px;
850
+ border-radius: var(--ermis-radius-full);
851
+ background: color-mix(in srgb, var(--ermis-accent) 14%, var(--ermis-bg-secondary));
852
+ color: var(--ermis-accent);
853
+ }
854
+
855
+ .ermis-e2ee-attachment-placeholder__title {
856
+ max-width: 100%;
857
+ overflow: hidden;
858
+ color: var(--ermis-text-primary);
859
+ font-size: var(--ermis-font-size-sm);
860
+ font-weight: 600;
861
+ text-overflow: ellipsis;
862
+ white-space: nowrap;
863
+ }
864
+
865
+ .ermis-e2ee-attachment-placeholder__meta,
866
+ .ermis-e2ee-attachment-actions__label {
867
+ color: var(--ermis-text-muted);
868
+ font-size: var(--ermis-font-size-xs);
869
+ }
870
+
871
+ .ermis-e2ee-attachment-actions {
872
+ display: flex;
873
+ align-items: center;
874
+ justify-content: space-between;
875
+ gap: var(--ermis-spacing-xs);
876
+ width: 100%;
877
+ min-width: 0;
878
+ }
879
+
880
+ .ermis-e2ee-attachment-actions__label {
881
+ min-width: 0;
882
+ overflow: hidden;
883
+ text-overflow: ellipsis;
884
+ white-space: nowrap;
885
+ }
886
+
612
887
  .ermis-message-bubble--own .ermis-attachment__file-name {
613
- color: rgba(255, 255, 255, 0.9);
888
+ color: var(--ermis-bubble-own-text);
614
889
  }
615
890
 
616
891
  .ermis-message-bubble--own .ermis-attachment__file-icon {
617
- background: rgba(255, 255, 255, 0.2);
618
- color: #fff;
892
+ background: color-mix(in srgb, var(--ermis-bubble-own-text) 20%, transparent);
893
+ color: var(--ermis-bubble-own-text);
619
894
  }
620
895
 
621
896
  .ermis-message-bubble--own .ermis-attachment__file-ext {
622
- color: rgba(255, 255, 255, 0.8);
897
+ color: var(--ermis-bubble-own-text);
898
+ opacity: 0.8;
623
899
  }
624
900
 
625
901
  .ermis-message-bubble--own .ermis-attachment__file-download {
626
- color: rgba(255, 255, 255, 0.7);
902
+ color: var(--ermis-bubble-own-text);
903
+ opacity: 0.8;
627
904
  }
628
905
 
629
906
  .ermis-message-bubble--own .ermis-attachment__file-download:hover {
630
- background-color: rgba(255, 255, 255, 0.15);
631
- color: #fff;
907
+ background-color: color-mix(in srgb, var(--ermis-bubble-own-text) 15%, transparent);
908
+ color: inherit;
909
+ }
910
+
911
+ .ermis-message-bubble--own .ermis-attachment--e2ee {
912
+ border-color: color-mix(in srgb, var(--ermis-bubble-own-text) 25%, transparent);
913
+ }
914
+
915
+ .ermis-message-bubble--own .ermis-e2ee-attachment-placeholder,
916
+ .ermis-message-bubble--own .ermis-e2ee-attachment-placeholder__title {
917
+ color: var(--ermis-bubble-own-text);
918
+ }
919
+
920
+ .ermis-message-bubble--own .ermis-e2ee-attachment-placeholder__meta,
921
+ .ermis-message-bubble--own .ermis-e2ee-attachment-actions__label {
922
+ color: var(--ermis-bubble-own-text);
923
+ opacity: 0.8;
924
+ }
925
+
926
+ .ermis-message-bubble--own .ermis-e2ee-attachment-placeholder__icon {
927
+ background: color-mix(in srgb, var(--ermis-bubble-own-text) 20%, transparent);
928
+ color: var(--ermis-bubble-own-text);
632
929
  }
633
930
 
634
- /* --- Voice recording --- */
635
- .ermis-attachment--voice {
931
+ /* --- Custom Audio Player --- */
932
+ .ermis-custom-audio-player {
636
933
  display: flex;
637
934
  align-items: center;
638
935
  gap: var(--ermis-spacing-sm);
639
- padding: var(--ermis-spacing-sm) var(--ermis-spacing-md);
640
- border-radius: var(--ermis-radius-md);
641
- background-color: var(--ermis-bg-hover);
642
- overflow: hidden;
936
+ min-width: 240px;
643
937
  width: 100%;
644
- box-sizing: border-box;
645
938
  }
646
939
 
647
- .ermis-attachment__voice-icon {
648
- font-size: 1.25rem;
940
+ .ermis-e2ee-voice-attachment {
941
+ width: min(320px, calc(100vw - 96px));
942
+ max-width: 100%;
943
+ }
944
+
945
+ .ermis-e2ee-voice-attachment .ermis-custom-audio-player {
946
+ width: min(320px, calc(100vw - 96px));
947
+ min-width: 260px;
948
+ max-width: 100%;
949
+ }
950
+
951
+ .ermis-custom-audio-player--placeholder {
952
+ padding: 0;
953
+ border: 0;
954
+ background: transparent;
955
+ color: inherit;
956
+ cursor: pointer;
957
+ }
958
+
959
+ .ermis-custom-audio-player--placeholder:disabled {
960
+ cursor: wait;
961
+ }
962
+
963
+ .ermis-custom-audio-play-btn {
964
+ display: flex;
965
+ align-items: center;
966
+ justify-content: center;
967
+ width: 36px;
968
+ height: 36px;
969
+ border-radius: 50%;
970
+ background-color: var(--ermis-accent);
971
+ border: none;
972
+ cursor: pointer;
973
+ color: white;
974
+ /* solid white icon */
649
975
  flex-shrink: 0;
976
+ transition: opacity 0.2s, transform 0.1s;
977
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
978
+ }
979
+
980
+ .ermis-custom-audio-play-btn:hover {
981
+ opacity: 0.9;
982
+ }
983
+
984
+ .ermis-custom-audio-play-btn:active {
985
+ transform: scale(0.95);
650
986
  }
651
987
 
652
- .ermis-attachment__voice-player {
988
+ .ermis-message-bubble--own .ermis-custom-audio-play-btn {
989
+ background-color: var(--ermis-bubble-own-text);
990
+ color: var(--ermis-accent);
991
+ }
992
+
993
+ .ermis-custom-audio-progress-container {
653
994
  flex: 1;
654
- min-width: 0;
995
+ display: flex;
996
+ align-items: center;
997
+ height: 24px;
998
+ padding: 0 6px;
999
+ /* prevent thumb cutoff */
1000
+ }
1001
+
1002
+ .ermis-custom-audio-progress-bg {
1003
+ position: relative;
655
1004
  width: 100%;
656
- max-width: 100%;
657
- height: 32px;
1005
+ height: 4px;
1006
+ background-color: rgba(0, 0, 0, 0.1);
1007
+ border-radius: 2px;
1008
+ cursor: pointer;
658
1009
  }
659
1010
 
660
- .ermis-attachment__voice-duration {
661
- font-size: var(--ermis-font-size-xs);
662
- color: var(--ermis-text-muted);
1011
+ .ermis-message-bubble--own .ermis-custom-audio-progress-bg {
1012
+ background-color: rgba(255, 255, 255, 0.3);
1013
+ }
1014
+
1015
+ .ermis-custom-audio-progress-fill {
1016
+ position: absolute;
1017
+ top: 0;
1018
+ left: 0;
1019
+ height: 100%;
1020
+ background-color: var(--ermis-accent);
1021
+ border-radius: 2px;
1022
+ pointer-events: none;
1023
+ }
1024
+
1025
+ .ermis-message-bubble--own .ermis-custom-audio-progress-fill {
1026
+ background-color: var(--ermis-bubble-own-text);
1027
+ }
1028
+
1029
+ .ermis-custom-audio-progress-thumb {
1030
+ position: absolute;
1031
+ top: 50%;
1032
+ width: 12px;
1033
+ height: 12px;
1034
+ background-color: var(--ermis-accent);
1035
+ border-radius: 50%;
1036
+ transform: translate(-50%, -50%);
1037
+ pointer-events: none;
1038
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
1039
+ }
1040
+
1041
+ .ermis-message-bubble--own .ermis-custom-audio-progress-thumb {
1042
+ background-color: var(--ermis-bubble-own-text);
1043
+ }
1044
+
1045
+ .ermis-custom-audio-duration {
1046
+ font-size: var(--ermis-font-size-sm);
1047
+ color: var(--ermis-text-primary);
1048
+ font-weight: 500;
663
1049
  flex-shrink: 0;
1050
+ min-width: 32px;
1051
+ text-align: right;
1052
+ }
1053
+
1054
+ .ermis-message-bubble--own .ermis-custom-audio-duration {
1055
+ color: var(--ermis-bubble-own-text);
1056
+ }
1057
+
1058
+ .ermis-custom-audio-download-btn {
1059
+ display: flex;
1060
+ align-items: center;
1061
+ justify-content: center;
1062
+ width: 32px;
1063
+ height: 32px;
1064
+ border-radius: 50%;
1065
+ background: transparent;
1066
+ color: var(--ermis-colors-text-muted, #72767d);
1067
+ border: none;
1068
+ cursor: pointer;
1069
+ transition: background-color 0.2s, color 0.2s;
1070
+ flex-shrink: 0;
1071
+ margin-left: 8px;
1072
+ }
1073
+
1074
+ .ermis-custom-audio-download-btn:hover {
1075
+ background-color: var(--ermis-colors-bg-hover, rgba(0, 0, 0, 0.05));
1076
+ color: var(--ermis-colors-text-normal, #36393f);
1077
+ }
1078
+
1079
+ .ermis-message-bubble--own .ermis-custom-audio-download-btn {
1080
+ color: rgba(255, 255, 255, 0.8);
1081
+ }
1082
+
1083
+ .ermis-message-bubble--own .ermis-custom-audio-download-btn:hover {
1084
+ background-color: rgba(255, 255, 255, 0.15);
1085
+ color: #fff;
1086
+ }
1087
+
1088
+ .ermis-custom-audio-hidden {
1089
+ display: none;
664
1090
  }
665
1091
 
666
1092
  /* --- Link preview --- */
@@ -754,9 +1180,10 @@
754
1180
  /* --- Sticker message --- */
755
1181
  .ermis-message-sticker-wrapper {
756
1182
  position: relative;
757
- width: 120px;
758
- height: 120px;
1183
+ width: 160px;
1184
+ height: 160px;
759
1185
  overflow: hidden;
1186
+ border-radius: 10px;
760
1187
  }
761
1188
 
762
1189
  .ermis-message-sticker {
@@ -774,6 +1201,48 @@
774
1201
  opacity: 1;
775
1202
  }
776
1203
 
1204
+ /* --- Sticker Message Overrides --- */
1205
+ .ermis-message-list__item--sticker .ermis-message-bubble {
1206
+ background: transparent !important;
1207
+ box-shadow: none !important;
1208
+ padding: 0 !important;
1209
+ border: none !important;
1210
+ position: relative;
1211
+ border-radius: 0;
1212
+ display: inline-block;
1213
+ /* Ensure bubble shrinks to fit sticker */
1214
+ }
1215
+
1216
+ /* No tail on sticker messages */
1217
+ .ermis-message-list__item--sticker .ermis-message-bubble::after {
1218
+ display: none;
1219
+ }
1220
+
1221
+ /* Timestamp overlay for stickers */
1222
+ .ermis-message-list__item--sticker .ermis-message-list__item-time {
1223
+ position: absolute;
1224
+ bottom: 8px;
1225
+ right: 8px;
1226
+ color: #ffffff;
1227
+ padding: 2px 8px;
1228
+ border-radius: 12px;
1229
+ font-size: 11px;
1230
+ margin: 0;
1231
+ line-height: 1.2;
1232
+ font-weight: 500;
1233
+ text-shadow: 0px 1px 3px rgba(0, 0, 0, 0.8), 0px 0px 1px rgba(0, 0, 0, 0.6);
1234
+ }
1235
+
1236
+ /* Ensure edited indicator and inline status icon styling for sticker */
1237
+ .ermis-message-list__item--sticker .ermis-message-list__item-time .ermis-message-list__edited-indicator {
1238
+ color: rgba(255, 255, 255, 0.9);
1239
+ }
1240
+
1241
+ .ermis-message-list__item--sticker .ermis-message-list__item-time svg {
1242
+ color: #ffffff;
1243
+ filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.8));
1244
+ }
1245
+
777
1246
  /* --- Error message --- */
778
1247
  .ermis-message-error {
779
1248
  font-size: var(--ermis-font-size-sm);
@@ -784,16 +1253,25 @@
784
1253
  /* --- Read receipts --- */
785
1254
  .ermis-read-receipts {
786
1255
  display: flex;
787
- justify-content: flex-end;
788
1256
  width: 100%;
789
1257
  padding-top: 2px;
790
1258
  }
791
1259
 
1260
+ .ermis-read-receipts--own {
1261
+ justify-content: flex-end;
1262
+ }
1263
+
1264
+ .ermis-read-receipts--other {
1265
+ justify-content: flex-start;
1266
+ padding-left: 2.75rem;
1267
+ }
1268
+
792
1269
  @keyframes ermis-receipt-pop {
793
1270
  0% {
794
1271
  opacity: 0;
795
1272
  transform: scale(0.5) translateY(5px);
796
1273
  }
1274
+
797
1275
  100% {
798
1276
  opacity: 1;
799
1277
  transform: scale(1) translateY(0);
@@ -807,6 +1285,7 @@
807
1285
  cursor: default;
808
1286
  position: relative;
809
1287
  animation: ermis-receipt-pop 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards;
1288
+ z-index: 5;
810
1289
  }
811
1290
 
812
1291
  .ermis-read-receipts__avatar {
@@ -843,10 +1322,17 @@
843
1322
  display: none;
844
1323
  position: absolute;
845
1324
  bottom: calc(100% + 6px);
846
- right: 0;
847
1325
  z-index: 50;
848
1326
  }
849
1327
 
1328
+ .ermis-read-receipts--own .ermis-read-receipts__tooltip-wrapper {
1329
+ right: 0;
1330
+ }
1331
+
1332
+ .ermis-read-receipts--other .ermis-read-receipts__tooltip-wrapper {
1333
+ left: 0;
1334
+ }
1335
+
850
1336
  /* Invisible bridge to prevent hover loss when moving mouse from avatar to tooltip */
851
1337
  .ermis-read-receipts__tooltip-wrapper::after {
852
1338
  content: '';
@@ -858,11 +1344,24 @@
858
1344
  background: transparent;
859
1345
  }
860
1346
 
1347
+ /* Inner Tooltip with scrolling and styling */
1348
+ @keyframes ermis-tooltip-fade-in {
1349
+ from {
1350
+ opacity: 0;
1351
+ transform: translateY(6px);
1352
+ }
1353
+
1354
+ to {
1355
+ opacity: 1;
1356
+ transform: translateY(0);
1357
+ }
1358
+ }
1359
+
861
1360
  .ermis-read-receipts__avatars:hover .ermis-read-receipts__tooltip-wrapper {
862
1361
  display: flex;
1362
+ animation: ermis-tooltip-fade-in 0.2s cubic-bezier(0.16, 1, 0.3, 1) forwards;
863
1363
  }
864
1364
 
865
- /* Inner Tooltip with scrolling and styling */
866
1365
  .ermis-read-receipts__tooltip {
867
1366
  display: flex;
868
1367
  flex-direction: column;
@@ -870,36 +1369,56 @@
870
1369
  background-color: var(--ermis-bg-secondary);
871
1370
  border: 1px solid var(--ermis-border);
872
1371
  border-radius: var(--ermis-radius-md, 8px);
873
- padding: var(--ermis-spacing-xs, 6px) var(--ermis-spacing-sm, 8px);
874
- box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
875
- width: 200px;
876
- max-height: 200px;
1372
+ padding: 8px 12px;
1373
+ box-shadow: none;
1374
+ min-width: 140px;
1375
+ width: max-content;
1376
+ max-width: 220px;
1377
+ max-height: 250px;
877
1378
  overflow-y: auto;
878
1379
  }
879
1380
 
1381
+ /* Custom scrollbar for tooltip */
1382
+ .ermis-read-receipts__tooltip::-webkit-scrollbar {
1383
+ width: 4px;
1384
+ }
1385
+
1386
+ .ermis-read-receipts__tooltip::-webkit-scrollbar-track {
1387
+ background: transparent;
1388
+ }
1389
+
1390
+ .ermis-read-receipts__tooltip::-webkit-scrollbar-thumb {
1391
+ background: var(--ermis-border);
1392
+ border-radius: 4px;
1393
+ }
1394
+
880
1395
  .ermis-read-receipts__tooltip-item {
881
1396
  display: flex;
882
1397
  align-items: center;
883
- gap: var(--ermis-spacing-sm, 8px);
1398
+ gap: 10px;
1399
+ padding: 2px 0;
884
1400
  }
885
1401
 
886
1402
  .ermis-read-receipts__tooltip-info {
887
1403
  display: flex;
888
1404
  flex-direction: column;
889
- gap: 1px;
1405
+ gap: 2px;
890
1406
  min-width: 0;
891
1407
  }
892
1408
 
893
1409
  .ermis-read-receipts__tooltip-name {
894
- font-size: var(--ermis-font-size-xs, 0.75rem);
1410
+ font-size: var(--ermis-font-size-sm, 0.875rem);
1411
+ font-weight: 500;
895
1412
  color: var(--ermis-text-primary);
896
1413
  white-space: nowrap;
897
1414
  overflow: hidden;
898
1415
  text-overflow: ellipsis;
1416
+ line-height: 1.2;
899
1417
  }
900
1418
 
901
1419
  .ermis-read-receipts__tooltip-time {
902
- font-size: 0.625rem;
1420
+ font-size: 0.65rem;
903
1421
  color: var(--ermis-text-muted);
904
1422
  white-space: nowrap;
1423
+ line-height: 1.2;
905
1424
  }