@ermis-network/ermis-chat-react 1.0.6 → 1.0.8

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 (62) hide show
  1. package/dist/index.cjs +3802 -1772
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.css +836 -25
  4. package/dist/index.css.map +1 -1
  5. package/dist/index.d.mts +304 -1
  6. package/dist/index.d.ts +304 -1
  7. package/dist/index.mjs +3755 -1761
  8. package/dist/index.mjs.map +1 -1
  9. package/package.json +2 -2
  10. package/src/channelRoleUtils.ts +73 -0
  11. package/src/channelTypeUtils.ts +46 -0
  12. package/src/components/Avatar.tsx +57 -31
  13. package/src/components/BannedOverlay.tsx +40 -0
  14. package/src/components/ChannelActions.tsx +233 -0
  15. package/src/components/ChannelHeader.tsx +126 -5
  16. package/src/components/ChannelInfo/ChannelInfo.tsx +128 -24
  17. package/src/components/ChannelInfo/ChannelInfoTabs.tsx +67 -28
  18. package/src/components/ChannelInfo/ChannelSettingsPanel.tsx +90 -1
  19. package/src/components/ChannelInfo/EditChannelModal.tsx +5 -4
  20. package/src/components/ChannelInfo/MemberListItem.tsx +2 -1
  21. package/src/components/ChannelList.tsx +514 -47
  22. package/src/components/ClosedTopicOverlay.tsx +38 -0
  23. package/src/components/CreateChannelModal.tsx +53 -16
  24. package/src/components/EditPreview.tsx +2 -1
  25. package/src/components/ForwardMessageModal.tsx +2 -1
  26. package/src/components/MediaLightbox.tsx +314 -0
  27. package/src/components/MessageInput.tsx +21 -3
  28. package/src/components/MessageItem.tsx +10 -12
  29. package/src/components/MessageQuickReactions.tsx +3 -2
  30. package/src/components/MessageReactions.tsx +8 -3
  31. package/src/components/MessageRenderers.tsx +174 -54
  32. package/src/components/PendingOverlay.tsx +51 -0
  33. package/src/components/PinnedMessages.tsx +2 -1
  34. package/src/components/ReplyPreview.tsx +2 -1
  35. package/src/components/SkippedOverlay.tsx +36 -0
  36. package/src/components/TopicModal.tsx +189 -0
  37. package/src/components/UserPicker.tsx +1 -1
  38. package/src/components/VirtualMessageList.tsx +162 -47
  39. package/src/hooks/useBannedState.ts +27 -3
  40. package/src/hooks/useBlockedState.ts +3 -2
  41. package/src/hooks/useChannelCapabilities.ts +10 -8
  42. package/src/hooks/useChannelData.ts +1 -1
  43. package/src/hooks/useChannelListUpdates.ts +28 -5
  44. package/src/hooks/useChannelMessages.ts +2 -3
  45. package/src/hooks/useChannelRowUpdates.ts +9 -2
  46. package/src/hooks/useMessageActions.ts +23 -9
  47. package/src/hooks/useOnlineStatus.ts +71 -0
  48. package/src/hooks/useOnlineUsers.ts +115 -0
  49. package/src/hooks/usePendingState.ts +8 -3
  50. package/src/index.ts +67 -10
  51. package/src/messageTypeUtils.ts +64 -0
  52. package/src/styles/_channel-info.css +21 -0
  53. package/src/styles/_channel-list.css +276 -6
  54. package/src/styles/_media-lightbox.css +263 -0
  55. package/src/styles/_message-bubble.css +170 -13
  56. package/src/styles/_message-input.css +24 -0
  57. package/src/styles/_message-list.css +76 -6
  58. package/src/styles/_message-quick-reactions.css +5 -0
  59. package/src/styles/_message-reactions.css +7 -0
  60. package/src/styles/_topic-modal.css +154 -0
  61. package/src/styles/index.css +2 -0
  62. package/src/types.ts +203 -3
@@ -26,6 +26,29 @@
26
26
  text-overflow: ellipsis;
27
27
  }
28
28
 
29
+ .ermis-channel-header__team-name {
30
+ font-size: var(--ermis-font-size-xs);
31
+ color: var(--ermis-text-secondary);
32
+ margin-bottom: 2px;
33
+ font-weight: 500;
34
+ white-space: nowrap;
35
+ overflow: hidden;
36
+ text-overflow: ellipsis;
37
+ }
38
+
39
+ .ermis-channel-header__topic-avatar {
40
+ width: 32px;
41
+ height: 32px;
42
+ min-width: 32px;
43
+ border-radius: var(--ermis-radius-md);
44
+ background-color: var(--ermis-bg-primary);
45
+ display: flex;
46
+ align-items: center;
47
+ justify-content: center;
48
+ font-size: 16px;
49
+ color: var(--ermis-text-secondary);
50
+ }
51
+
29
52
  .ermis-channel-header__subtitle {
30
53
  font-size: var(--ermis-font-size-xs);
31
54
  color: var(--ermis-text-muted);
@@ -34,6 +57,40 @@
34
57
  text-overflow: ellipsis;
35
58
  }
36
59
 
60
+ /* --- Online Status Indicator --- */
61
+ .ermis-channel-header__online-status {
62
+ display: flex;
63
+ align-items: center;
64
+ gap: 5px;
65
+ margin-top: 1px;
66
+ }
67
+
68
+ .ermis-channel-header__online-dot {
69
+ width: 8px;
70
+ height: 8px;
71
+ border-radius: var(--ermis-radius-full);
72
+ flex-shrink: 0;
73
+ transition: background-color var(--ermis-transition);
74
+ }
75
+
76
+ .ermis-channel-header__online-dot--online {
77
+ background-color: var(--ermis-color-success);
78
+ }
79
+
80
+ .ermis-channel-header__online-dot--offline {
81
+ background-color: var(--ermis-text-muted);
82
+ }
83
+
84
+ .ermis-channel-header__online-label {
85
+ font-size: var(--ermis-font-size-xs);
86
+ color: var(--ermis-text-muted);
87
+ line-height: 1;
88
+ }
89
+
90
+ .ermis-channel-header__online-status--online .ermis-channel-header__online-label {
91
+ color: var(--ermis-color-success);
92
+ }
93
+
37
94
  .ermis-channel-header__info {
38
95
  flex: 1;
39
96
  }
@@ -79,6 +136,7 @@
79
136
  cursor: pointer;
80
137
  border-left: 2px solid transparent;
81
138
  transition: background-color var(--ermis-transition), border-color var(--ermis-transition);
139
+ position: relative;
82
140
  }
83
141
 
84
142
  .ermis-channel-list__item:hover {
@@ -97,6 +155,46 @@
97
155
  flex: 1;
98
156
  }
99
157
 
158
+ /* --- Avatar wrapper with online dot overlay --- */
159
+ .ermis-channel-list__item-avatar-wrapper {
160
+ position: relative;
161
+ flex-shrink: 0;
162
+ }
163
+
164
+ .ermis-channel-list__online-dot {
165
+ position: absolute;
166
+ bottom: 0;
167
+ right: 0;
168
+ width: 10px;
169
+ height: 10px;
170
+ border-radius: var(--ermis-radius-full);
171
+ border: 2px solid var(--ermis-bg-secondary);
172
+ transition: background-color var(--ermis-transition);
173
+ }
174
+
175
+ .ermis-channel-list__online-dot--online {
176
+ background-color: var(--ermis-color-success);
177
+ }
178
+
179
+ .ermis-channel-list__online-dot--offline {
180
+ background-color: var(--ermis-text-muted);
181
+ }
182
+
183
+ .ermis-channel-list__item-top-row {
184
+ display: flex;
185
+ align-items: baseline;
186
+ justify-content: space-between;
187
+ gap: var(--ermis-spacing-sm);
188
+ }
189
+
190
+ .ermis-channel-list__item-bottom-row {
191
+ display: flex;
192
+ align-items: center;
193
+ justify-content: space-between;
194
+ gap: var(--ermis-spacing-sm);
195
+ margin-top: 2px;
196
+ }
197
+
100
198
  .ermis-channel-list__item-name {
101
199
  font-size: var(--ermis-font-size-sm);
102
200
  font-weight: 500;
@@ -104,6 +202,15 @@
104
202
  white-space: nowrap;
105
203
  overflow: hidden;
106
204
  text-overflow: ellipsis;
205
+ flex: 1;
206
+ }
207
+
208
+ .ermis-channel-list__item-timestamp {
209
+ font-size: var(--ermis-font-size-xs);
210
+ color: var(--ermis-text-muted);
211
+ white-space: nowrap;
212
+ flex-shrink: 0;
213
+ margin-top: 2px;
107
214
  }
108
215
 
109
216
  .ermis-channel-list__item-last-message {
@@ -112,13 +219,92 @@
112
219
  white-space: nowrap;
113
220
  overflow: hidden;
114
221
  text-overflow: ellipsis;
115
- margin-top: 2px;
222
+ flex: 1;
223
+ }
224
+
225
+ .ermis-channel-list__item-closed-indicator {
226
+ display: flex;
227
+ align-items: center;
228
+ gap: 6px;
229
+ font-size: var(--ermis-font-size-xs);
230
+ color: var(--ermis-text-secondary);
231
+ font-weight: 500;
232
+ white-space: nowrap;
233
+ overflow: hidden;
234
+ text-overflow: ellipsis;
235
+ flex: 1;
236
+ }
237
+
238
+ .ermis-channel-list__closed-icon {
239
+ display: inline-flex;
240
+ align-items: center;
241
+ justify-content: center;
242
+ flex-shrink: 0;
243
+ color: var(--ermis-color-danger);
244
+ }
245
+
246
+ .ermis-channel-list__pinned-icon {
247
+ position: absolute;
248
+ top: -5px;
249
+ right: 0px;
250
+ color: var(--ermis-color-danger, #ef4444);
251
+ display: inline-flex;
252
+ align-items: center;
253
+ justify-content: center;
254
+ transform: rotate(45deg);
255
+ }
256
+
257
+ .ermis-channel-list__item-badges {
258
+ display: flex;
259
+ align-items: center;
260
+ gap: 4px;
261
+ flex-shrink: 0;
116
262
  }
117
263
 
118
264
  .ermis-channel-list__item-last-message-user {
119
265
  color: var(--ermis-text-secondary);
120
266
  }
121
267
 
268
+ .ermis-channel-list__item-actions-wrapper,
269
+ .ermis-channel-list__topic-actions-wrapper {
270
+ position: absolute;
271
+ right: var(--ermis-spacing-sm);
272
+ top: 50%;
273
+ transform: translateY(-50%);
274
+ opacity: 0;
275
+ transition: opacity var(--ermis-transition);
276
+ display: flex;
277
+ align-items: center;
278
+ z-index: 1;
279
+ }
280
+
281
+ .ermis-channel-list__item:hover .ermis-channel-list__item-actions-wrapper,
282
+ .ermis-channel-list__topic-header:hover .ermis-channel-list__topic-actions-wrapper,
283
+ .ermis-channel-list__item-actions-wrapper:has(.ermis-channel-list__actions-trigger--active),
284
+ .ermis-channel-list__topic-actions-wrapper:has(.ermis-channel-list__actions-trigger--active) {
285
+ opacity: 1;
286
+ }
287
+
288
+ .ermis-channel-list__actions-trigger {
289
+ display: flex;
290
+ align-items: center;
291
+ justify-content: center;
292
+ width: 24px;
293
+ height: 24px;
294
+ border-radius: var(--ermis-radius-sm);
295
+ background-color: var(--ermis-bg-primary);
296
+ color: var(--ermis-text-muted);
297
+ border: none;
298
+ cursor: pointer;
299
+ transition: all var(--ermis-transition);
300
+ }
301
+
302
+ .ermis-channel-list__actions-trigger:hover,
303
+ .ermis-channel-list__actions-trigger--active {
304
+ background-color: var(--ermis-bg-primary);
305
+ color: var(--ermis-accent);
306
+ }
307
+
122
308
  /* --- Unread channel indicator --- */
123
309
  .ermis-channel-list__item--unread .ermis-channel-list__item-name {
124
310
  font-weight: 700;
@@ -146,11 +332,6 @@
146
332
  flex-shrink: 0;
147
333
  }
148
334
 
149
- /* --- Blocked channel indicator --- */
150
- .ermis-channel-list__item--blocked {
151
- opacity: 0.5;
152
- }
153
-
154
335
  .ermis-channel-list__blocked-icon {
155
336
  display: inline-flex;
156
337
  align-items: center;
@@ -215,3 +396,92 @@
215
396
  .ermis-channel-list__accordion-icon--expanded {
216
397
  transform: rotate(0deg);
217
398
  }
399
+
400
+ /* --- Topic Group --- */
401
+ .ermis-channel-list__topic-group {
402
+ display: flex;
403
+ flex-direction: column;
404
+ }
405
+
406
+ .ermis-channel-list__topic-header {
407
+ display: flex;
408
+ align-items: center;
409
+ gap: var(--ermis-spacing-md);
410
+ padding: var(--ermis-spacing-md) var(--ermis-spacing-lg);
411
+ cursor: pointer;
412
+ border-left: 2px solid transparent;
413
+ transition: background-color var(--ermis-transition);
414
+ position: relative;
415
+ }
416
+
417
+ .ermis-channel-list__topic-header:hover {
418
+ background-color: var(--ermis-bg-hover);
419
+ }
420
+
421
+ .ermis-channel-list__topic-header-name {
422
+ font-size: var(--ermis-font-size-sm);
423
+ font-weight: 600;
424
+ color: var(--ermis-text-primary);
425
+ white-space: nowrap;
426
+ overflow: hidden;
427
+ text-overflow: ellipsis;
428
+ flex: 1;
429
+ }
430
+
431
+ .ermis-channel-list__add-topic-btn {
432
+ display: flex;
433
+ align-items: center;
434
+ justify-content: center;
435
+ width: 24px;
436
+ height: 24px;
437
+ border-radius: var(--ermis-radius-sm);
438
+ background-color: transparent;
439
+ color: var(--ermis-text-muted);
440
+ border: none;
441
+ cursor: pointer;
442
+ transition: all var(--ermis-transition);
443
+ }
444
+
445
+ .ermis-channel-list__add-topic-btn:hover {
446
+ background-color: var(--ermis-bg-primary);
447
+ color: var(--ermis-accent);
448
+ }
449
+
450
+ .ermis-channel-list__topic-header--expanded .ermis-channel-list__accordion-icon {
451
+ transform: rotate(0deg);
452
+ }
453
+
454
+ .ermis-channel-list__topic-sublist {
455
+ display: flex;
456
+ flex-direction: column;
457
+ background-color: var(--ermis-bg-secondary);
458
+ }
459
+
460
+ /* Indent nested items and provide hierarchical line */
461
+ .ermis-channel-list__topic-sublist .ermis-channel-list__item {
462
+ padding-left: var(--ermis-spacing-md);
463
+ margin-left: 20px;
464
+ border-left: 2px solid var(--ermis-border);
465
+ }
466
+
467
+ .ermis-channel-list__topic-sublist .ermis-channel-list__item:hover {
468
+ border-left-color: var(--ermis-border-hover);
469
+ }
470
+
471
+ .ermis-channel-list__topic-sublist .ermis-channel-list__item--active {
472
+ border-left-color: var(--ermis-accent);
473
+ }
474
+
475
+ .ermis-channel-list__topic-hashtag {
476
+ display: flex;
477
+ align-items: center;
478
+ justify-content: center;
479
+ width: 24px;
480
+ height: 24px;
481
+ background-color: transparent;
482
+ color: var(--ermis-text-muted);
483
+ border-radius: var(--ermis-radius-full);
484
+ font-size: 0.95rem;
485
+ font-weight: 600;
486
+ flex-shrink: 0;
487
+ }
@@ -0,0 +1,263 @@
1
+ /* ============================================================
2
+ Media Lightbox – Full-screen overlay for images & videos
3
+ BEM: .ermis-lightbox__{element}--{modifier}
4
+ ============================================================ */
5
+
6
+ /* ----------------------------------------------------------
7
+ Overlay & backdrop
8
+ ---------------------------------------------------------- */
9
+ .ermis-lightbox {
10
+ position: fixed;
11
+ inset: 0;
12
+ z-index: 1100;
13
+ display: flex;
14
+ flex-direction: column;
15
+ animation: ermis-lightbox-fade-in 0.2s ease-out;
16
+ }
17
+
18
+ .ermis-lightbox__backdrop {
19
+ position: absolute;
20
+ inset: 0;
21
+ background-color: rgba(0, 0, 0, 0.92);
22
+ backdrop-filter: blur(8px);
23
+ }
24
+
25
+ @keyframes ermis-lightbox-fade-in {
26
+ from { opacity: 0; }
27
+ to { opacity: 1; }
28
+ }
29
+
30
+ /* ----------------------------------------------------------
31
+ Header: counter + close
32
+ ---------------------------------------------------------- */
33
+ .ermis-lightbox__header {
34
+ position: relative;
35
+ z-index: 2;
36
+ display: flex;
37
+ align-items: center;
38
+ justify-content: space-between;
39
+ padding: 12px 16px;
40
+ min-height: 48px;
41
+ }
42
+
43
+ .ermis-lightbox__counter {
44
+ color: rgba(255, 255, 255, 0.8);
45
+ font-size: 14px;
46
+ font-weight: 500;
47
+ letter-spacing: 0.5px;
48
+ user-select: none;
49
+ }
50
+
51
+ .ermis-lightbox__actions {
52
+ display: flex;
53
+ align-items: center;
54
+ gap: 8px;
55
+ margin-left: auto;
56
+ }
57
+
58
+ .ermis-lightbox__action-btn {
59
+ background: rgba(255, 255, 255, 0.1);
60
+ border: none;
61
+ border-radius: 50%;
62
+ width: 36px;
63
+ height: 36px;
64
+ display: flex;
65
+ align-items: center;
66
+ justify-content: center;
67
+ color: rgba(255, 255, 255, 0.85);
68
+ cursor: pointer;
69
+ transition: background-color 0.15s ease, color 0.15s ease;
70
+ }
71
+
72
+ .ermis-lightbox__action-btn:hover {
73
+ background: rgba(255, 255, 255, 0.2);
74
+ color: #fff;
75
+ }
76
+
77
+ /* ----------------------------------------------------------
78
+ Content area
79
+ ---------------------------------------------------------- */
80
+ .ermis-lightbox__content {
81
+ position: relative;
82
+ z-index: 1;
83
+ flex: 1;
84
+ display: flex;
85
+ align-items: center;
86
+ justify-content: center;
87
+ padding: 0 60px;
88
+ overflow: hidden;
89
+ cursor: default;
90
+ }
91
+
92
+ /* ----------------------------------------------------------
93
+ Image
94
+ ---------------------------------------------------------- */
95
+ .ermis-lightbox__image {
96
+ max-width: 90vw;
97
+ max-height: 80vh;
98
+ object-fit: contain;
99
+ border-radius: 4px;
100
+ user-select: none;
101
+ transition: transform 0.15s ease;
102
+ animation: ermis-lightbox-zoom-in 0.25s cubic-bezier(0.16, 1, 0.3, 1);
103
+ }
104
+
105
+ .ermis-lightbox__image--zoomed {
106
+ transition: none;
107
+ }
108
+
109
+ @keyframes ermis-lightbox-zoom-in {
110
+ from {
111
+ opacity: 0;
112
+ transform: scale(0.92);
113
+ }
114
+ to {
115
+ opacity: 1;
116
+ transform: scale(1);
117
+ }
118
+ }
119
+
120
+ /* ----------------------------------------------------------
121
+ Video
122
+ ---------------------------------------------------------- */
123
+ .ermis-lightbox__video {
124
+ max-width: 90vw;
125
+ max-height: 80vh;
126
+ border-radius: 4px;
127
+ background: #000;
128
+ outline: none;
129
+ animation: ermis-lightbox-zoom-in 0.25s cubic-bezier(0.16, 1, 0.3, 1);
130
+ }
131
+
132
+ /* ----------------------------------------------------------
133
+ Navigation buttons
134
+ ---------------------------------------------------------- */
135
+ .ermis-lightbox__nav {
136
+ position: absolute;
137
+ top: 50%;
138
+ transform: translateY(-50%);
139
+ z-index: 3;
140
+ background: rgba(255, 255, 255, 0.08);
141
+ border: none;
142
+ border-radius: 50%;
143
+ width: 44px;
144
+ height: 44px;
145
+ display: flex;
146
+ align-items: center;
147
+ justify-content: center;
148
+ color: rgba(255, 255, 255, 0.75);
149
+ cursor: pointer;
150
+ transition: background-color 0.15s ease, color 0.15s ease, transform 0.15s ease;
151
+ }
152
+
153
+ .ermis-lightbox__nav:hover {
154
+ background: rgba(255, 255, 255, 0.18);
155
+ color: #fff;
156
+ }
157
+
158
+ .ermis-lightbox__nav--prev {
159
+ left: 12px;
160
+ }
161
+
162
+ .ermis-lightbox__nav--prev:hover {
163
+ transform: translateY(-50%) translateX(-2px);
164
+ }
165
+
166
+ .ermis-lightbox__nav--next {
167
+ right: 12px;
168
+ }
169
+
170
+ .ermis-lightbox__nav--next:hover {
171
+ transform: translateY(-50%) translateX(2px);
172
+ }
173
+
174
+ /* ----------------------------------------------------------
175
+ Filename
176
+ ---------------------------------------------------------- */
177
+ .ermis-lightbox__filename {
178
+ position: relative;
179
+ z-index: 2;
180
+ text-align: center;
181
+ padding: 8px 16px 16px;
182
+ color: rgba(255, 255, 255, 0.6);
183
+ font-size: 13px;
184
+ white-space: nowrap;
185
+ overflow: hidden;
186
+ text-overflow: ellipsis;
187
+ user-select: none;
188
+ }
189
+
190
+ /* ----------------------------------------------------------
191
+ Clickable attachment overlay (hover effect on images/videos in messages)
192
+ ---------------------------------------------------------- */
193
+ .ermis-attachment--clickable {
194
+ cursor: pointer;
195
+ position: relative;
196
+ }
197
+
198
+ .ermis-attachment--clickable::after {
199
+ content: '';
200
+ position: absolute;
201
+ inset: 0;
202
+ background: rgba(0, 0, 0, 0);
203
+ border-radius: inherit;
204
+ transition: background-color 0.2s ease;
205
+ pointer-events: none;
206
+ }
207
+
208
+ .ermis-attachment--clickable:hover::after {
209
+ background: rgba(0, 0, 0, 0.12);
210
+ }
211
+
212
+ /* Zoom hint icon on hover */
213
+ .ermis-attachment__overlay {
214
+ position: absolute;
215
+ top: 50%;
216
+ left: 50%;
217
+ transform: translate(-50%, -50%) scale(0.8);
218
+ z-index: 2;
219
+ opacity: 0;
220
+ transition: opacity 0.2s ease, transform 0.2s ease;
221
+ color: #fff;
222
+ background: rgba(0, 0, 0, 0.5);
223
+ border-radius: 50%;
224
+ width: 36px;
225
+ height: 36px;
226
+ display: flex;
227
+ align-items: center;
228
+ justify-content: center;
229
+ pointer-events: none;
230
+ }
231
+
232
+ .ermis-attachment--clickable:hover .ermis-attachment__overlay {
233
+ opacity: 1;
234
+ transform: translate(-50%, -50%) scale(1);
235
+ }
236
+
237
+ /* ----------------------------------------------------------
238
+ Responsive: small viewports
239
+ ---------------------------------------------------------- */
240
+ @media (max-width: 768px) {
241
+ .ermis-lightbox__content {
242
+ padding: 0 12px;
243
+ }
244
+
245
+ .ermis-lightbox__image,
246
+ .ermis-lightbox__video {
247
+ max-width: 100vw;
248
+ max-height: 75vh;
249
+ }
250
+
251
+ .ermis-lightbox__nav {
252
+ width: 36px;
253
+ height: 36px;
254
+ }
255
+
256
+ .ermis-lightbox__nav--prev {
257
+ left: 4px;
258
+ }
259
+
260
+ .ermis-lightbox__nav--next {
261
+ right: 4px;
262
+ }
263
+ }