@linktr.ee/messaging-react 3.37.1 → 3.38.0-rc-1786343622

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 (39) hide show
  1. package/dist/{Card-DVMzYquF.js → Card-D2RldKU0.js} +2 -2
  2. package/dist/{Card-DVMzYquF.js.map → Card-D2RldKU0.js.map} +1 -1
  3. package/dist/{Card-Dxk_Ggxw.cjs → Card-OtystGRA.cjs} +2 -2
  4. package/dist/{Card-Dxk_Ggxw.cjs.map → Card-OtystGRA.cjs.map} +1 -1
  5. package/dist/assets/index.css +1 -1
  6. package/dist/{index-BOBIiAuD.js → index-BoxX5w8R.js} +3123 -3163
  7. package/dist/index-BoxX5w8R.js.map +1 -0
  8. package/dist/index-BrZetD5p.cjs +3 -0
  9. package/dist/index-BrZetD5p.cjs.map +1 -0
  10. package/dist/index.cjs +1 -1
  11. package/dist/index.d.ts +1 -34
  12. package/dist/index.js +27 -29
  13. package/package.json +4 -3
  14. package/src/components/ChannelView.tsx +1 -6
  15. package/src/components/CustomMessage/CustomMessage.test.tsx +0 -12
  16. package/src/components/CustomMessage/MessageTag.test.tsx +9 -18
  17. package/src/components/CustomMessage/MessageTag.tsx +16 -17
  18. package/src/components/CustomMessage/MessageTail.tsx +45 -0
  19. package/src/components/CustomMessage/SentMessageDeliveryStatus.tsx +9 -2
  20. package/src/components/CustomMessage/StreamAttachmentMessage.tsx +18 -4
  21. package/src/components/CustomMessage/index.tsx +32 -24
  22. package/src/components/LinkAttachment/components/_shared/BubbleTail.tsx +5 -6
  23. package/src/components/MessageAttachment/_shared/CarouselNav.tsx +5 -6
  24. package/src/components/MessageAttachment/_shared/DownloadAction.tsx +5 -8
  25. package/src/components/MessageAttachment/_shared/ImageViewer.tsx +8 -12
  26. package/src/components/MessageAttachment/_shared/PdfViewer.tsx +1 -1
  27. package/src/components/MessageAttachment/_shared/VideoViewer.tsx +1 -1
  28. package/src/components/MessageAttachment/_shared/ViewerShell.tsx +16 -11
  29. package/src/components/MessageAttachment/_shared/viewerChromeClasses.ts +16 -0
  30. package/src/components/MessagingShell/index.tsx +0 -2
  31. package/src/index.ts +0 -3
  32. package/src/styles.css +56 -377
  33. package/src/types.ts +0 -8
  34. package/dist/index-BOBIiAuD.js.map +0 -1
  35. package/dist/index-D7A8U8GQ.cjs +0 -3
  36. package/dist/index-D7A8U8GQ.cjs.map +0 -1
  37. package/src/components/CustomMessage/MessageVoteButtons.stories.tsx +0 -95
  38. package/src/components/CustomMessage/MessageVoteButtons.tsx +0 -47
  39. package/src/hooks/useMessageVote.ts +0 -77
package/src/styles.css CHANGED
@@ -1,3 +1,48 @@
1
+ /* =====================================================================
2
+ WHEN TO EDIT THIS FILE (read before adding anything)
3
+
4
+ Tailwind on the JSX is the default. This stylesheet is the escape hatch
5
+ for what Tailwind can't reach. DO NOT append new rules to the bottom by
6
+ reflex — most styling belongs on the element in JSX, not here.
7
+
8
+ Before adding a rule, ask: "Am I styling our own JSX with plain
9
+ utilities (flex/grid, gap, padding, font, color, radius)?"
10
+ → YES: put Tailwind classes on that element. Nothing goes here.
11
+ → NO, because one of the following: add it here, grouped with the
12
+ related block (never at EOF).
13
+
14
+ Legitimate reasons a style lives HERE, not in Tailwind:
15
+ 1. It targets stream-chat-react's internal DOM (`.str-chat__*`). We don't
16
+ render that markup, so there's no JSX to put a class on.
17
+ 2. Tailwind can't express it: `::before`/`::after` generated content,
18
+ `::backdrop`, `@starting-style`, top-layer dialog transitions, layered
19
+ `backdrop-filter` masks/gradients, SVG-mask data URIs, `oklch(from …)`
20
+ relative color, or gnarly `:has()`/compound-state selectors.
21
+ 3. It must ship unconditionally in the built stylesheet — e.g. the
22
+ media-viewer / dialog chrome — so consumers get it without adding our
23
+ `src` to their Tailwind `content` glob. See #gotcha below.
24
+
25
+ NOT reasons to add a rule here:
26
+ - "It has variants / state." A variant matrix is plain Tailwind — resolve
27
+ the class list per case in JSX (see the chatbot indicator in
28
+ MessageTag.tsx: base string + a ternary over the resolved variant).
29
+ - "A test asserts on the class name." Don't keep styling-only classes as
30
+ test hooks. Assert on behavior instead — visible copy, roles, child
31
+ order, or a `data-*` attribute — and style with Tailwind.
32
+
33
+ #gotcha — why Tailwind-on-JSX isn't automatic here: this file has no
34
+ `@tailwind` directives, so the shipped `dist/assets/index.css` contains
35
+ ONLY these hand-written rules (plus the stream import) — NO Tailwind
36
+ utilities. Utility classes in our JSX render only because the *consumer's*
37
+ Tailwind build scans our `src`. So utilities are correct for our
38
+ components, but chrome that must render even for a non-Tailwind consumer
39
+ has to be hand-written CSS.
40
+
41
+ When you DO move a rule to Tailwind: prefer `text-[12px]` over `text-xs`
42
+ when the source sets font-size without a matching line-height — Tailwind's
43
+ `text-xs`/`text-sm` also set line-height and will silently change it.
44
+ ===================================================================== */
45
+
1
46
  /* Stream Chat base styles */
2
47
  @import 'stream-chat-react/dist/css/v2/index.css';
3
48
 
@@ -264,14 +309,12 @@
264
309
  }
265
310
  }
266
311
 
267
- /* Full-screen media viewer dialog. Drives ImageViewer / VideoViewer /
268
- PdfViewer chrome with plain CSS so the package ships self-contained
269
- styles consumers don't need to wire our dist into their Tailwind
270
- `content` glob for the lightbox to render correctly. */
312
+ /* Full-screen media viewer dialog (ImageViewer / VideoViewer / PdfViewer).
313
+ Only the `<dialog>` surface, backdrop, and open/close transitions live here
314
+ they use `::backdrop` / `@starting-style`, which Tailwind can't express.
315
+ The chrome inside (buttons, counter, body, media) is Tailwind on the JSX. */
271
316
  .mes-media-viewer {
272
317
  --transition-duration: 0.15s;
273
- --mes-media-viewer-padding: 64px 24px;
274
- --mes-media-viewer-max-w: min(96vw, 1400px);
275
318
 
276
319
  border: none;
277
320
  padding: 0;
@@ -320,155 +363,6 @@
320
363
  }
321
364
  }
322
365
 
323
- /* Top chrome bar — splits the counter (left) from the close + actions
324
- (right). Sits absolutely positioned over the body so it doesn't push
325
- the centered media down.
326
- `pointer-events: none` on the row lets clicks fall through the
327
- negative space; the counter / actions re-enable `pointer-events`
328
- on themselves so the buttons stay interactive. */
329
- .mes-media-viewer__chrome {
330
- position: absolute;
331
- inset: 12px 12px auto 12px;
332
- display: flex;
333
- align-items: center;
334
- justify-content: space-between;
335
- gap: 12px;
336
- pointer-events: none;
337
- z-index: 1;
338
- }
339
-
340
- .mes-media-viewer__counter {
341
- pointer-events: auto;
342
- display: inline-flex;
343
- align-items: center;
344
- padding: 6px 12px;
345
- border-radius: 9999px;
346
- background-color: rgba(255, 255, 255, 0.12);
347
- color: white;
348
- font-size: 13px;
349
- line-height: 1;
350
- font-weight: 500;
351
- font-variant-numeric: tabular-nums;
352
- }
353
-
354
- .mes-media-viewer__actions {
355
- pointer-events: auto;
356
- display: inline-flex;
357
- align-items: center;
358
- gap: 8px;
359
- margin-left: auto;
360
- }
361
-
362
- /* Shared circular icon button used by the close action, the download
363
- action, and any consumer that drops a button into the chrome.
364
- Defined once so every viewer-chrome button stays visually
365
- consistent and so consumers can rely on a stable selector. */
366
- .mes-media-viewer__action {
367
- width: 40px;
368
- height: 40px;
369
- display: inline-flex;
370
- align-items: center;
371
- justify-content: center;
372
- padding: 0;
373
- border: 0;
374
- border-radius: 9999px;
375
- background-color: rgba(255, 255, 255, 0.12);
376
- color: white;
377
- cursor: pointer;
378
- transition: background-color 0.15s ease;
379
- }
380
-
381
- .mes-media-viewer__action:hover,
382
- .mes-media-viewer__action:focus-visible {
383
- background-color: rgba(255, 255, 255, 0.22);
384
- outline: none;
385
- }
386
-
387
- .mes-media-viewer__action[disabled] {
388
- opacity: 0.4;
389
- cursor: default;
390
- }
391
-
392
- /* Carousel prev/next chrome — only rendered when a viewer carries
393
- more than one item. Positioned absolutely against the dialog so the
394
- buttons hug the viewport edges, mid-height. */
395
- .mes-media-viewer__nav {
396
- position: absolute;
397
- top: 50%;
398
- transform: translateY(-50%);
399
- width: 48px;
400
- height: 48px;
401
- display: inline-flex;
402
- align-items: center;
403
- justify-content: center;
404
- padding: 0;
405
- border: 0;
406
- border-radius: 9999px;
407
- background-color: rgba(255, 255, 255, 0.12);
408
- color: white;
409
- cursor: pointer;
410
- z-index: 1;
411
- transition: background-color 0.15s ease;
412
- }
413
-
414
- .mes-media-viewer__nav:hover,
415
- .mes-media-viewer__nav:focus-visible {
416
- background-color: rgba(255, 255, 255, 0.22);
417
- outline: none;
418
- }
419
-
420
- .mes-media-viewer__nav--prev {
421
- left: 16px;
422
- }
423
-
424
- .mes-media-viewer__nav--next {
425
- right: 16px;
426
- }
427
-
428
- /* Flex-centered body. */
429
- .mes-media-viewer__body {
430
- display: flex;
431
- align-items: center;
432
- justify-content: center;
433
- width: 100%;
434
- height: 100%;
435
- padding: var(--mes-media-viewer-padding);
436
- box-sizing: border-box;
437
- }
438
-
439
- /* Image: contained at reasonable max dimensions, never bigger than the
440
- available body. `object-fit: contain` keeps aspect ratio. */
441
- .mes-media-viewer__image {
442
- display: block;
443
- max-width: var(--mes-media-viewer-max-w);
444
- max-height: calc(100dvh - 128px);
445
- width: auto;
446
- height: auto;
447
- object-fit: contain;
448
- -webkit-user-select: none;
449
- user-select: none;
450
- }
451
-
452
- /* Video: keeps native controls; let the height grow up to the bounded
453
- box and width track the intrinsic aspect ratio. */
454
- .mes-media-viewer__video {
455
- display: block;
456
- max-width: var(--mes-media-viewer-max-w);
457
- max-height: calc(100dvh - 128px);
458
- width: auto;
459
- height: auto;
460
- background: black;
461
- }
462
-
463
- /* PDF iframe: native browser PDF rendering owns the inside, so we just
464
- bound the frame and give it an opaque background. */
465
- .mes-media-viewer__iframe {
466
- display: block;
467
- width: var(--mes-media-viewer-max-w);
468
- height: calc(100dvh - 128px);
469
- background: white;
470
- border: 0;
471
- }
472
366
 
473
367
  /* Textarea composer focus styles */
474
368
  .mes-textarea-composer-container:has(.mes-textarea-composer:focus) {
@@ -515,17 +409,6 @@
515
409
  position: relative;
516
410
  }
517
411
 
518
- .sent-message-broadcast-link {
519
- display: inline-flex;
520
- align-items: center;
521
- gap: 0.25rem;
522
- background: none;
523
- border: 0;
524
- padding: 0;
525
- font: inherit;
526
- color: inherit;
527
- cursor: pointer;
528
- }
529
412
 
530
413
  .str-chat__li .str-chat__message-inner {
531
414
  grid-column-gap: 4px;
@@ -732,14 +615,6 @@
732
615
  .sent-message-broadcast-name {
733
616
  color: var(--sent-message-broadcast-name-color);
734
617
  }
735
- .str-chat__li
736
- .str-chat__message--me
737
- .sent-message-status-row
738
- .sent-message-broadcast-link
739
- .sent-message-broadcast-name {
740
- text-decoration: underline;
741
- text-decoration-skip-ink: auto;
742
- }
743
618
  .str-chat__li .str-chat__message--me .sent-message-status--failed {
744
619
  color: var(--str-chat__message-error-color, #d92d20);
745
620
  }
@@ -763,126 +638,6 @@
763
638
  padding: 0;
764
639
  }
765
640
 
766
- /* Custom message tag styles */
767
- .message-tag {
768
- display: inline-flex;
769
- align-items: center;
770
- gap: 4px;
771
- padding: 0;
772
- font-size: 12px;
773
- line-height: 2;
774
- font-weight: 500;
775
- }
776
-
777
- .message-tag__icon {
778
- display: flex;
779
- align-items: center;
780
- }
781
-
782
- .message-tag--tip {
783
- background-color: transparent;
784
- color: #016630;
785
- }
786
-
787
- .message-chatbot-indicator {
788
- display: inline-flex;
789
- align-items: center;
790
- font-size: 10px;
791
- font-weight: 400;
792
- line-height: 16px;
793
- letter-spacing: 0.2px;
794
- }
795
-
796
- .message-chatbot-indicator--text {
797
- width: 100%;
798
- gap: 6px;
799
- margin-top: 12px;
800
- padding-inline: 16px;
801
- }
802
-
803
- .message-chatbot-indicator--receiver {
804
- justify-content: flex-start;
805
- color: rgba(0, 0, 0, 0.3);
806
- }
807
-
808
- .message-chatbot-indicator--sender {
809
- justify-content: flex-end;
810
- }
811
-
812
- .message-chatbot-indicator--sender.message-chatbot-indicator--text {
813
- justify-content: flex-start;
814
- color: rgba(255, 255, 255, 0.55);
815
- }
816
-
817
- .message-chatbot-indicator--attachment {
818
- gap: 8px;
819
- color: rgba(0, 0, 0, 0.3);
820
- }
821
-
822
- .message-chatbot-indicator__icon {
823
- display: inline-flex;
824
- align-items: center;
825
- line-height: 1;
826
- }
827
-
828
- .message-chatbot-indicator__label {
829
- text-align: left;
830
- }
831
-
832
- /* Message vote buttons (chatbot feedback) */
833
- .message-vote-buttons {
834
- display: inline-flex;
835
- align-items: center;
836
- gap: 2px;
837
- }
838
-
839
- .message-vote-button {
840
- position: relative;
841
- display: flex;
842
- align-items: center;
843
- justify-content: center;
844
- width: 28px;
845
- height: 28px;
846
- padding: 0;
847
- border: none;
848
- border-radius: 50%;
849
- background-color: transparent;
850
- color: #737373;
851
- cursor: pointer;
852
- transition:
853
- background-color 0.15s,
854
- color 0.15s;
855
- }
856
-
857
- .message-vote-button:hover {
858
- background-color: rgba(0, 0, 0, 0.05);
859
- color: #737373;
860
- }
861
-
862
- .message-vote-button[data-tooltip]::after {
863
- content: attr(data-tooltip);
864
- position: absolute;
865
- bottom: calc(100% + 6px);
866
- left: 50%;
867
- transform: translateX(-50%);
868
- background-color: rgba(0, 0, 0, 0.85);
869
- color: #fff;
870
- font-size: 12px;
871
- line-height: 1;
872
- padding: 4px 8px;
873
- border-radius: 4px;
874
- white-space: nowrap;
875
- pointer-events: none;
876
- opacity: 0;
877
- transition: opacity 0.15s 0s;
878
- }
879
-
880
- .message-vote-button[data-tooltip]:hover::after,
881
- .message-vote-button[data-tooltip]:focus-visible::after {
882
- opacity: 1;
883
- transition-delay: 300ms;
884
- }
885
-
886
641
  .str-chat__message
887
642
  .str-chat__message-inner
888
643
  .str-chat__message-bubble
@@ -903,7 +658,7 @@
903
658
  .str-chat__message-bubble` rules at specificity (0,3,0). We prepend the
904
659
  `.str-chat` root class to reach (0,4,0) so this wins independently of
905
660
  stylesheet load order and restores the fully-rounded pill from the Figma
906
- spec — only the trailing bubble's tail (`::after`, below) breaks the pill. */
661
+ spec — only the trailing bubble's rendered `MessageTail` breaks the pill. */
907
662
  .str-chat
908
663
  .str-chat__li--single
909
664
  .str-chat__message--me
@@ -1051,75 +806,12 @@
1051
806
  margin-bottom: 0;
1052
807
  }
1053
808
 
1054
- .str-chat__li--single,
1055
- .str-chat__li--bottom {
1056
- .str-chat__message {
1057
- margin-block-end: 0.875rem;
1058
- }
1059
-
1060
- /* `:not([data-attachment-bubble])` keeps the tail off self-contained
1061
- attachment/media cards (see `MediaMessage`): those render their own
1062
- shadowed card inside a transparent bubble, so a tail tinted from the
1063
- text-bubble surface would hang off the card rather than read as part
1064
- of it. Only genuine text/message bubbles get a tail. */
1065
- .str-chat__message--other
1066
- .str-chat__message-bubble-wrapper
1067
- > .str-chat__message-bubble:last-child:not([data-attachment-bubble]) {
1068
- position: relative;
1069
- /* Form a stacking context so the `z-index: -1` tail below paints
1070
- *after* this bubble's own (opaque, same-color) background but
1071
- *behind* its in-flow content. Without this the tail would either
1072
- sit on top of content (a positioned pseudo-element paints above
1073
- in-flow siblings — switching to `::before` would NOT change that)
1074
- or drop behind the whole bubble. This matters most for the
1075
- zero-padding `MediaMessageRoot` bubble, whose media card reaches
1076
- the corner: the tail must tuck behind the card, not cover it. */
1077
- isolation: isolate;
1078
-
1079
- &::after {
1080
- content: '';
1081
- position: absolute;
1082
- inset-block-end: 0;
1083
- inset-inline-start: calc(-1 * 0.3125rem);
1084
- z-index: -1;
1085
- width: 1.25rem;
1086
- height: 1.4375rem;
1087
- background-color: var(--str-chat__message-bubble-background-color);
1088
- pointer-events: none;
1089
- transform: scaleX(-1);
1090
- transform-origin: center;
1091
- -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='23' fill='none'%3E%3Cpath fill='black' d='M0 0H15C15 10.1934 15.859 15.2345 19.168 21.4893C19.527 22.168 19.039 22.9917 18.274 22.9178C5.176 21.6506 0.32 6.0737 0 0Z'/%3E%3C/svg%3E")
1092
- no-repeat center / 100% 100%;
1093
- mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='23' fill='none'%3E%3Cpath fill='black' d='M0 0H15C15 10.1934 15.859 15.2345 19.168 21.4893C19.527 22.168 19.039 22.9917 18.274 22.9178C5.176 21.6506 0.32 6.0737 0 0Z'/%3E%3C/svg%3E")
1094
- no-repeat center / 100% 100%;
1095
- }
1096
- }
1097
-
1098
- .str-chat__message--me
1099
- .str-chat__message-bubble-wrapper
1100
- > .str-chat__message-bubble:last-child:not([data-attachment-bubble]) {
1101
- position: relative;
1102
- /* See the `--other` rule above: stacking context so the tail tucks
1103
- behind in-flow content (e.g. the corner of a zero-padding
1104
- `MediaMessageRoot` card) instead of painting over it. */
1105
- isolation: isolate;
1106
-
1107
- &::after {
1108
- content: '';
1109
- position: absolute;
1110
- inset-block-end: 0;
1111
- inset-inline-end: calc(-1 * 0.3125rem);
1112
- z-index: -1;
1113
- width: 1.25rem;
1114
- height: 1.4375rem;
1115
- background-color: var(--str-chat__own-message-bubble-background-color);
1116
- pointer-events: none;
1117
- -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='23' fill='none'%3E%3Cpath fill='black' d='M0 0H15C15 10.1934 15.859 15.2345 19.168 21.4893C19.527 22.168 19.039 22.9917 18.274 22.9178C5.176 21.6506 0.32 6.0737 0 0Z'/%3E%3C/svg%3E")
1118
- no-repeat center / 100% 100%;
1119
- mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='23' fill='none'%3E%3Cpath fill='black' d='M0 0H15C15 10.1934 15.859 15.2345 19.168 21.4893C19.527 22.168 19.039 22.9917 18.274 22.9178C5.176 21.6506 0.32 6.0737 0 0Z'/%3E%3C/svg%3E")
1120
- no-repeat center / 100% 100%;
1121
- }
1122
- }
809
+ /* Trailing bubble of a same-author run gets extra spacing. The bubble tail
810
+ itself is now a rendered `MessageTail` element (see CustomMessage /
811
+ StreamAttachmentMessage), not a pseudo-element. */
812
+ .str-chat__li--single .str-chat__message,
813
+ .str-chat__li--bottom .str-chat__message {
814
+ margin-block-end: 0.875rem;
1123
815
  }
1124
816
 
1125
817
  /* Derived accent surface for `LinkAttachment` cards. `--accent` is the raw
@@ -1212,19 +904,6 @@
1212
904
  margin-top: 4px;
1213
905
  }
1214
906
 
1215
- /* Standalone tip message (tip without text) */
1216
- .message-tip-standalone {
1217
- display: inline-flex;
1218
- align-items: center;
1219
- gap: 6px;
1220
- padding: 10px 14px;
1221
- border-radius: 18px;
1222
- font-size: 14px;
1223
- font-weight: 500;
1224
- color: #016e1a;
1225
- background-color: #dbf0e0;
1226
- }
1227
-
1228
907
  /** Remove padding from the text inside the locked attachment text shell,
1229
908
  and inherit TextShell's explicit colour — stream-chat-react's own
1230
909
  `MessageText` sets its own (black) colour that only gets overridden by
package/src/types.ts CHANGED
@@ -296,13 +296,6 @@ export interface ChannelViewProps {
296
296
  */
297
297
  showChannelInfo?: boolean
298
298
 
299
- /**
300
- * Enable thumbs up/down voting on chatbot messages.
301
- * When true, vote buttons render below chatbot (DM Agent) messages.
302
- * Votes are persisted as Stream Chat reactions (vote_up / vote_down).
303
- * Defaults to false.
304
- */
305
- chatbotVotingEnabled?: boolean
306
299
  /**
307
300
  * Language code used to pick translated message text from Stream Chat i18n.
308
301
  * Falls back to message.text when no matching translation exists.
@@ -443,7 +436,6 @@ export type ChannelViewPassthroughProps = Pick<
443
436
  | 'onReportParticipantClick'
444
437
  | 'dmAgentEnabled'
445
438
  | 'onMessageSent'
446
- | 'chatbotVotingEnabled'
447
439
  | 'viewerLanguage'
448
440
  | 'renderChannelBanner'
449
441
  | 'customChannelActions'