@linktr.ee/messaging-react 3.5.6-rc-1783100793 → 3.5.6

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 (40) hide show
  1. package/dist/{Card-XSDNvOZf.js → Card-B5lE5A2D.js} +3 -3
  2. package/dist/{Card-XSDNvOZf.js.map → Card-B5lE5A2D.js.map} +1 -1
  3. package/dist/{Card-Bxu71IQM.cjs → Card-CAJnEq1K.cjs} +2 -2
  4. package/dist/{Card-Bxu71IQM.cjs.map → Card-CAJnEq1K.cjs.map} +1 -1
  5. package/dist/{Card-4eHS-HQB.cjs → Card-DYe76Xh3.cjs} +2 -2
  6. package/dist/{Card-4eHS-HQB.cjs.map → Card-DYe76Xh3.cjs.map} +1 -1
  7. package/dist/{Card-By-eDX0U.cjs → Card-D_N5hclc.cjs} +2 -2
  8. package/dist/{Card-By-eDX0U.cjs.map → Card-D_N5hclc.cjs.map} +1 -1
  9. package/dist/{Card-mDB7sZiu.js → Card-MBp3Wg6r.js} +2 -2
  10. package/dist/{Card-mDB7sZiu.js.map → Card-MBp3Wg6r.js.map} +1 -1
  11. package/dist/{Card-CmLNgIdO.js → Card-rblNjC58.js} +2 -2
  12. package/dist/{Card-CmLNgIdO.js.map → Card-rblNjC58.js.map} +1 -1
  13. package/dist/{LockedThumbnail-C44Wkle9.js → LockedThumbnail-BqyPPVrO.js} +3 -3
  14. package/dist/{LockedThumbnail-C44Wkle9.js.map → LockedThumbnail-BqyPPVrO.js.map} +1 -1
  15. package/dist/{LockedThumbnail-CWhzO3wx.cjs → LockedThumbnail-C7PpVZQ0.cjs} +2 -2
  16. package/dist/{LockedThumbnail-CWhzO3wx.cjs.map → LockedThumbnail-C7PpVZQ0.cjs.map} +1 -1
  17. package/dist/assets/index.css +1 -1
  18. package/dist/{index-BRV621wo.js → index-BXzwYXLT.js} +67 -55
  19. package/dist/index-BXzwYXLT.js.map +1 -0
  20. package/dist/index-BflWZq0e.cjs +2 -0
  21. package/dist/index-BflWZq0e.cjs.map +1 -0
  22. package/dist/index.cjs +1 -1
  23. package/dist/index.js +1 -1
  24. package/package.json +2 -2
  25. package/src/components/AttachmentCard/index.tsx +1 -1
  26. package/src/components/CustomLinkPreviewList/CustomLinkPreviewCard.tsx +1 -1
  27. package/src/components/CustomLinkPreviewList/index.tsx +12 -6
  28. package/src/components/CustomMessage/CustomMessage.stories.tsx +0 -27
  29. package/src/components/CustomMessage/MessageAttachmentConversations.stories.tsx +2 -2
  30. package/src/components/CustomMessage/MessageTag.stories.tsx +2 -2
  31. package/src/components/CustomMessageInput/index.tsx +12 -4
  32. package/src/components/LinkAttachment/components/_shared/CardShell.tsx +1 -1
  33. package/src/components/LockedAttachment/components/_shared/LockedCardShell.tsx +1 -1
  34. package/src/components/MediaMessage/index.tsx +1 -8
  35. package/src/components/MessageAttachment/_shared/Bubble.tsx +7 -7
  36. package/src/components/MessageAttachment/_shared/CompactDocumentRow.tsx +3 -3
  37. package/src/styles.css +6 -75
  38. package/dist/index-BRV621wo.js.map +0 -1
  39. package/dist/index-DBVgTHrA.cjs +0 -2
  40. package/dist/index-DBVgTHrA.cjs.map +0 -1
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-DBVgTHrA.cjs");exports.ActionButton=e.ActionButton;exports.Avatar=e.Avatar;exports.ChannelEmptyState=e.ChannelEmptyState;exports.ChannelList=e.ChannelList;exports.ChannelView=e.ChannelView;exports.CustomMessageProvider=e.CustomMessageProvider;exports.FaqList=e.FaqList;exports.FaqListItem=e.FaqListItem;exports.LinkAttachment=e.LinkAttachment;exports.LockedAttachment=e.LockedAttachment;exports.MediaMessage=e.MediaMessage;exports.MessageAttachment=e.MessageAttachment;exports.MessageVoteButtons=e.MessageVoteButtons;exports.MessagingProvider=e.MessagingProvider;exports.MessagingShell=e.MessagingShell;exports.buildCompactMetaLabel=e.buildCompactMetaLabel;exports.formatFileSize=e.formatFileSize;exports.formatRelativeTime=e.formatRelativeTime;exports.getFileExtensionLabel=e.getFileExtensionLabel;exports.getMessageDisplayText=e.getMessageDisplayText;exports.isLinkAttachment=e.isLinkAttachment;exports.isUuidLike=e.isUuidLike;exports.messageAttachmentGroupPositionFromStream=e.bubbleGroupPositionFromStream;exports.normalizeLanguageCode=e.normalizeLanguageCode;exports.resolveConversationParticipant=e.resolveConversationParticipant;exports.resolveLinkAttachment=e.resolveLinkAttachment;exports.resolveMediaFromMessage=e.resolveMediaFromMessage;exports.resolveParticipantDisplayName=e.resolveParticipantDisplayName;exports.useComposerLocked=e.useComposerLocked;exports.useCustomMessage=e.useCustomMessage;exports.useMessageVote=e.useMessageVote;exports.useMessaging=e.useMessaging;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-BflWZq0e.cjs");exports.ActionButton=e.ActionButton;exports.Avatar=e.Avatar;exports.ChannelEmptyState=e.ChannelEmptyState;exports.ChannelList=e.ChannelList;exports.ChannelView=e.ChannelView;exports.CustomMessageProvider=e.CustomMessageProvider;exports.FaqList=e.FaqList;exports.FaqListItem=e.FaqListItem;exports.LinkAttachment=e.LinkAttachment;exports.LockedAttachment=e.LockedAttachment;exports.MediaMessage=e.MediaMessage;exports.MessageAttachment=e.MessageAttachment;exports.MessageVoteButtons=e.MessageVoteButtons;exports.MessagingProvider=e.MessagingProvider;exports.MessagingShell=e.MessagingShell;exports.buildCompactMetaLabel=e.buildCompactMetaLabel;exports.formatFileSize=e.formatFileSize;exports.formatRelativeTime=e.formatRelativeTime;exports.getFileExtensionLabel=e.getFileExtensionLabel;exports.getMessageDisplayText=e.getMessageDisplayText;exports.isLinkAttachment=e.isLinkAttachment;exports.isUuidLike=e.isUuidLike;exports.messageAttachmentGroupPositionFromStream=e.bubbleGroupPositionFromStream;exports.normalizeLanguageCode=e.normalizeLanguageCode;exports.resolveConversationParticipant=e.resolveConversationParticipant;exports.resolveLinkAttachment=e.resolveLinkAttachment;exports.resolveMediaFromMessage=e.resolveMediaFromMessage;exports.resolveParticipantDisplayName=e.resolveParticipantDisplayName;exports.useComposerLocked=e.useComposerLocked;exports.useCustomMessage=e.useCustomMessage;exports.useMessageVote=e.useMessageVote;exports.useMessaging=e.useMessaging;
2
2
  //# sourceMappingURL=index.cjs.map
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as e, b as t, C as i, c as o, d as n, e as m, F as r, f as g, L as l, h as M, M as c, i as u, j as L, k as h, l as d, m as p, n as v, o as C, p as A, q as k, s as F, t as P, u as b, v as f, w as x, x as y, y as S, z as q, B as z, D as B, E as D, G as E } from "./index-BRV621wo.js";
1
+ import { a as e, b as t, C as i, c as o, d as n, e as m, F as r, f as g, L as l, h as M, M as c, i as u, j as L, k as h, l as d, m as p, n as v, o as C, p as A, q as k, s as F, t as P, u as b, v as f, w as x, x as y, y as S, z as q, B as z, D as B, E as D, G as E } from "./index-BXzwYXLT.js";
2
2
  export {
3
3
  e as ActionButton,
4
4
  t as Avatar,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@linktr.ee/messaging-react",
3
- "version": "3.5.6-rc-1783100793",
3
+ "version": "3.5.6",
4
4
  "description": "React messaging components built on messaging-core for web applications",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -38,7 +38,7 @@
38
38
  },
39
39
  "dependencies": {
40
40
  "@linktr.ee/component-library": "11.8.6",
41
- "@linktr.ee/messaging-core": "2.3.0-rc-1783100793",
41
+ "@linktr.ee/messaging-core": "^2.2.0",
42
42
  "@phosphor-icons/react": "^2.1.10"
43
43
  },
44
44
  "devDependencies": {
@@ -57,7 +57,7 @@ const AttachmentCard: React.FC<AttachmentCardProps> = ({
57
57
  data-testid={dataTestId}
58
58
  className={classNames(
59
59
  'relative w-[280px] select-none overflow-hidden rounded-[24px] shadow-[0_0_0_1px_rgba(0,0,0,0.04),0_4px_8px_rgba(0,0,0,0.06)]',
60
- isDark ? 'bg-[#1e2330]' : 'bg-white'
60
+ isDark ? 'bg-[#121110]' : 'bg-white'
61
61
  )}
62
62
  >
63
63
  {topLeft ? (
@@ -23,7 +23,7 @@ const CustomLinkPreviewCard: React.FC<CustomLinkPreviewCardProps> = ({
23
23
  href={og_scrape_url}
24
24
  target="_blank"
25
25
  rel="noopener noreferrer"
26
- className="relative block w-full rounded-[24px] bg-[#1e2330] p-2 no-underline transition-opacity hover:opacity-90"
26
+ className="relative block w-full rounded-[24px] bg-[#121110] p-2 no-underline transition-opacity hover:opacity-90"
27
27
  >
28
28
  {image_url && (
29
29
  <img
@@ -32,13 +32,19 @@ export const CustomLinkPreviewList = () => {
32
32
  if (!showLinkPreviews) return null
33
33
 
34
34
  return (
35
- <div className="flex flex-col items-stretch w-full gap-2 mb-4">
35
+ // Layout contract: this list is the composer's *shrinkable* region. The
36
+ // mobile visitor surface sizes itself to the keyboard-shrunk
37
+ // visualViewport, so when vertical space runs out this container gives
38
+ // way (min-h-0) and scrolls, while the textarea + send row stays visible
39
+ // (shrink-0 in CustomMessageInput). Each card is wrapped in a shrink-0
40
+ // block so it keeps its intrinsic height and the container scrolls — a
41
+ // bare flex-column child would be shrunk on the column axis and its
42
+ // fixed-height hero would spill out of the collapsed card box.
43
+ <div className="messaging-link-preview-list flex min-h-0 flex-col items-stretch w-full gap-2 mb-4 overflow-y-auto overscroll-contain">
36
44
  {stateLinkPreviews.map((linkPreview) => (
37
- <CustomLinkPreviewCard
38
- key={linkPreview.og_scrape_url}
39
- link={linkPreview}
40
- onDismiss={handleDismiss}
41
- />
45
+ <div key={linkPreview.og_scrape_url} className="w-full shrink-0">
46
+ <CustomLinkPreviewCard link={linkPreview} onDismiss={handleDismiss} />
47
+ </div>
42
48
  ))}
43
49
  </div>
44
50
  )
@@ -247,33 +247,6 @@ WithTipTag.args = {
247
247
  ],
248
248
  }
249
249
 
250
- export const ThreeConsecutiveSentMessages: StoryFn<TemplateProps> =
251
- Template.bind({})
252
- ThreeConsecutiveSentMessages.args = {
253
- messages: [
254
- {
255
- id: 'msg-1',
256
- text: 'why is it that the sun',
257
- user: storyUsers.visitor,
258
- },
259
- {
260
- id: 'msg-2',
261
- text: 'has rays',
262
- user: storyUsers.creator,
263
- },
264
- {
265
- id: 'msg-3',
266
- text: 'how how how',
267
- user: storyUsers.creator,
268
- },
269
- {
270
- id: 'msg-4',
271
- text: 'thanks for the note',
272
- user: storyUsers.visitor,
273
- },
274
- ],
275
- }
276
-
277
250
  export const TipOnly: StoryFn<TemplateProps> = Template.bind({})
278
251
  TipOnly.args = {
279
252
  messages: [
@@ -42,8 +42,8 @@ interface ChatNode {
42
42
  }
43
43
 
44
44
  const TEXT_BG_BY_ROLE: Record<ChatRole, string> = {
45
- sender: 'bg-[#1e2330] text-white',
46
- receiver: 'bg-[#f2f1ef] text-[#000000]',
45
+ sender: 'bg-[#121110] text-white',
46
+ receiver: 'bg-[#e9eaed] text-[#080707]',
47
47
  }
48
48
 
49
49
  const TextBubble: React.FC<{ role: ChatRole; children: React.ReactNode }> = ({
@@ -83,7 +83,7 @@ ChatbotReceiverText.parameters = skipInChromatic
83
83
  export const ChatbotSenderText: StoryFn<ComponentProps> = (args) => {
84
84
  return (
85
85
  <div className="p-12">
86
- <div className="bg-[#1e2330] rounded-[24px] px-4 py-3 w-[280px]">
86
+ <div className="bg-[#121110] rounded-[24px] px-4 py-3 w-[280px]">
87
87
  <MessageTag {...args} />
88
88
  </div>
89
89
  </div>
@@ -150,7 +150,7 @@ export const AllVariants: StoryFn = () => {
150
150
  </div>
151
151
  <div className="flex items-center gap-4">
152
152
  <span className="text-sm w-32">Chatbot (sender):</span>
153
- <div className="bg-[#1e2330] rounded-[24px] px-4 py-3 w-[280px]">
153
+ <div className="bg-[#121110] rounded-[24px] px-4 py-3 w-[280px]">
154
154
  <MessageTag
155
155
  message={createMockMessage({
156
156
  metadata: { custom_type: 'MESSAGE_CHATBOT' },
@@ -61,14 +61,22 @@ const CustomMessageInputInner: React.FC = () => {
61
61
  } = useComponentContext('CustomMessageInput')
62
62
 
63
63
  return (
64
+ // min-h-0 lets the composer shrink under keyboard squeeze (the link
65
+ // preview list inside is the scrollable region); the textarea + send row
66
+ // is shrink-0 so it can never be pushed out of view. self-stretch matters
67
+ // because the parent `.message-input` row uses items-end, which suppresses
68
+ // the default cross-axis stretch — without it this container keeps its
69
+ // content height and the squeeze never reaches the preview list. Stream's
70
+ // <MessageInput> renders its Input directly (context providers only, no
71
+ // wrapper element), so this is a direct flex item of that row.
64
72
  <div
65
- className="central-container flex flex-col gap-2 min-w-0 w-full p-2 bg-white rounded-[1.5rem] shadow-[0_4px_16px_0_rgba(0,0,0,0.08),0_1px_2px_0_rgba(0,0,0,0.04),0_0_0_1px_rgba(0,0,0,0.04)]"
73
+ className="central-container flex min-h-0 flex-col gap-2 min-w-0 w-full self-stretch p-2 bg-white rounded-[1.5rem] shadow-[0_4px_16px_0_rgba(0,0,0,0.08),0_1px_2px_0_rgba(0,0,0,0.04),0_0_0_1px_rgba(0,0,0,0.04)]"
66
74
  data-dd-privacy="mask"
67
75
  >
68
76
  <QuotedMessagePreview />
69
77
  <CustomLinkPreviewList />
70
78
  <AttachmentPreviewList />
71
- <div className="flex">
79
+ <div className="flex shrink-0">
72
80
  <div className="w-full ml-2 mr-4 self-center leading-[0]">
73
81
  <TextareaComposer
74
82
  aria-disabled={disabled || undefined}
@@ -155,12 +163,12 @@ export const CustomMessageInput: React.FC<CustomMessageInputProps> = ({
155
163
  }
156
164
 
157
165
  return (
158
- <div className="flex flex-col gap-4 p-4">
166
+ <div className="flex min-h-0 flex-col gap-4 p-4">
159
167
  <div
160
168
  // @ts-expect-error Only React 19 onwards has `inert` in its types.
161
169
  inert={isFrozen ? '' : undefined}
162
170
  aria-disabled={isFrozen || undefined}
163
- className="message-input flex items-end gap-4 aria-disabled:opacity-40"
171
+ className="message-input flex min-h-0 items-end gap-4 aria-disabled:opacity-40"
164
172
  >
165
173
  {renderActions && (
166
174
  <div className="flex h-12 shrink-0 items-center justify-center">
@@ -64,7 +64,7 @@ const CardShell: React.FC<CardShellProps> = ({
64
64
  const isInteractive = href != null || onClick != null
65
65
  const className = classNames(
66
66
  SHELL_CLASS,
67
- bgClassName ?? (variant === 'dark' ? 'bg-[#1e2330]' : 'bg-white'),
67
+ bgClassName ?? (variant === 'dark' ? 'bg-[#121110]' : 'bg-white'),
68
68
  // `focus-ring` is a design-system utility from the component-library
69
69
  // tailwind preset — outline-none + a black 2px focus-visible ring
70
70
  // with offset, so keyboard users can see the focused card.
@@ -26,7 +26,7 @@ const LockedCardShell: React.FC<LockedCardShellProps> = ({
26
26
  className={classNames(
27
27
  'relative w-[280px] select-none overflow-hidden rounded-md',
28
28
  'shadow-[0_0_0_1px_rgba(0,0,0,0.04),0_1px_2px_rgba(0,0,0,0.04),0_8px_32px_rgba(0,0,0,0.1)]',
29
- variant === 'dark' ? 'bg-[#1e2330]' : 'bg-white'
29
+ variant === 'dark' ? 'bg-[#121110]' : 'bg-white'
30
30
  )}
31
31
  >
32
32
  {children}
@@ -15,7 +15,7 @@ function formatBytes(bytes: number): string {
15
15
  }
16
16
 
17
17
  function linkCardShellClass(isMyMessage: boolean) {
18
- const bg = isMyMessage ? 'bg-[#1e2330]' : 'bg-[#F3F3F1]'
18
+ const bg = isMyMessage ? 'bg-[#121110]' : 'bg-[#F3F3F1]'
19
19
  return `w-[280px] select-none overflow-hidden rounded-[24px] ${bg} shadow-[0_0_0_1px_rgba(0,0,0,0.04),0_4px_8px_rgba(0,0,0,0.06)]`
20
20
  }
21
21
 
@@ -318,13 +318,6 @@ const MediaMessageRoot: React.FC<MediaMessageProps> = ({
318
318
  <div className="str-chat__message-bubble-wrapper">
319
319
  <div
320
320
  className="str-chat__message-bubble"
321
- // The visible child is a self-contained AttachmentCard (white /
322
- // #1e2330 card with its own shadow + radius), not a speech
323
- // bubble, and this wrapper is transparent. Mark it so the
324
- // received/sent tail in `styles.css` skips it — otherwise a
325
- // tail tinted from the text-bubble surface (#f2f1ef) hangs off
326
- // a white card and reads as a detached grey nub.
327
- data-attachment-bubble="true"
328
321
  style={{ padding: 0, borderRadius: 0, overflow: 'visible', background: 'transparent' }}
329
322
  >
330
323
  {linkAttachment ? (
@@ -29,8 +29,8 @@ export interface BubbleProps {
29
29
  // Colors and metrics tracked from `stream-chat-react`'s default
30
30
  // `.str-chat__message-bubble` token set so attachments visually drop
31
31
  // into a normal `CustomMessage` thread without any seams:
32
- // - light → `--str-chat__message-bubble-background-color` in `styles.css` (#f2f1ef)
33
- // - dark → `.str-chat__message--me` override in `styles.css` (#1e2330)
32
+ // - light → `--str-chat__secondary-surface-color` = grey200 (#e9eaed)
33
+ // - dark → `.str-chat__message--me` override in `styles.css` (#121110)
34
34
  // - text padding → `--str-chat__spacing-2 --str-chat__spacing-4` = 8px 16px
35
35
  // - border-radius → `--str-chat__border-radius-md` = 18px
36
36
  //
@@ -41,13 +41,13 @@ export interface BubbleProps {
41
41
  // rebrand would need to touch every site. A central token would
42
42
  // collapse the migration to one definition.
43
43
  const BUBBLE_BG_BY_VARIANT: Record<BubbleVariant, string> = {
44
- dark: 'bg-[#1e2330]',
45
- light: 'bg-[#f2f1ef]',
44
+ dark: 'bg-[#121110]',
45
+ light: 'bg-[#e9eaed]',
46
46
  }
47
47
 
48
48
  const BUBBLE_TEXT_BY_VARIANT: Record<BubbleVariant, string> = {
49
49
  dark: 'text-white',
50
- light: 'text-[#000000]',
50
+ light: 'text-[#080707]',
51
51
  }
52
52
 
53
53
  const BUBBLE_BORDER_BY_VARIANT: Record<BubbleVariant, string> = {
@@ -104,8 +104,8 @@ const CORNER_CLASSES_BY_SIDE_AND_POSITION: Record<
104
104
  * is the file', 'Here is the image').
105
105
  *
106
106
  * Two visual variants:
107
- * - `dark` — sender-side (Composer / Sent), white text on `#1e2330`.
108
- * - `light` — recipient-side (Received), dark text on `#f2f1ef`.
107
+ * - `dark` — sender-side (Composer / Sent), white text on `#121110`.
108
+ * - `light` — recipient-side (Received), dark text on `#e9eaed`.
109
109
  *
110
110
  * Background colors, padding, border-radius, and inherited font come
111
111
  * from the stream-chat-react `.str-chat__message-bubble` token set so
@@ -41,11 +41,11 @@ export interface CompactDocumentRowProps {
41
41
  // so they stay variant-aware. The title inherits the bubble's text
42
42
  // color (set on the parent `Bubble`).
43
43
  //
44
- // `text-black/55` on the `#f2f1ef` light bubble lands right at the
44
+ // `text-black/55` on the `#e9eaed` light bubble lands right at the
45
45
  // WCAG AA 4.5:1 small-text threshold (≈4.5:1) — bump to `/65` so
46
46
  // the meta line has a comfortable margin on the light bubble. The
47
- // dark variant (`text-white/55` on `#1e2330`) already passes AA,
48
- // so we leave it alone.
47
+ // dark variant (`text-white/55` on `#121110`) already passes AA at
48
+ // ~6:1, so we leave it alone.
49
49
  const META_CLASS_BY_VARIANT: Record<BubbleVariant, string> = {
50
50
  dark: 'text-white/55',
51
51
  light: 'text-black/65',
package/src/styles.css CHANGED
@@ -8,10 +8,10 @@
8
8
  --str-chat__font-family: inherit;
9
9
 
10
10
  --str-chat__message-bubble-border-radius: 1.5rem;
11
- --str-chat__message-bubble-background-color: #f2f1ef;
12
- --str-chat__message-bubble-color: #000000;
11
+ --str-chat__message-bubble-background-color: #f1f0ee;
12
+ --str-chat__message-bubble-color: #181818;
13
13
 
14
- --str-chat__own-message-bubble-background-color: #1e2330;
14
+ --str-chat__own-message-bubble-background-color: #121110;
15
15
  --str-chat__own-message-bubble-color: #fff;
16
16
  }
17
17
 
@@ -560,8 +560,7 @@
560
560
 
561
561
  .str-chat__message .str-chat__message-bubble {
562
562
  font-size: 0.875rem;
563
- line-height: 1.3125rem;
564
- letter-spacing: 0.14px;
563
+ line-height: 1.25rem;
565
564
  }
566
565
 
567
566
  /* Chatbot reply markdown — restore semantics that consumer Tailwind preflight
@@ -674,83 +673,15 @@
674
673
  margin-block-end: 0.875rem;
675
674
  }
676
675
 
677
- /* Re-round the outer bottom corner of the trailing/standalone bubble
678
- (bottom-inline-start for `--other`, bottom-inline-end for `--me`) that
679
- stream's grouping flattens — matches main's merged-run shape where the
680
- run reads as one column capped by a rounded bottom corner. The inner
681
- corners stay flattened so consecutive bubbles still merge. */
682
676
  .str-chat__message--other .str-chat__message-bubble {
683
677
  border-end-start-radius: var(--str-chat__message-bubble-border-radius);
684
678
  }
679
+
685
680
  .str-chat__message--me .str-chat__message-bubble {
686
681
  border-end-end-radius: var(--str-chat__message-bubble-border-radius);
687
682
  }
688
-
689
- /* `:not([data-attachment-bubble])` keeps the tail off self-contained
690
- attachment/media cards (see `MediaMessage`): those render their own
691
- shadowed card inside a transparent bubble, so a tail tinted from the
692
- text-bubble surface would hang off the card rather than read as part
693
- of it. Only genuine text/message bubbles get a tail. */
694
- .str-chat__message--other
695
- .str-chat__message-bubble-wrapper
696
- > .str-chat__message-bubble:last-child:not([data-attachment-bubble]) {
697
- position: relative;
698
- /* Form a stacking context so the `z-index: -1` tail below paints
699
- *after* this bubble's own (opaque, same-color) background but
700
- *behind* its in-flow content. Without this the tail would either
701
- sit on top of content (a positioned pseudo-element paints above
702
- in-flow siblings — switching to `::before` would NOT change that)
703
- or drop behind the whole bubble. This matters most for the
704
- zero-padding `MediaMessageRoot` bubble, whose media card reaches
705
- the corner: the tail must tuck behind the card, not cover it. */
706
- isolation: isolate;
707
-
708
- &::after {
709
- content: '';
710
- position: absolute;
711
- inset-block-end: 0;
712
- inset-inline-start: calc(-1 * 0.25rem);
713
- z-index: -1;
714
- width: 1.25rem;
715
- height: 1.4375rem;
716
- background-color: var(--str-chat__message-bubble-background-color);
717
- pointer-events: none;
718
- transform: scaleX(-1);
719
- transform-origin: center;
720
- -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")
721
- no-repeat center / 100% 100%;
722
- 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")
723
- no-repeat center / 100% 100%;
724
- }
725
- }
726
-
727
- .str-chat__message--me
728
- .str-chat__message-bubble-wrapper
729
- > .str-chat__message-bubble:last-child:not([data-attachment-bubble]) {
730
- position: relative;
731
- /* See the `--other` rule above: stacking context so the tail tucks
732
- behind in-flow content (e.g. the corner of a zero-padding
733
- `MediaMessageRoot` card) instead of painting over it. */
734
- isolation: isolate;
735
-
736
- &::after {
737
- content: '';
738
- position: absolute;
739
- inset-block-end: 0;
740
- inset-inline-end: calc(-1 * 0.25rem);
741
- z-index: -1;
742
- width: 1.25rem;
743
- height: 1.4375rem;
744
- background-color: var(--str-chat__own-message-bubble-background-color);
745
- pointer-events: none;
746
- -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")
747
- no-repeat center / 100% 100%;
748
- 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")
749
- no-repeat center / 100% 100%;
750
- }
751
- }
752
-
753
683
  }
684
+
754
685
  /* Locked attachment wrapper: stack card + text bubble in the correct direction */
755
686
  .str-chat__li .str-chat__message--me .str-chat__message-bubble-wrapper {
756
687
  display: flex;