@linktr.ee/messaging-react 3.35.0-rc-1786106245 → 3.35.0-rc-1786109913

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-B-fh4Zxu.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.MessageBubble=e.MessageBubble;exports.MessageVoteButtons=e.MessageVoteButtons;exports.MessagingProvider=e.MessagingProvider;exports.MessagingShell=e.MessagingShell;exports.RichCard=e.RichCard;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.optimizeMessagingAttachmentUrl=e.optimizeMessagingAttachmentUrl;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-AQNn2p5e.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.MessageBubble=e.MessageBubble;exports.MessageVoteButtons=e.MessageVoteButtons;exports.MessagingProvider=e.MessagingProvider;exports.MessagingShell=e.MessagingShell;exports.RichCard=e.RichCard;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.optimizeMessagingAttachmentUrl=e.optimizeMessagingAttachmentUrl;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 h, k as L, l as d, m as p, R as C, n as v, p as A, q as k, s as F, t as b, u as P, v as f, w as x, x as y, o as z, y as B, z as S, B as q, D, E, G as R, H as V, I as w } from "./index-DAY8iAgG.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 h, k as L, l as d, m as p, R as C, n as v, p as A, q as k, s as F, t as b, u as P, v as f, w as x, x as y, o as z, y as B, z as S, B as q, D, E, G as R, H as V, I as w } from "./index-CrdAtOBl.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.35.0-rc-1786106245",
3
+ "version": "3.35.0-rc-1786109913",
4
4
  "description": "React messaging components built on messaging-core for web applications",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -50,7 +50,7 @@
50
50
  },
51
51
  "dependencies": {
52
52
  "@linktr.ee/component-library": "11.8.6",
53
- "@linktr.ee/messaging-core": "2.4.0-rc-1786106245",
53
+ "@linktr.ee/messaging-core": "2.4.0-rc-1786109913",
54
54
  "@linktr.ee/messaging-taxonomy": "^0.7.0",
55
55
  "@phosphor-icons/react": "^2.1.10"
56
56
  },
@@ -46,10 +46,10 @@ describe('RichCard', () => {
46
46
  />
47
47
  )
48
48
  await screen.findByTestId('rich-card')
49
- // Three <img> nodes render; only the first is labelled (the rest are
50
- // decorative, alt="" + aria-hidden, so they're out of the a11y tree).
49
+ // Three <img> nodes render; all are decorative (alt=""), so the fan is out
50
+ // of the a11y tree — the accessible content is the card's title/subtitle.
51
51
  expect(container.querySelectorAll('img')).toHaveLength(3)
52
- expect(screen.getByAltText('Collection')).toBeInTheDocument()
52
+ expect(screen.queryByAltText('Collection')).toBeNull()
53
53
  })
54
54
 
55
55
  it('drops a failed fan image and re-fans the survivors', async () => {
@@ -68,6 +68,42 @@ describe('RichCard', () => {
68
68
  expect(container.querySelectorAll('img')).toHaveLength(2)
69
69
  })
70
70
 
71
+ it('keeps fan thumbnails decorative (empty alt)', async () => {
72
+ const { container } = renderWithProviders(
73
+ <RichCard.Received
74
+ title="Collection"
75
+ images={[HERO, IMG_2, IMG_3]}
76
+ imagePresentation="fan"
77
+ />
78
+ )
79
+ await screen.findByTestId('rich-card')
80
+ const imgs = Array.from(container.querySelectorAll('img'))
81
+ expect(imgs).toHaveLength(3)
82
+ expect(imgs.every((img) => img.getAttribute('alt') === '')).toBe(true)
83
+ })
84
+
85
+ it('resets failed fan tiles when the image set changes', async () => {
86
+ const { container, rerender } = renderWithProviders(
87
+ <RichCard.Received
88
+ title="Collection"
89
+ images={[HERO, IMG_2, IMG_3]}
90
+ imagePresentation="fan"
91
+ />
92
+ )
93
+ await screen.findByTestId('rich-card')
94
+ fireEvent.error(container.querySelectorAll('img')[2])
95
+ expect(container.querySelectorAll('img')).toHaveLength(2)
96
+ // A recycled card with a new collection clears the stale failure tracking.
97
+ rerender(
98
+ <RichCard.Received
99
+ title="Collection"
100
+ images={['https://cdn.example.com/a.jpg', 'https://cdn.example.com/b.jpg', 'https://cdn.example.com/c.jpg']}
101
+ imagePresentation="fan"
102
+ />
103
+ )
104
+ expect(container.querySelectorAll('img')).toHaveLength(3)
105
+ })
106
+
71
107
  it('defaults presentation from image count (>=2 fans)', async () => {
72
108
  const { container } = renderWithProviders(
73
109
  <RichCard.Sent title="Two" images={[HERO, IMG_2]} />
@@ -50,9 +50,21 @@ const FAN_OFFSET_PX: Record<1 | 2 | 3, number[]> = {
50
50
  const RichCardFan: React.FC<{
51
51
  variant: LinkAttachmentVariant
52
52
  images: string[]
53
- title?: string
54
- }> = ({ variant, images, title }) => {
53
+ }> = ({ variant, images }) => {
55
54
  const [failed, setFailed] = React.useState<Record<number, boolean>>({})
55
+
56
+ // Reset the per-tile failure tracking when the image set changes, so a
57
+ // recycled card (same element, new collection) doesn't carry a previous
58
+ // array's failed indexes onto a valid replacement. Adjusting state during
59
+ // render on a key change is the endorsed alternative to a set-state effect
60
+ // (mirrors how `useChinPalette` clears `heroFailed` when `thumbnailUrl` changes).
61
+ const imagesKey = images.join('\n')
62
+ const [trackedKey, setTrackedKey] = React.useState(imagesKey)
63
+ if (imagesKey !== trackedKey) {
64
+ setTrackedKey(imagesKey)
65
+ setFailed({})
66
+ }
67
+
56
68
  const survivors = images
57
69
  .slice(0, 3)
58
70
  .map((src, index) => ({ src, index }))
@@ -75,8 +87,10 @@ const RichCardFan: React.FC<{
75
87
  <img
76
88
  key={`${src}-${index}`}
77
89
  src={optimizeMessagingAttachmentUrl(src) ?? src}
78
- alt={index === 0 ? (title ?? '') : ''}
79
- aria-hidden={index !== 0}
90
+ // Decorative: the card's title + subtitle carry the meaning, so the
91
+ // fan thumbnails are illustration only. Empty alt keeps them out of
92
+ // the accessibility tree (the accessible content is the text).
93
+ alt=""
80
94
  draggable={false}
81
95
  loading="lazy"
82
96
  decoding="async"
@@ -117,7 +131,7 @@ const RichCardImages: React.FC<RichCardImagesProps> = ({
117
131
  }) => (
118
132
  <div className={IMAGE_REGION_CLASS}>
119
133
  {presentation === 'fan' ? (
120
- <RichCardFan variant={variant} images={images} title={title} />
134
+ <RichCardFan variant={variant} images={images} />
121
135
  ) : (
122
136
  // `heroUrl` is the palette-tracked source: it becomes `undefined` when the
123
137
  // hero image errors, so `CardThumbnail` falls through to its placeholder.