@linktr.ee/messaging-react 2.1.0 → 2.2.0-rc-1778753733

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 (58) hide show
  1. package/dist/{Card-CsJvUF_b.js → Card-BdTueeyk.js} +2 -2
  2. package/dist/{Card-CsJvUF_b.js.map → Card-BdTueeyk.js.map} +1 -1
  3. package/dist/{Card-DlMSDSdm.js → Card-ChR37pLZ.js} +2 -2
  4. package/dist/{Card-DlMSDSdm.js.map → Card-ChR37pLZ.js.map} +1 -1
  5. package/dist/{Card-CFFNq49v.js → Card-EKxCn56j.js} +3 -3
  6. package/dist/{Card-CFFNq49v.js.map → Card-EKxCn56j.js.map} +1 -1
  7. package/dist/{LockedThumbnail-DpJx169C.js → LockedThumbnail-B16qP3eH.js} +2 -2
  8. package/dist/{LockedThumbnail-DpJx169C.js.map → LockedThumbnail-B16qP3eH.js.map} +1 -1
  9. package/dist/index-Dn7BC9xK.js +4748 -0
  10. package/dist/index-Dn7BC9xK.js.map +1 -0
  11. package/dist/index.d.ts +591 -25
  12. package/dist/index.js +24 -19
  13. package/package.json +1 -1
  14. package/src/components/CustomMessage/MessageAttachmentConversations.stories.tsx +841 -0
  15. package/src/components/LinkAttachment/LinkAttachment.stories.tsx +7 -92
  16. package/src/components/LinkAttachment/LinkAttachment.test.tsx +69 -0
  17. package/src/components/LinkAttachment/components/Received/Card.tsx +10 -30
  18. package/src/components/LinkAttachment/components/_shared/CardShell.tsx +5 -1
  19. package/src/components/LinkAttachment/index.tsx +24 -50
  20. package/src/components/LinkAttachment/types.ts +12 -5
  21. package/src/components/MessageAttachment/Audio/AudioAttachment.stories.tsx +203 -0
  22. package/src/components/MessageAttachment/Audio/index.tsx +189 -0
  23. package/src/components/MessageAttachment/File/FileAttachment.stories.tsx +352 -0
  24. package/src/components/MessageAttachment/File/index.tsx +240 -0
  25. package/src/components/MessageAttachment/Image/ImageAttachment.stories.tsx +288 -0
  26. package/src/components/MessageAttachment/Image/index.tsx +257 -0
  27. package/src/components/MessageAttachment/MessageAttachment.test.tsx +783 -0
  28. package/src/components/MessageAttachment/Pdf/PdfAttachment.stories.tsx +292 -0
  29. package/src/components/MessageAttachment/Pdf/index.tsx +228 -0
  30. package/src/components/MessageAttachment/Video/VideoAttachment.stories.tsx +272 -0
  31. package/src/components/MessageAttachment/Video/index.tsx +281 -0
  32. package/src/components/MessageAttachment/_shared/Bubble.tsx +173 -0
  33. package/src/components/MessageAttachment/_shared/CompactDocumentRow.tsx +152 -0
  34. package/src/components/MessageAttachment/_shared/DismissButton.tsx +39 -0
  35. package/src/components/MessageAttachment/_shared/DownloadAction.tsx +175 -0
  36. package/src/components/MessageAttachment/_shared/ImageViewer.tsx +314 -0
  37. package/src/components/MessageAttachment/_shared/MediaStackGrid.tsx +139 -0
  38. package/src/components/MessageAttachment/_shared/PdfViewer.tsx +100 -0
  39. package/src/components/MessageAttachment/_shared/VideoViewer.tsx +171 -0
  40. package/src/components/MessageAttachment/_shared/ViewerShell.tsx +159 -0
  41. package/src/components/MessageAttachment/_shared/fileMeta.test.ts +82 -0
  42. package/src/components/MessageAttachment/_shared/fileMeta.ts +95 -0
  43. package/src/components/MessageAttachment/_shared/triggerDownload.ts +54 -0
  44. package/src/components/MessageAttachment/_shared/useViewer.ts +53 -0
  45. package/src/components/MessageAttachment/index.tsx +149 -0
  46. package/src/components/MessageAttachment/stories/StoryTable.tsx +72 -0
  47. package/src/components/MessageAttachment/types.ts +178 -0
  48. package/src/index.ts +32 -0
  49. package/dist/Card-D32U6KfZ.js +0 -85
  50. package/dist/Card-D32U6KfZ.js.map +0 -1
  51. package/dist/Card-DlSSJPip.js +0 -60
  52. package/dist/Card-DlSSJPip.js.map +0 -1
  53. package/dist/Card-zGbhRBwv.js +0 -48
  54. package/dist/Card-zGbhRBwv.js.map +0 -1
  55. package/dist/CardThumbnail-DTBuRQHF.js +0 -239
  56. package/dist/CardThumbnail-DTBuRQHF.js.map +0 -1
  57. package/dist/index-DfcRe-Hj.js +0 -3103
  58. package/dist/index-DfcRe-Hj.js.map +0 -1
package/dist/index.d.ts CHANGED
@@ -6,6 +6,7 @@ import { ChannelSort } from 'stream-chat';
6
6
  import { ComponentType } from 'react';
7
7
  import { default as default_2 } from 'react';
8
8
  import { EmptyStateIndicatorProps } from 'stream-chat-react';
9
+ import { FC } from 'react';
9
10
  import { JSX as JSX_2 } from 'react/jsx-runtime';
10
11
  import { LocalMessage } from 'stream-chat';
11
12
  import { MessagingUser } from '@linktr.ee/messaging-core';
@@ -25,6 +26,42 @@ declare type AgeSafetySystemType = 'SYSTEM_AGE_SAFETY_BLOCKED';
25
26
 
26
27
  export declare type AttachmentSourceType = 'image' | 'audio' | 'video' | 'document';
27
28
 
29
+ declare interface AudioAttachmentSharedProps extends MessageAttachmentBaseProps {
30
+ /** Audio source URL (`mp3`, `aac`, `wav`, …). */
31
+ src?: string;
32
+ /** MIME type hint — typed onto the inline `<source>` element. */
33
+ mimeType?: string;
34
+ /**
35
+ * Filename — used as the download default name (consumed by the
36
+ * native player's kebab menu). The HTML `<audio>` element doesn't
37
+ * expose a built-in title slot, so we don't render the filename
38
+ * inside the bubble itself.
39
+ */
40
+ filename?: string;
41
+ /**
42
+ * Stacked audio. Takes precedence over `src` when set. Each item
43
+ * renders its own native `<audio controls>` player, vertically
44
+ * stacked inside the same bubble with an 8px gap between players.
45
+ * Sent + Received only — the composer surface accepts a single
46
+ * attachment at a time.
47
+ */
48
+ items?: MessageAttachmentAudioItem[];
49
+ /**
50
+ * `<audio preload>` hint applied to every player on the bubble.
51
+ * When omitted, the default depends on the rendered shape:
52
+ *
53
+ * - Single audio (no `items`, or `items.length === 1`) →
54
+ * `'metadata'` so the native player surfaces duration
55
+ * immediately.
56
+ * - Stacked audio (`items.length > 1`) → `'none'` so a thread
57
+ * of voice memos doesn't fan out N parallel metadata requests
58
+ * on first paint.
59
+ *
60
+ * Per-track overrides live on `AudioItem.preload`.
61
+ */
62
+ preload?: MediaPreloadMode;
63
+ }
64
+
28
65
  /**
29
66
  * Avatar component that displays a user image or colored initial fallback
30
67
  */
@@ -41,6 +78,13 @@ export declare interface AvatarProps {
41
78
  dmAgentEnabled?: boolean;
42
79
  }
43
80
 
81
+ /**
82
+ * Build the meta line shown under the title in compact document / file
83
+ * attachments — `EXT · SIZE` (`PDF · 379.5 KB`). Either part is dropped
84
+ * when not available so audio / generic files still get a useful label.
85
+ */
86
+ export declare function buildCompactMetaLabel(mimeType?: string, filename?: string, fileSize?: number): string | undefined;
87
+
44
88
  /**
45
89
  * Empty state component shown when a channel has no messages
46
90
  * Returns null to show nothing - the LoadingIndicator handles the loading state
@@ -267,6 +311,12 @@ export declare interface ComposerCardProps extends LockedAttachmentBaseProps {
267
311
  onEditClick?: () => void;
268
312
  }
269
313
 
314
+ /** Shared props for the `Composer` state of every attachment type. */
315
+ declare interface ComposerExtras {
316
+ /** Renders a dismiss `×` button overlaid on the attachment. */
317
+ onDismiss?: () => void;
318
+ }
319
+
270
320
  /**
271
321
  * @deprecated Renamed to `SentCardProps`. Drafting usages (with `onDismiss`)
272
322
  * should migrate to `ComposerCardProps`.
@@ -310,43 +360,129 @@ export declare interface FaqListProps {
310
360
  avatarName?: string;
311
361
  }
312
362
 
363
+ declare interface FileAttachmentSharedProps extends MessageAttachmentBaseProps {
364
+ /** Source URL of the file (used as the download target). */
365
+ src?: string;
366
+ /** Filename — drives the title + the meta line + the download default name. */
367
+ filename?: string;
368
+ fileSize?: number;
369
+ /** MIME type — drives the type icon. Defaults to `application/octet-stream`. */
370
+ mimeType?: string;
371
+ /**
372
+ * Override displayed title (defaults to `filename`). Useful when a
373
+ * sender renames the attachment before sending.
374
+ */
375
+ title?: string;
376
+ /**
377
+ * Stacked files. Takes precedence over `src` when set. Each item
378
+ * renders as its own row inside the bubble; clicking a row downloads
379
+ * that file. Sent + Received only — the composer surface accepts a
380
+ * single attachment at a time.
381
+ */
382
+ items?: MessageAttachmentFileItem[];
383
+ /**
384
+ * Forwarded to the row trigger. When omitted the click still
385
+ * downloads the file. Supply this for analytics, or return `false`
386
+ * to fully intercept the download (e.g. show a confirmation modal,
387
+ * route to a custom preview, throttle large files). Any other
388
+ * return value — including `void`/`undefined` — lets the built-in
389
+ * download proceed. For stacked attachments the `index` argument
390
+ * identifies the row.
391
+ */
392
+ onClick?: (index: number) => boolean | void;
393
+ }
394
+
395
+ /**
396
+ * Format a byte count as a short human-readable string (`'379.5 KB'`).
397
+ * Mirrors the meta line shown next to file attachments in the mobile chat
398
+ * design — `EXT · SIZE`, e.g. `PDF · 379.5 KB`.
399
+ */
400
+ export declare function formatFileSize(bytes: number): string;
401
+
313
402
  /**
314
403
  * Format a date - shows time for today, relative time for older messages
315
404
  * (e.g., "Just now", "2:08 PM" for today, "Yesterday" for yesterday, "2d" for 2 days ago)
316
405
  */
317
406
  export declare const formatRelativeTime: (date: Date) => string;
318
407
 
408
+ /**
409
+ * Returns the short uppercase extension label shown in the meta line of
410
+ * compact document / file attachments. Prefers the filename extension
411
+ * when present (matches the mobile design which trusts the filename),
412
+ * and falls back to a label derived from the MIME type.
413
+ */
414
+ export declare function getFileExtensionLabel(mimeType?: string, filename?: string): string | undefined;
415
+
319
416
  export declare function getMessageDisplayText({ message, viewerLanguage, }: {
320
417
  message?: MessageWithI18n | null;
321
418
  viewerLanguage?: string;
322
419
  }): string | undefined;
323
420
 
421
+ declare interface ImageAttachmentSharedProps extends MessageAttachmentBaseProps {
422
+ /** Single image — convenience for the most common case. */
423
+ src?: string;
424
+ alt?: string;
425
+ /** Filename surfaced in the viewer toolbar + download default name. */
426
+ filename?: string;
427
+ /**
428
+ * Stacked images. Takes precedence over `src` when set. Renders a
429
+ * 1 / 2 / 3 / 4-tile grid (5+ collapse into a `+N` overflow tile).
430
+ * Sent + Received only — the composer surface intentionally accepts
431
+ * a single attachment at a time.
432
+ */
433
+ items?: MessageAttachmentImageItem[];
434
+ /**
435
+ * Native lazy-load hint forwarded to every `<img>` rendered on the
436
+ * bubble surface (Composer thumbnail, single + stacked tiles, and
437
+ * the `+N` overflow tile). Defaults to `'lazy'` — chat surfaces
438
+ * usually scroll a long history, and lazy loading prevents every
439
+ * historical image from being fetched on mount. Set `'eager'` for
440
+ * above-the-fold hero attachments. Per-tile overrides live on
441
+ * `ImageItem.loading`. The opened `ImageViewer` always eager-loads
442
+ * the active image regardless of this value.
443
+ */
444
+ loading?: ImageLoadingMode;
445
+ /**
446
+ * Forwarded to the Image viewer trigger. When omitted the click
447
+ * still opens the built-in viewer — supply this for analytics, or
448
+ * return `false` to intercept the open (e.g. switch to a route-
449
+ * based gallery / confirmation modal). Any other return value
450
+ * (including `void`/`undefined`) lets the built-in viewer open.
451
+ * For stacked attachments the `index` argument identifies the tile.
452
+ */
453
+ onClick?: (index: number) => boolean | void;
454
+ }
455
+
456
+ /** Loading hint forwarded to the underlying `<img>` element. */
457
+ declare type ImageLoadingMode = 'lazy' | 'eager';
458
+
324
459
  export declare function isLinkAttachment(a: Attachment): boolean;
325
460
 
326
461
  /**
327
- * Link attachments (image / file media + 1P/3P Link Apps) shown in the chat
328
- * thread. Mirrors the `LockedAttachment` API — render `LinkAttachment.Composer`
329
- * while drafting, `LinkAttachment.Sent` after posting, and
462
+ * Link previews (1P / 3P Link Apps) shown in the chat thread. Mirrors
463
+ * the `LockedAttachment` API — render `LinkAttachment.Composer` while
464
+ * drafting, `LinkAttachment.Sent` after posting, and
330
465
  * `LinkAttachment.Received` in the recipient's thread. Maps to the
331
- * "Attachments" and "LinkApps" sections of the messaging design system.
466
+ * "LinkApps" section of the messaging design system.
332
467
  *
333
468
  * Two visual layouts via the `layout` prop:
334
- * - **Featured** (default) — 180px hero thumbnail above the body. Used by
335
- * image / file Attachments and by hero-image LinkApps (Spotify with
336
- * cover art, TikTok with a frame, etc.).
469
+ * - **Featured** (default) — 180px hero thumbnail above the body. Used
470
+ * by hero-image LinkApps (Spotify with cover art, TikTok with a
471
+ * frame, etc.).
337
472
  * - **Classic** — compact card with no hero thumbnail; title /
338
473
  * description / URL / CTA only. Used for LinkApp embeds without
339
474
  * artwork (FAQ, Form) and any link preview that lacks OG imagery.
340
475
  *
341
- * Image / file Attachments use `layout="featured"` and skip the title /
342
- * description / URL body entirely (`CardBody` collapses to nothing when no
343
- * text content is provided). LinkApps always carry a title + description
344
- * and prefix the title with an `appIcon` brand badge.
476
+ * For chat **document / image / video / audio attachments**, reach for
477
+ * `MessageAttachment.{Image,Video,Audio,Pdf,File}` instead those
478
+ * render as bubbles with built-in viewers (zoom-capable image
479
+ * lightbox, native PDF viewer, video / audio with download) and a
480
+ * caption slot for accompanying text.
345
481
  */
346
482
  export declare const LinkAttachment: {
347
- Composer: (props: LinkAttachmentComposerCardProps) => JSX_2.Element;
348
- Sent: (props: LinkAttachmentSentCardProps) => JSX_2.Element;
349
- Received: (props: LinkAttachmentReceivedCardProps) => JSX_2.Element;
483
+ Composer: FC<LinkAttachmentComposerCardProps>;
484
+ Sent: FC<LinkAttachmentSentCardProps>;
485
+ Received: FC<LinkAttachmentReceivedCardProps>;
350
486
  };
351
487
 
352
488
  /**
@@ -373,9 +509,11 @@ export declare interface LinkAttachmentBaseProps {
373
509
  /** Hero thumbnail (180px tall) shown above the title block. */
374
510
  thumbnailUrl?: string;
375
511
  /**
376
- * Source URL for playable media (video, audio). When provided alongside a
377
- * video / audio `mimeType`, the hero region renders an inline player with
378
- * native controls instead of the static thumbnail / type-icon.
512
+ * Source URL for playable media in the hero region. When provided
513
+ * alongside a video / audio `mimeType`, the hero renders an inline
514
+ * native player (used by media-rich link previews that embed a
515
+ * preview clip). For chat document / file attachments, reach for
516
+ * `MessageAttachment.{Pdf,File}` instead.
379
517
  */
380
518
  sourceUrl?: string;
381
519
  /**
@@ -422,11 +560,16 @@ export declare interface LinkAttachmentCta {
422
560
  * Visual layout for a `LinkAttachment.*` card.
423
561
  *
424
562
  * - `featured` — full card with a 180px hero thumbnail above the body.
425
- * The default; matches the "Attachments" frames and the hero-image
426
- * "LinkApps" frames in Figma.
563
+ * The default; matches the hero-image "LinkApps" frames in Figma
564
+ * (Spotify with cover art, TikTok with a frame, etc.).
427
565
  * - `classic` — compact card without a hero thumbnail. Title /
428
566
  * description / URL / CTA only. Used for Link App embeds that don't
429
567
  * carry artwork (and for plain link previews without OG imagery).
568
+ *
569
+ * For document / image / video / audio chat attachments, reach for
570
+ * `MessageAttachment.{Image,Video,Audio,Pdf,File}` instead — those
571
+ * render as bubbles with built-in viewers and download support and
572
+ * carry a `text` slot for accompanying captions.
430
573
  */
431
574
  export declare type LinkAttachmentLayout = 'featured' | 'classic';
432
575
 
@@ -440,12 +583,11 @@ export declare interface LinkAttachmentReceivedCardProps extends LinkAttachmentB
440
583
  * - **Link app with a URL** (Spotify / TikTok / generic link): the card
441
584
  * chrome is an `<a target="_blank">` opening `url` — `onClick` fires
442
585
  * alongside the navigation (use for analytics).
443
- * - **Image / file / placeholder attachment**: the card has no URL, so
444
- * it renders as a button. `onClick` is the consumer's hook for
445
- * opening an image / file preview (lightbox).
446
- * - **Video / audio attachment**: the shell stays non-interactive so
447
- * the native media controls remain operable — `onClick` is ignored
448
- * in this configuration.
586
+ * - **Hero-image only card**: the card has no URL, so it renders as
587
+ * a button. `onClick` is the consumer's hook for opening a preview.
588
+ * - **Video / audio link previews**: the shell stays non-interactive
589
+ * so the native media controls remain operable `onClick` is
590
+ * ignored in this configuration.
449
591
  */
450
592
  onClick?: () => void;
451
593
  }
@@ -525,6 +667,363 @@ export declare interface MediaMessageResolved {
525
667
  thumbnailUrl?: string;
526
668
  }
527
669
 
670
+ /** Preload hint forwarded to the underlying `<video>` / `<audio>` element. */
671
+ declare type MediaPreloadMode = 'none' | 'metadata' | 'auto';
672
+
673
+ /**
674
+ * Per-MIME chat attachment cards used inside the messaging stream.
675
+ *
676
+ * Each subnamespace (`Image`, `Video`, `Audio`, `Pdf`, `File`) exposes
677
+ * three states (`Composer`, `Sent`, `Received`) that map to the
678
+ * sender / recipient sides of a chat:
679
+ *
680
+ * - `Composer` — sender draft state with a dismiss `×` affordance.
681
+ * - `Sent` — sender-side state shown after posting.
682
+ * - `Received` — recipient-side state.
683
+ *
684
+ * Sent / Received variants accept an optional `text` prop that renders
685
+ * inside the same bubble as the attachment — mirroring the mobile chat
686
+ * where a sender can pair a caption with an attachment ('Here is the
687
+ * file', 'Here is the image'). Composer prop types intentionally omit
688
+ * `text` (and `items` / `groupPosition`) so the type system enforces
689
+ * the same contract: captions live in the message-input textarea, not
690
+ * inside the draft attachment preview.
691
+ *
692
+ * Stacked attachments — every type except `Composer` accepts an
693
+ * `items={[…]}` prop on Sent / Received that takes precedence over
694
+ * the singular `src`/`filename`/etc. inputs:
695
+ *
696
+ * - Image / Video render a 1 / 2 / 3 / 4-tile grid (5+ collapse
697
+ * into a `+N` overflow tile). Activating any tile opens the
698
+ * built-in `ImageViewer` / `VideoViewer` at that index, with
699
+ * arrow-key navigation between siblings.
700
+ * - Pdf / Audio / File render their compact rows / players in a
701
+ * vertical stack with an 8px gap between rows. Each row keeps
702
+ * its own activation target — Pdf opens the viewer at that
703
+ * index, Audio gets its own native player, and File downloads
704
+ * the asset for that row.
705
+ *
706
+ * The Composer surface accepts only a single attachment at a time,
707
+ * so its props omit `items` / `text`.
708
+ *
709
+ * Image / Video Composer renders bare — just the media with rounded
710
+ * corners and a dismiss overlay, no surrounding bubble — so the draft
711
+ * preview reads as an in-progress attachment instead of a sent
712
+ * message. Sent / Received wrap the media in the shared bubble chrome.
713
+ *
714
+ * Image / Video / Pdf are interactive in every state (Composer, Sent,
715
+ * Received) — clicks open the corresponding native viewer with built-in
716
+ * download. File rows download the asset directly. Audio renders a
717
+ * native `<audio controls>` player which exposes its own download in
718
+ * the kebab menu, so we don't render a separate Download affordance.
719
+ *
720
+ * # Lazy-loading defaults
721
+ *
722
+ * Media attachments bake in network-friendly defaults for long chat
723
+ * histories and expose explicit escape hatches when a caller knows
724
+ * better (e.g. a hero attachment that's already on-screen):
725
+ *
726
+ * - **Image** — every `<img>` rendered on the bubble surface
727
+ * (Composer thumbnail, single + stacked tiles, `+N` overflow)
728
+ * ships with `loading="lazy" decoding="async"`. Override via the
729
+ * attachment's `loading` prop (or `ImageItem.loading` for per-tile
730
+ * control). The opened `ImageViewer` always eager-loads the
731
+ * active image so it appears immediately.
732
+ * - **Video** — the `<video>` rendered inside the `VideoViewer`
733
+ * defaults to `preload="none"`, so no video bytes are fetched
734
+ * until the user opens the viewer. Poster `<img>` thumbnails on
735
+ * the bubble surface are `loading="lazy" decoding="async"`.
736
+ * Override via the attachment's `preload` prop (or
737
+ * `VideoItem.preload` per item). Once the viewer is open the
738
+ * active item bumps to `preload="metadata"` so duration / the
739
+ * first frame appear immediately.
740
+ * - **Audio** — a single audio bubble defaults to
741
+ * `preload="metadata"` so the native player surfaces duration
742
+ * immediately. A stacked audio bubble (`items.length > 1`)
743
+ * defaults to `preload="none"` for every player so a thread of
744
+ * voice memos doesn't fan out N parallel metadata requests on
745
+ * first paint. Override via the attachment's `preload` prop
746
+ * (or `AudioItem.preload` per track).
747
+ * - **Pdf** / **File** — no inline media element to throttle; the
748
+ * bubble renders compact rows that download / open lazily on
749
+ * activation. No `loading` / `preload` props on these surfaces.
750
+ */
751
+ export declare const MessageAttachment: {
752
+ Image: {
753
+ Composer: FC<MessageAttachmentImageComposerProps>;
754
+ Sent: FC<ImageAttachmentSharedProps>;
755
+ Received: FC<ImageAttachmentSharedProps>;
756
+ };
757
+ Video: {
758
+ Composer: FC<MessageAttachmentVideoComposerProps>;
759
+ Sent: FC<VideoAttachmentSharedProps>;
760
+ Received: FC<VideoAttachmentSharedProps>;
761
+ };
762
+ Audio: {
763
+ Composer: FC<MessageAttachmentAudioComposerProps>;
764
+ Sent: FC<AudioAttachmentSharedProps>;
765
+ Received: FC<AudioAttachmentSharedProps>;
766
+ };
767
+ Pdf: {
768
+ Composer: FC<MessageAttachmentPdfComposerProps>;
769
+ Sent: FC<PdfAttachmentSharedProps>;
770
+ Received: FC<PdfAttachmentSharedProps>;
771
+ };
772
+ File: {
773
+ Composer: FC<MessageAttachmentFileComposerProps>;
774
+ Sent: FC<FileAttachmentSharedProps>;
775
+ Received: FC<FileAttachmentSharedProps>;
776
+ };
777
+ };
778
+
779
+ /**
780
+ * Composer-only props. Single audio (`src`) only — the composer
781
+ * surface accepts a single attachment at a time, so `items` is not
782
+ * supported. Captions (`text`) and `groupPosition` are also dropped:
783
+ * the composer renders a standalone draft, not part of a same-author
784
+ * run, and captions live in the message-input textarea, not inside
785
+ * the draft attachment preview.
786
+ */
787
+ export declare interface MessageAttachmentAudioComposerProps extends ComposerExtras {
788
+ src?: string;
789
+ mimeType?: string;
790
+ filename?: string;
791
+ /** See `AudioAttachmentSharedProps.preload`. */
792
+ preload?: MediaPreloadMode;
793
+ }
794
+
795
+ /** A single audio file inside an Audio attachment (single or stacked). */
796
+ export declare interface MessageAttachmentAudioItem {
797
+ src: string;
798
+ /** MIME type hint — typed onto the inline `<source>` element. */
799
+ mimeType?: string;
800
+ /**
801
+ * Filename — used as the download default name (consumed by the
802
+ * native player's kebab menu).
803
+ */
804
+ filename?: string;
805
+ /**
806
+ * Per-track override for the `<audio preload>` hint. Defaults to
807
+ * the parent attachment's `preload` value, which itself defaults
808
+ * to `'metadata'` for a single audio (so the native player can
809
+ * surface duration immediately) and `'none'` for a stacked thread
810
+ * (so a fan-out of metadata requests doesn't happen on first paint).
811
+ */
812
+ preload?: MediaPreloadMode;
813
+ }
814
+
815
+ export declare type MessageAttachmentAudioReceivedProps = AudioAttachmentSharedProps;
816
+
817
+ export declare type MessageAttachmentAudioSentProps = AudioAttachmentSharedProps;
818
+
819
+ /** Shared props every `MessageAttachment.*.{Composer|Sent|Received}` accepts. */
820
+ export declare interface MessageAttachmentBaseProps {
821
+ /**
822
+ * Optional text rendered below the attachment inside the same bubble.
823
+ * Mirrors the chat behavior in the mobile screenshots — `'Here is the
824
+ * file'`, `'Here is the image'`, etc.
825
+ */
826
+ text?: default_2.ReactNode;
827
+ /**
828
+ * Position of this attachment inside a same-author message run —
829
+ * mirrors the corner-flattening stream-chat-react applies to text
830
+ * bubbles in a clustered conversation. Defaults to `'single'`, so
831
+ * standalone usage keeps every corner rounded. Pass the value
832
+ * derived from `bubbleGroupPositionFromStream({ firstOfGroup,
833
+ * endOfGroup, groupedByUser })` when rendering inside a real
834
+ * `CustomMessage` thread to make the attachment visually merge
835
+ * with adjacent bubbles. Image / Video Composer ignore this — the
836
+ * draft preview renders bare without the surrounding bubble.
837
+ */
838
+ groupPosition?: MessageAttachmentGroupPosition;
839
+ }
840
+
841
+ /**
842
+ * Composer-only props. Single file (`src`) only — the composer surface
843
+ * accepts a single attachment at a time, so `items` is not supported.
844
+ * Captions (`text`) and `groupPosition` are also dropped: the composer
845
+ * renders a standalone draft, not part of a same-author run, and
846
+ * captions live in the message-input textarea, not inside the draft
847
+ * attachment preview.
848
+ */
849
+ export declare interface MessageAttachmentFileComposerProps extends ComposerExtras {
850
+ src?: string;
851
+ filename?: string;
852
+ fileSize?: number;
853
+ mimeType?: string;
854
+ title?: string;
855
+ onClick?: (index: number) => boolean | void;
856
+ }
857
+
858
+ /** A single generic file inside a File attachment (single or stacked). */
859
+ export declare interface MessageAttachmentFileItem {
860
+ src: string;
861
+ /** Filename — drives the title + the meta line + the download default name. */
862
+ filename?: string;
863
+ /** File size in bytes — formatted into the `EXT · SIZE` meta line. */
864
+ fileSize?: number;
865
+ /** MIME type — drives the type icon. Defaults to `application/octet-stream`. */
866
+ mimeType?: string;
867
+ /** Override displayed title. Defaults to `filename`. */
868
+ title?: string;
869
+ }
870
+
871
+ export declare type MessageAttachmentFileReceivedProps = FileAttachmentSharedProps;
872
+
873
+ export declare type MessageAttachmentFileSentProps = FileAttachmentSharedProps;
874
+
875
+ /**
876
+ * Position of a bubble inside a same-author run, mirroring the grouping
877
+ * stream-chat-react applies to consecutive messages from the same user:
878
+ *
879
+ * - `'single'` — standalone message, every corner fully rounded.
880
+ * - `'first'` — first in a 2+ message run; the corner facing the
881
+ * next bubble in the run is flattened.
882
+ * - `'middle'` — both the corner facing the previous bubble and the
883
+ * corner facing the next bubble are flattened.
884
+ * - `'end'` — last in a 2+ message run; the corner facing the
885
+ * previous bubble is flattened (this is also the
886
+ * bubble the avatar attaches to on the receiver side).
887
+ *
888
+ * "Facing" is determined by the bubble's side: sender-aligned bubbles
889
+ * cluster against their right edge, receiver-aligned bubbles against
890
+ * their left edge.
891
+ */
892
+ export declare type MessageAttachmentGroupPosition = 'single' | 'first' | 'middle' | 'end';
893
+
894
+ /**
895
+ * Convenience adapter that derives the `BubbleGroupPosition` from the
896
+ * three booleans `stream-chat-react` forwards into the `Message` HOC.
897
+ * Drop-in for `useMessageContext()` consumers:
898
+ *
899
+ * ```tsx
900
+ * const { firstOfGroup, endOfGroup, groupedByUser } = useMessageContext()
901
+ * <MessageAttachment.Image.Sent
902
+ * {...props}
903
+ * groupPosition={bubbleGroupPositionFromStream({
904
+ * firstOfGroup, endOfGroup, groupedByUser,
905
+ * })}
906
+ * />
907
+ * ```
908
+ */
909
+ export declare const messageAttachmentGroupPositionFromStream: ({ firstOfGroup, endOfGroup, groupedByUser, }: {
910
+ firstOfGroup?: boolean;
911
+ endOfGroup?: boolean;
912
+ groupedByUser?: boolean;
913
+ }) => MessageAttachmentGroupPosition;
914
+
915
+ /**
916
+ * Composer-only props. Single image (`src`) is required; stacked
917
+ * `items` and `text` captions are not supported in the composer state.
918
+ */
919
+ export declare interface MessageAttachmentImageComposerProps {
920
+ src: string;
921
+ alt?: string;
922
+ filename?: string;
923
+ /**
924
+ * Native lazy-load hint forwarded to the composer thumbnail `<img>`.
925
+ * Defaults to `'lazy'`. See `ImageAttachmentSharedProps.loading` for
926
+ * the rationale.
927
+ */
928
+ loading?: ImageLoadingMode;
929
+ onClick?: (index: number) => boolean | void;
930
+ onDismiss?: () => void;
931
+ }
932
+
933
+ /** A single image inside an Image attachment (single or stacked). */
934
+ export declare interface MessageAttachmentImageItem {
935
+ src: string;
936
+ alt?: string;
937
+ /** Optional width/height hint — preserved aspect on cover-fit. */
938
+ width?: number;
939
+ height?: number;
940
+ /**
941
+ * Per-tile native lazy-load override. Defaults to the parent
942
+ * attachment's `loading` value (which itself defaults to `'lazy'`).
943
+ * Pass `'eager'` for above-the-fold hero tiles.
944
+ */
945
+ loading?: ImageLoadingMode;
946
+ }
947
+
948
+ export declare type MessageAttachmentImageReceivedProps = ImageAttachmentSharedProps;
949
+
950
+ export declare type MessageAttachmentImageSentProps = ImageAttachmentSharedProps;
951
+
952
+ /**
953
+ * Composer-only props. Single PDF (`src`) only — the composer surface
954
+ * accepts a single attachment at a time, so `items` is not supported.
955
+ * Captions (`text`) and `groupPosition` are also dropped: the composer
956
+ * renders a standalone draft, not part of a same-author run, and
957
+ * captions live in the message-input textarea, not inside the draft
958
+ * attachment preview.
959
+ */
960
+ export declare interface MessageAttachmentPdfComposerProps extends ComposerExtras {
961
+ src?: string;
962
+ filename?: string;
963
+ fileSize?: number;
964
+ title?: string;
965
+ onClick?: (index: number) => boolean | void;
966
+ }
967
+
968
+ /** A single PDF inside a Pdf attachment (single or stacked). */
969
+ export declare interface MessageAttachmentPdfItem {
970
+ src: string;
971
+ /** Filename — drives the title + the meta line + the viewer toolbar. */
972
+ filename?: string;
973
+ /** File size in bytes — formatted into the `EXT · SIZE` meta line. */
974
+ fileSize?: number;
975
+ /** Override displayed title. Defaults to `filename`. */
976
+ title?: string;
977
+ }
978
+
979
+ export declare type MessageAttachmentPdfReceivedProps = PdfAttachmentSharedProps;
980
+
981
+ export declare type MessageAttachmentPdfSentProps = PdfAttachmentSharedProps;
982
+
983
+ /**
984
+ * Three messaging states a `MessageAttachment.*` card can render in,
985
+ * mirroring the LinkAttachment / LockedAttachment families.
986
+ */
987
+ export declare type MessageAttachmentState = 'composer' | 'sent' | 'received';
988
+
989
+ /**
990
+ * Composer-only props. Single video (`src`) is required; stacked
991
+ * `items` and `text` captions are not supported in the composer state.
992
+ */
993
+ export declare interface MessageAttachmentVideoComposerProps {
994
+ src: string;
995
+ poster?: string;
996
+ mimeType?: string;
997
+ filename?: string;
998
+ /**
999
+ * `<video preload>` hint forwarded into the viewer. Defaults to
1000
+ * `'none'`. See `VideoAttachmentSharedProps.preload`.
1001
+ */
1002
+ preload?: MediaPreloadMode;
1003
+ onClick?: (index: number) => boolean | void;
1004
+ onDismiss?: () => void;
1005
+ }
1006
+
1007
+ /** A single video inside a Video attachment (single or stacked). */
1008
+ export declare interface MessageAttachmentVideoItem {
1009
+ src: string;
1010
+ /** Poster / thumbnail rendered before playback starts. */
1011
+ poster?: string;
1012
+ /** Optional MIME type (e.g. `video/mp4`). */
1013
+ mimeType?: string;
1014
+ /**
1015
+ * Per-item override for the `<video preload>` hint. Defaults to the
1016
+ * parent attachment's `preload` value (which itself defaults to
1017
+ * `'none'` so the poster carries the visual weight and no video
1018
+ * bytes are fetched until playback).
1019
+ */
1020
+ preload?: MediaPreloadMode;
1021
+ }
1022
+
1023
+ export declare type MessageAttachmentVideoReceivedProps = VideoAttachmentSharedProps;
1024
+
1025
+ export declare type MessageAttachmentVideoSentProps = VideoAttachmentSharedProps;
1026
+
528
1027
  declare type MessageCustomType = 'MESSAGE_TIP' | 'MESSAGE_PAID' | 'MESSAGE_CHATBOT' | 'MESSAGE_ATTACHMENT' | AgeSafetySystemType | DmAgentSystemType;
529
1028
 
530
1029
  export declare interface MessageMetadata {
@@ -674,6 +1173,36 @@ export declare interface Participant {
674
1173
  */
675
1174
  declare type PaymentStatus = 'pending' | 'paid' | 'failed' | 'refunded';
676
1175
 
1176
+ declare interface PdfAttachmentSharedProps extends MessageAttachmentBaseProps {
1177
+ /** Single PDF — convenience for the most common case. */
1178
+ src?: string;
1179
+ /** Filename — drives the title + the meta line + the viewer toolbar. */
1180
+ filename?: string;
1181
+ /** File size in bytes — formatted into the `EXT · SIZE` meta line. */
1182
+ fileSize?: number;
1183
+ /**
1184
+ * Override displayed title (defaults to `filename`). Useful when a
1185
+ * sender re-titles a generated PDF before sending.
1186
+ */
1187
+ title?: string;
1188
+ /**
1189
+ * Stacked PDFs. Takes precedence over `src` when set. Each item
1190
+ * renders as its own row inside the bubble; clicking a row opens
1191
+ * that PDF in the viewer. Sent + Received only — the composer
1192
+ * surface accepts a single attachment at a time.
1193
+ */
1194
+ items?: MessageAttachmentPdfItem[];
1195
+ /**
1196
+ * Forwarded to the viewer trigger. When omitted the click still
1197
+ * opens the built-in `PdfViewer`. Supply this to fire analytics, or
1198
+ * return `false` to intercept the open (e.g. swap to a route-based
1199
+ * viewer / confirmation modal). Any other return value (including
1200
+ * `void`/`undefined`) lets the built-in viewer open. For stacked
1201
+ * attachments the `index` argument identifies the row.
1202
+ */
1203
+ onClick?: (index: number) => boolean | void;
1204
+ }
1205
+
677
1206
  export declare interface ReceivedCardProps extends LockedAttachmentBaseProps {
678
1207
  /**
679
1208
  * Called when the recipient clicks Unlock on an unpaid attachment.
@@ -739,6 +1268,43 @@ declare interface UseMessageVoteResult {
739
1268
  */
740
1269
  export declare const useMessaging: () => MessagingContextValue;
741
1270
 
1271
+ declare interface VideoAttachmentSharedProps extends MessageAttachmentBaseProps {
1272
+ /** Single video — convenience for the most common case. */
1273
+ src?: string;
1274
+ /** Poster image — preview shown before playback starts. */
1275
+ poster?: string;
1276
+ /** MIME type hint — typed onto the inline `<source>` element. */
1277
+ mimeType?: string;
1278
+ /** Filename surfaced in the viewer toolbar + download default name. */
1279
+ filename?: string;
1280
+ /**
1281
+ * Stacked videos. Takes precedence over `src` when set. Renders a
1282
+ * 1 / 2 / 3 / 4-tile grid (5+ collapse into a `+N` overflow tile).
1283
+ * Sent + Received only — the composer surface intentionally accepts
1284
+ * a single attachment at a time.
1285
+ */
1286
+ items?: MessageAttachmentVideoItem[];
1287
+ /**
1288
+ * `<video preload>` hint forwarded into the viewer. Defaults to
1289
+ * `'none'` — the poster `<img>` carries the visual weight on the
1290
+ * bubble surface, and we shouldn't fetch any video bytes until the
1291
+ * user actually opens the viewer. Per-item overrides live on
1292
+ * `VideoItem.preload`. The opened `VideoViewer` always preloads
1293
+ * metadata for the active item (so duration / first-frame appear
1294
+ * immediately) regardless of this value.
1295
+ */
1296
+ preload?: MediaPreloadMode;
1297
+ /**
1298
+ * Forwarded to the viewer trigger. When omitted the click still
1299
+ * opens the built-in `VideoViewer` — supply this for analytics, or
1300
+ * return `false` to intercept the open (e.g. switch to a route-
1301
+ * based player / confirmation modal). Any other return value
1302
+ * (including `void`/`undefined`) lets the built-in viewer open.
1303
+ * For stacked attachments the `index` argument identifies the tile.
1304
+ */
1305
+ onClick?: (index: number) => boolean | void;
1306
+ }
1307
+
742
1308
  /** @deprecated Renamed to `ReceivedCardProps`. */
743
1309
  export declare type VisitorCardProps = ReceivedCardProps;
744
1310