@linktr.ee/messaging-react 3.10.0-rc-1783660962 → 3.10.0

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 (86) hide show
  1. package/dist/Card-B-L2MST4.js +107 -0
  2. package/dist/Card-B-L2MST4.js.map +1 -0
  3. package/dist/Card-B56QxJW3.cjs +2 -0
  4. package/dist/Card-B56QxJW3.cjs.map +1 -0
  5. package/dist/Card-Bqh-BQaX.js +132 -0
  6. package/dist/Card-Bqh-BQaX.js.map +1 -0
  7. package/dist/Card-ZCE6Lhfc.cjs +2 -0
  8. package/dist/Card-ZCE6Lhfc.cjs.map +1 -0
  9. package/dist/Card-g4JD-2ES.js +163 -0
  10. package/dist/Card-g4JD-2ES.js.map +1 -0
  11. package/dist/Card-wac6AMNc.cjs +2 -0
  12. package/dist/Card-wac6AMNc.cjs.map +1 -0
  13. package/dist/LockedThumbnail-BAQmoIff.js +220 -0
  14. package/dist/LockedThumbnail-BAQmoIff.js.map +1 -0
  15. package/dist/LockedThumbnail-Cr0Gqs3Y.cjs +2 -0
  16. package/dist/LockedThumbnail-Cr0Gqs3Y.cjs.map +1 -0
  17. package/dist/assets/index.css +1 -1
  18. package/dist/index-BPhZyaxT.cjs +2 -0
  19. package/dist/index-BPhZyaxT.cjs.map +1 -0
  20. package/dist/{index-DFZrAiLB.js → index-BxzzWK4K.js} +1249 -1276
  21. package/dist/index-BxzzWK4K.js.map +1 -0
  22. package/dist/index.cjs +1 -1
  23. package/dist/index.d.ts +101 -164
  24. package/dist/index.js +1 -1
  25. package/dist/testing.d.ts +0 -1
  26. package/package.json +2 -2
  27. package/src/components/ChannelList/CustomChannelPreview.test.tsx +0 -95
  28. package/src/components/ChannelList/CustomChannelPreview.tsx +9 -21
  29. package/src/components/CustomMessage/CustomMessage.stories.tsx +1 -54
  30. package/src/components/CustomMessage/MessageTag.tsx +0 -8
  31. package/src/components/CustomMessage/context.tsx +1 -1
  32. package/src/components/CustomMessage/index.tsx +42 -76
  33. package/src/components/CustomMessageInput/CustomMessageInput.stories.tsx +3 -5
  34. package/src/components/LockedAttachment/LockedAttachment.stories.tsx +450 -0
  35. package/src/components/LockedAttachment/components/Composer/Card.tsx +221 -0
  36. package/src/components/LockedAttachment/components/Composer/index.ts +2 -0
  37. package/src/components/LockedAttachment/components/Received/Card.tsx +191 -0
  38. package/src/components/{CustomMessage/LockedAttachment/components/Media → LockedAttachment/components/Received}/CardActions.tsx +2 -9
  39. package/src/components/LockedAttachment/components/Received/index.ts +2 -0
  40. package/src/components/LockedAttachment/components/Sent/Card.tsx +177 -0
  41. package/src/components/LockedAttachment/components/Sent/index.ts +2 -0
  42. package/src/components/{CustomMessage/LockedAttachment → LockedAttachment}/components/_shared/CardBody.tsx +7 -8
  43. package/src/components/{CustomMessage/LockedAttachment → LockedAttachment}/components/_shared/GalleryThumbnail.tsx +39 -31
  44. package/src/components/LockedAttachment/components/_shared/LockBadge.tsx +39 -0
  45. package/src/components/{CustomMessage/LockedAttachment/components/_shared/MediaShell.tsx → LockedAttachment/components/_shared/LockedCardShell.tsx} +8 -8
  46. package/src/components/{CustomMessage/LockedAttachment/components/_shared/SingleThumbnail.tsx → LockedAttachment/components/_shared/LockedThumbnail.tsx} +7 -11
  47. package/src/components/LockedAttachment/index.tsx +63 -0
  48. package/src/components/LockedAttachment/types.ts +51 -0
  49. package/src/index.ts +8 -3
  50. package/src/stream-custom-data.ts +0 -1
  51. package/src/styles.css +0 -12
  52. package/src/types.ts +1 -1
  53. package/dist/Card-415OfRhw.cjs +0 -2
  54. package/dist/Card-415OfRhw.cjs.map +0 -1
  55. package/dist/Card-CyWdUMCB.cjs +0 -2
  56. package/dist/Card-CyWdUMCB.cjs.map +0 -1
  57. package/dist/Card-V5d6qhDT.js +0 -694
  58. package/dist/Card-V5d6qhDT.js.map +0 -1
  59. package/dist/Card-qS17qnN0.js +0 -103
  60. package/dist/Card-qS17qnN0.js.map +0 -1
  61. package/dist/LoadingDots-Ct3WmVlT.js +0 -59
  62. package/dist/LoadingDots-Ct3WmVlT.js.map +0 -1
  63. package/dist/LoadingDots-D9GGphgM.cjs +0 -2
  64. package/dist/LoadingDots-D9GGphgM.cjs.map +0 -1
  65. package/dist/index-Bx_zjNMR.cjs +0 -2
  66. package/dist/index-Bx_zjNMR.cjs.map +0 -1
  67. package/dist/index-DFZrAiLB.js.map +0 -1
  68. package/src/components/CustomMessage/LockedAttachment/LockedAttachment.stories.tsx +0 -541
  69. package/src/components/CustomMessage/LockedAttachment/LockedAttachment.test.tsx +0 -117
  70. package/src/components/CustomMessage/LockedAttachment/components/Media/Card.tsx +0 -358
  71. package/src/components/CustomMessage/LockedAttachment/components/Media/types.ts +0 -79
  72. package/src/components/CustomMessage/LockedAttachment/components/Text/Card.tsx +0 -153
  73. package/src/components/CustomMessage/LockedAttachment/components/Text/types.ts +0 -58
  74. package/src/components/CustomMessage/LockedAttachment/components/_shared/CardThumbnail.tsx +0 -92
  75. package/src/components/CustomMessage/LockedAttachment/components/_shared/LoadingDots.tsx +0 -36
  76. package/src/components/CustomMessage/LockedAttachment/components/_shared/LockBadge.tsx +0 -63
  77. package/src/components/CustomMessage/LockedAttachment/components/_shared/PreviewToggle.tsx +0 -58
  78. package/src/components/CustomMessage/LockedAttachment/components/_shared/PriceLockRow.tsx +0 -21
  79. package/src/components/CustomMessage/LockedAttachment/components/_shared/PurchaseStatusBadge.tsx +0 -74
  80. package/src/components/CustomMessage/LockedAttachment/components/_shared/SkeletonTextLines.tsx +0 -29
  81. package/src/components/CustomMessage/LockedAttachment/components/_shared/TextShell.tsx +0 -28
  82. package/src/components/CustomMessage/LockedAttachment/components/_shared/usePreviewToggle.test.ts +0 -67
  83. package/src/components/CustomMessage/LockedAttachment/components/_shared/usePreviewToggle.ts +0 -89
  84. package/src/components/CustomMessage/LockedAttachment/components/_shared/useReceivedSource.ts +0 -83
  85. package/src/components/CustomMessage/LockedAttachment/index.tsx +0 -105
  86. package/src/components/CustomMessage/LockedAttachment/types.ts +0 -44
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-Bx_zjNMR.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.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-BPhZyaxT.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.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.d.ts CHANGED
@@ -404,12 +404,44 @@ export declare interface ChannelViewProps {
404
404
  onParticipantNameClick?: () => void;
405
405
  }
406
406
 
407
+ export declare interface ComposerCardProps extends LockedAttachmentBaseProps {
408
+ /** Placeholder shown in the title slot before the composer types one. */
409
+ placeholderTitle?: string;
410
+ /** Placeholder shown in the amount slot before one is configured. */
411
+ placeholderAmountText?: string;
412
+ /**
413
+ * When provided, renders a dismiss X in the thumbnail corner. Called when
414
+ * the composer clicks it to remove the attachment.
415
+ */
416
+ onDismiss?: () => void;
417
+ /** Fired the first time the composer taps the thumbnail to preview. */
418
+ onPreviewClick?: () => void;
419
+ /**
420
+ * Lazily loads the underlying source so the composer can preview the
421
+ * attachment they're about to send. Called the first time the thumbnail is
422
+ * tapped; the returned source is cached and reused on subsequent toggles.
423
+ */
424
+ onFetchSource?: () => Promise<LockedAttachmentSource | void>;
425
+ /**
426
+ * When provided, renders a pencil button in the body bottom-right that the
427
+ * composer can use to edit the attachment metadata (e.g. open the price /
428
+ * gallery editor). Matches the Composer "Button" instance in Figma.
429
+ */
430
+ onEditClick?: () => void;
431
+ }
432
+
407
433
  /** Shared props for the `Composer` state of every attachment type. */
408
434
  declare interface ComposerExtras {
409
435
  /** Renders a dismiss `×` button overlaid on the attachment. */
410
436
  onDismiss?: () => void;
411
437
  }
412
438
 
439
+ /**
440
+ * @deprecated Renamed to `SentCardProps`. Drafting usages (with `onDismiss`)
441
+ * should migrate to `ComposerCardProps`.
442
+ */
443
+ export declare type CreatorCardProps = SentCardProps;
444
+
413
445
  export declare const CustomMessageProvider: Provider<Partial<CustomMessageRegistry>>;
414
446
 
415
447
  export declare interface CustomMessageRegistry {
@@ -418,19 +450,6 @@ export declare interface CustomMessageRegistry {
418
450
 
419
451
  declare type DmAgentSystemType = 'SYSTEM_DM_AGENT_PAUSED' | 'SYSTEM_DM_AGENT_RESUMED';
420
452
 
421
- declare type DraftProps = MediaCardDraftProps & {
422
- /** Drafting is always the sender — doesn't apply here. */
423
- isMine?: never;
424
- /**
425
- * "text" renders as a chat bubble showing the real draft `text` instead of
426
- * a media thumbnail card. Media-only fields below are ignored in text mode.
427
- * Defaults to `"media"`.
428
- */
429
- contentType?: 'text' | 'media';
430
- /** The message's own text, shown as-is (not redacted yet). Only used when `contentType` is `"text"`. */
431
- renderedText?: default_2.ReactNode;
432
- };
433
-
434
453
  export declare interface Faq {
435
454
  id: string;
436
455
  question: string;
@@ -460,9 +479,6 @@ export declare interface FaqListProps {
460
479
  avatarName?: string;
461
480
  }
462
481
 
463
- /** Fetches the underlying source; `void` return means none available. */
464
- declare type FetchSourceHandler = () => Promise<LockedAttachmentSource | void>;
465
-
466
482
  declare interface FileAttachmentSharedProps extends MessageAttachmentBaseProps {
467
483
  /** Source URL of the file (used as the download target). */
468
484
  src?: string;
@@ -712,113 +728,56 @@ export declare interface LinkAttachmentSentCardProps extends LinkAttachmentBaseP
712
728
  onClick?: () => void;
713
729
  }
714
730
 
715
- export declare const LockedAttachment: default_2.FC<LockedAttachmentProps>;
731
+ export declare const LockedAttachment: {
732
+ Composer: (props: ComposerCardProps) => JSX_2.Element;
733
+ Sent: (props: SentCardProps) => JSX_2.Element;
734
+ Received: (props: ReceivedCardProps) => JSX_2.Element;
735
+ Creator: (props: SentCardProps) => JSX_2.Element;
736
+ Visitor: (props: ReceivedCardProps) => JSX_2.Element;
737
+ };
738
+
739
+ declare interface LockedAttachmentBaseProps {
740
+ title?: string;
741
+ mimeType?: string;
742
+ thumbnailUrl?: string;
743
+ detail?: string;
744
+ amountText?: string;
745
+ paymentStatus?: PaymentStatus;
746
+ /**
747
+ * When provided with 2+ items, the card renders as a mixed-media carousel
748
+ * (e.g. a couple of photos + a video) instead of a single thumbnail. Each
749
+ * item brings its own thumbnail and optional source so that
750
+ * `LockedAttachment.Composer` / `.Sent` / `.Received` can all share the
751
+ * same carousel chrome.
752
+ */
753
+ gallery?: LockedAttachmentGalleryItem[];
754
+ }
716
755
 
717
756
  export declare interface LockedAttachmentContextValue {
718
- /** Whether the given message is mid-checkout. */
719
757
  isUnlocking: (id: string) => boolean;
720
- /** Opens the checkout flow for a message. */
721
758
  onUnlockClick?: (message: LocalMessage, channel: Channel) => void;
722
- /** Handles a Download click for a message. */
723
759
  onDownloadClick?: (message: LocalMessage, channel: Channel) => void;
724
- /** Reveals the locked media's source. Unused for text — payment writes `message.text` directly. */
725
760
  onFetchSource?: (message: LocalMessage, channel: Channel) => Promise<LockedAttachmentSource | void>;
726
761
  }
727
762
 
728
763
  export declare interface LockedAttachmentGalleryItem {
729
- /** Drives the per-item play/lock affordance. */
764
+ /** MIME type of this carousel item — drives the per-item play / lock affordance. */
730
765
  mimeType: string;
731
- /** Poster image, locked or unlocked. */
766
+ /** Poster image used for both the locked (blurred) and unlocked preview state. */
732
767
  thumbnailUrl?: string;
733
- /** Media source, shown only when unlocked. */
768
+ /** Underlying source (image or video URL) — shown only when unlocked. */
734
769
  sourceUrl?: string;
735
770
  }
736
771
 
737
- /**
738
- * The card for a paid attachment — a still-drafting `isDraft` card, a static
739
- * receiver-facing `isPreview` mockup, or a sent text/media card discriminated
740
- * by `isMine` + `contentType`. Internally lazy-loads only the one underlying
741
- * implementation the resolved branch needs.
742
- */
743
- export declare type LockedAttachmentProps = DraftProps | PreviewProps | SentTextOwnProps | SentTextOtherProps | SentMediaOwnProps | SentMediaOtherProps;
744
-
745
772
  export declare interface LockedAttachmentSource {
746
- /** Proxied URL for in-app playback. */
773
+ /** Proxied URL used by the media player for in-app playback. */
747
774
  sourceUrl: string;
748
- /** Opened when the visitor clicks Download. */
775
+ /** URL opened when the visitor clicks Download — may be a file or a web destination. */
749
776
  redeemUrl?: string;
750
- /** Overrides the metadata thumbnail when present. */
777
+ /** Thumbnail URL from the fetched asset — overrides the metadata thumbnail when present. */
751
778
  thumbnailUrl?: string;
752
779
  }
753
780
 
754
- declare interface MediaCardBaseProps {
755
- /** Attachment title. */
756
- title?: string;
757
- /** Fallback shown when `title` is unset. */
758
- placeholderTitle?: string;
759
- /** Drives icon/thumbnail rendering. */
760
- mimeType?: string;
761
- /** Poster image, locked or unlocked. */
762
- thumbnailUrl?: string;
763
- /** Secondary description text. */
764
- detail?: string;
765
- /** Amount label. */
766
- amountText?: string;
767
- /** 2+ items renders as a carousel instead of a single thumbnail. */
768
- gallery?: LockedAttachmentGalleryItem[];
769
- }
770
-
771
- declare interface MediaCardDraftProps extends MediaCardBaseProps {
772
- /** True while composing — shows the real (unredacted) thumbnail. */
773
- isDraft: true;
774
- isPreview?: false;
775
- /** Fallback amount before a price is set. */
776
- placeholderAmountText?: string;
777
- /** Lazily fetches the source on first tap; cached and reused after. */
778
- onFetchSource?: FetchSourceHandler;
779
- /** Fired on first tap to preview. */
780
- onPreviewClick?: () => void;
781
- /** Removes the draft attachment. */
782
- onDismiss?: () => void;
783
- /** Renders a pencil button to edit the attachment metadata. */
784
- onEditClick?: () => void;
785
- }
786
-
787
- declare type MediaCardOtherProps = MediaCardSentBaseProps & {
788
- /** Recipient's view. */
789
- isMine: false;
790
- /** Opens checkout on click. Omit to hide the button. */
791
- onUnlockClick?: () => void;
792
- /** Omit to hide the Download button. */
793
- onDownloadClick?: () => void;
794
- /** Spinner on Unlock while checkout runs. */
795
- isUnlocking?: boolean;
796
- };
797
-
798
- declare type MediaCardOwnProps = MediaCardSentBaseProps & {
799
- /** Sender's own view. */
800
- isMine: true;
801
- /** Fired on first tap to preview own attachment. */
802
- onPreviewClick?: () => void;
803
- };
804
-
805
- declare interface MediaCardPreviewProps extends MediaCardBaseProps {
806
- /** True to render exactly as the recipient will see it before purchase — always locked/blurred. */
807
- isDraft?: false;
808
- isPreview: true;
809
- /** Fallback amount before a price is set. */
810
- placeholderAmountText?: string;
811
- }
812
-
813
- declare interface MediaCardSentBaseProps extends MediaCardBaseProps {
814
- /** False once sent. */
815
- isDraft?: false;
816
- isPreview?: false;
817
- /** Drives the lock/skeleton/badge state. */
818
- paymentStatus?: PaymentStatus;
819
- onFetchSource?: FetchSourceHandler;
820
- }
821
-
822
781
  export declare const MediaMessage: default_2.FC<MediaMessageProps> & {
823
782
  Creator: default_2.FC<{
824
783
  message: LocalMessage;
@@ -1274,7 +1233,6 @@ export declare interface MessageMetadata {
1274
1233
  amount_text?: string;
1275
1234
  payment_status?: PaymentStatus;
1276
1235
  attachment_title?: string;
1277
- attachment_content_type?: 'text' | 'media';
1278
1236
  attachment_mime_type?: string;
1279
1237
  attachment_thumbnail?: string;
1280
1238
  attachment_detail?: string;
@@ -1487,16 +1445,6 @@ declare interface PdfAttachmentSharedProps extends MessageAttachmentBaseProps {
1487
1445
  onClick?: (index: number) => boolean | void;
1488
1446
  }
1489
1447
 
1490
- declare type PreviewProps = MediaCardPreviewProps & {
1491
- /** Drafting is always the sender — doesn't apply here. */
1492
- isMine?: never;
1493
- /**
1494
- * "text" renders as a chat bubble instead of a media thumbnail card.
1495
- * Media-only fields below are ignored in text mode. Defaults to `"media"`.
1496
- */
1497
- contentType?: 'text' | 'media';
1498
- };
1499
-
1500
1448
  export declare interface ReceivedBubbleProps extends MessageBubbleBaseProps {
1501
1449
  /**
1502
1450
  * Optional header rendered above the text inside the bubble — used by the
@@ -1505,6 +1453,31 @@ export declare interface ReceivedBubbleProps extends MessageBubbleBaseProps {
1505
1453
  header?: default_2.ReactNode;
1506
1454
  }
1507
1455
 
1456
+ export declare interface ReceivedCardProps extends LockedAttachmentBaseProps {
1457
+ /**
1458
+ * Called when the recipient clicks Unlock on an unpaid attachment.
1459
+ * Use this to open a checkout flow. Omit to hide the Unlock button.
1460
+ */
1461
+ onUnlockClick?: () => void;
1462
+ /**
1463
+ * Called to fetch the attachment source — fired automatically when
1464
+ * `paymentStatus` transitions to `'paid'`, or immediately on click when
1465
+ * `paymentStatus` is already `'paid'`. Return a `LockedAttachmentSource`
1466
+ * to unlock the card.
1467
+ */
1468
+ onFetchSource?: () => Promise<LockedAttachmentSource | void>;
1469
+ /**
1470
+ * Called when the recipient clicks Download on an unlocked card.
1471
+ * Omit to hide the Download button.
1472
+ */
1473
+ onDownloadClick?: () => void;
1474
+ /**
1475
+ * When true, shows a loading spinner on the Unlock button.
1476
+ * Driven by the LockedAttachmentContext (e.g. checkout in progress).
1477
+ */
1478
+ isUnlocking?: boolean;
1479
+ }
1480
+
1508
1481
  /**
1509
1482
  * Resolves the member to display as the conversation's "other party".
1510
1483
  *
@@ -1530,56 +1503,17 @@ export declare function resolveParticipantDisplayName(user?: ParticipantDisplayU
1530
1503
  export declare interface SentBubbleProps extends MessageBubbleBaseProps {
1531
1504
  }
1532
1505
 
1533
- declare type SentMediaOtherProps = MediaCardOtherProps & {
1534
- contentType?: 'media';
1535
- };
1536
-
1537
- declare type SentMediaOwnProps = MediaCardOwnProps & {
1538
- contentType?: 'media';
1539
- /** Sender's view has no unlock/download flow doesn't apply here. */
1540
- onUnlockClick?: never;
1541
- isUnlocking?: never;
1542
- onDownloadClick?: never;
1543
- };
1544
-
1545
- declare type SentTextOtherProps = TextCardOtherProps & {
1546
- contentType: 'text';
1547
- };
1548
-
1549
- declare type SentTextOwnProps = TextCardOwnProps & {
1550
- contentType: 'text';
1551
- /** Sender's view has no unlock flow — doesn't apply here. */
1552
- onUnlockClick?: never;
1553
- isUnlocking?: never;
1554
- };
1555
-
1556
- declare interface TextCardBaseProps {
1557
- /** Amount label. */
1558
- amountText?: string;
1559
- }
1560
-
1561
- declare type TextCardOtherProps = TextCardSentBaseProps & {
1562
- /** Recipient's view. */
1563
- isMine: false;
1564
- /** Spinner on Unlock while checkout runs. */
1565
- isUnlocking?: boolean;
1566
- /** Opens checkout on click. Omit to hide the button. */
1567
- onUnlockClick?: () => void;
1568
- };
1569
-
1570
- declare type TextCardOwnProps = TextCardSentBaseProps & {
1571
- /** Sender's own view. */
1572
- isMine: true;
1573
- };
1574
-
1575
- declare interface TextCardSentBaseProps extends TextCardBaseProps {
1576
- /** False once sent. */
1577
- isDraft?: false;
1578
- isPreview?: false;
1579
- /** Revealed content once paid. */
1580
- renderedText?: default_2.ReactNode;
1581
- /** Drives the lock/skeleton/badge state. */
1582
- paymentStatus?: PaymentStatus;
1506
+ export declare interface SentCardProps extends LockedAttachmentBaseProps {
1507
+ /** Placeholder shown in the title slot when no title is set. */
1508
+ placeholderTitle?: string;
1509
+ /** Fired the first time the sender taps the thumbnail to preview their own attachment. */
1510
+ onPreviewClick?: () => void;
1511
+ /**
1512
+ * Lazily loads the underlying source so the sender can preview the attachment.
1513
+ * Called the first time the thumbnail is tapped; the returned source is cached
1514
+ * and reused on subsequent toggles.
1515
+ */
1516
+ onFetchSource?: () => Promise<LockedAttachmentSource | void>;
1583
1517
  }
1584
1518
 
1585
1519
  /**
@@ -1650,6 +1584,9 @@ declare interface VideoAttachmentSharedProps extends MessageAttachmentBaseProps
1650
1584
  onClick?: (index: number) => boolean | void;
1651
1585
  }
1652
1586
 
1587
+ /** @deprecated Renamed to `ReceivedCardProps`. */
1588
+ export declare type VisitorCardProps = ReceivedCardProps;
1589
+
1653
1590
  export declare type VoteSelection = 'up' | 'down' | null;
1654
1591
 
1655
1592
  export { }
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 u, i as c, 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 b, u as P, v as f, w as x, x as y, y as B, z as S, B as q, D as z, E as D, G as E, H as V } from "./index-DFZrAiLB.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 u, i as c, 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 b, u as P, v as f, w as x, x as y, y as B, z as S, B as q, D as z, E as D, G as E, H as V } from "./index-BxzzWK4K.js";
2
2
  export {
3
3
  e as ActionButton,
4
4
  t as Avatar,
package/dist/testing.d.ts CHANGED
@@ -47,7 +47,6 @@ export declare interface MessageMetadata {
47
47
  amount_text?: string;
48
48
  payment_status?: PaymentStatus;
49
49
  attachment_title?: string;
50
- attachment_content_type?: 'text' | 'media';
51
50
  attachment_mime_type?: string;
52
51
  attachment_thumbnail?: string;
53
52
  attachment_detail?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@linktr.ee/messaging-react",
3
- "version": "3.10.0-rc-1783660962",
3
+ "version": "3.10.0",
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.3.0-rc-1783660962",
53
+ "@linktr.ee/messaging-core": "^2.2.0",
54
54
  "@phosphor-icons/react": "^2.1.10"
55
55
  },
56
56
  "devDependencies": {
@@ -260,101 +260,6 @@ describe('CustomChannelPreview', () => {
260
260
  expect(screen.getByText('No messages yet')).toBeInTheDocument()
261
261
  })
262
262
 
263
- it('shows a locked indicator for a text-only attachment message, even when paid', () => {
264
- // The channel-list preview always shows the locked wording for an
265
- // attachment-type message and never echoes `message.text` — the
266
- // revealed content is only ever shown inside the full conversation.
267
- const channel = createMockChannel([
268
- {
269
- id: 'msg-1',
270
- text: 'REDACTED',
271
- type: 'regular',
272
- created_at: new Date('2026-01-01T00:00:00.000Z'),
273
- user: { id: 'participant-1', name: 'Alice' },
274
- metadata: {
275
- custom_type: 'MESSAGE_ATTACHMENT',
276
- attachment_content_type: 'text',
277
- payment_status: 'paid',
278
- },
279
- },
280
- ])
281
-
282
- renderWithProviders(
283
- <CustomChannelPreview {...defaultProps} channel={channel} />
284
- )
285
-
286
- expect(screen.getByText('🔒 Sent a locked message')).toBeInTheDocument()
287
- expect(screen.queryByText(/REDACTED/)).not.toBeInTheDocument()
288
- })
289
-
290
- it('shows a locked indicator for an unpaid text-only attachment message', () => {
291
- const channel = createMockChannel([
292
- {
293
- id: 'msg-1',
294
- text: 'REDACTED',
295
- type: 'regular',
296
- created_at: new Date('2026-01-01T00:00:00.000Z'),
297
- user: { id: 'participant-1', name: 'Alice' },
298
- metadata: {
299
- custom_type: 'MESSAGE_ATTACHMENT',
300
- attachment_content_type: 'text',
301
- payment_status: 'pending',
302
- },
303
- },
304
- ])
305
-
306
- renderWithProviders(
307
- <CustomChannelPreview {...defaultProps} channel={channel} />
308
- )
309
-
310
- expect(screen.getByText('🔒 Sent a locked message')).toBeInTheDocument()
311
- expect(screen.queryByText(/REDACTED/)).not.toBeInTheDocument()
312
- })
313
-
314
- it('shows a locked indicator for a media attachment message, even when paid', () => {
315
- const channel = createMockChannel([
316
- {
317
- id: 'msg-1',
318
- type: 'regular',
319
- created_at: new Date('2026-01-01T00:00:00.000Z'),
320
- user: { id: 'participant-1', name: 'Alice' },
321
- metadata: {
322
- custom_type: 'MESSAGE_ATTACHMENT',
323
- attachment_content_type: 'media',
324
- payment_status: 'paid',
325
- },
326
- },
327
- ])
328
-
329
- renderWithProviders(
330
- <CustomChannelPreview {...defaultProps} channel={channel} />
331
- )
332
-
333
- expect(screen.getByText('🔒 Sent a locked attachment')).toBeInTheDocument()
334
- })
335
-
336
- it('shows a locked indicator for an unpaid media attachment message', () => {
337
- const channel = createMockChannel([
338
- {
339
- id: 'msg-1',
340
- type: 'regular',
341
- created_at: new Date('2026-01-01T00:00:00.000Z'),
342
- user: { id: 'participant-1', name: 'Alice' },
343
- metadata: {
344
- custom_type: 'MESSAGE_ATTACHMENT',
345
- attachment_content_type: 'media',
346
- payment_status: 'pending',
347
- },
348
- },
349
- ])
350
-
351
- renderWithProviders(
352
- <CustomChannelPreview {...defaultProps} channel={channel} />
353
- )
354
-
355
- expect(screen.getByText('🔒 Sent a locked attachment')).toBeInTheDocument()
356
- })
357
-
358
263
  it('updates starred state when the channel membership changes', () => {
359
264
  const channel = createMockChannel([])
360
265
 
@@ -1,9 +1,6 @@
1
1
  import classNames from 'classnames'
2
2
  import React from 'react'
3
- import {
4
- ChannelPreviewUIComponentProps,
5
- useChatContext,
6
- } from 'stream-chat-react'
3
+ import { ChannelPreviewUIComponentProps, useChatContext } from 'stream-chat-react'
7
4
 
8
5
  import { useChannelStar } from '../../hooks/useChannelStar'
9
6
  import { formatRelativeTime } from '../../utils/formatRelativeTime'
@@ -88,23 +85,14 @@ const CustomChannelPreview = React.memo<ChannelPreviewUIComponentProps>(
88
85
  viewerLanguage,
89
86
  })
90
87
 
91
- const { custom_type, attachment_content_type } =
92
- lastMessage?.metadata || {}
93
-
94
- if (custom_type === 'MESSAGE_TIP') {
95
- return displayText ? displayText : 'Sent a tip'
96
- }
97
- if (custom_type === 'MESSAGE_PAID') {
98
- return displayText ? displayText : 'Sent a message'
99
- }
100
- if (custom_type === 'MESSAGE_ATTACHMENT') {
101
- if (attachment_content_type === 'text') {
102
- return '🔒 Sent a locked message'
103
- }
104
- if (attachment_content_type === 'media') {
105
- return '🔒 Sent a locked attachment'
106
- }
107
- }
88
+ const isTip = lastMessage?.metadata?.custom_type === 'MESSAGE_TIP'
89
+ if (isTip) return displayText ? `💵 ${displayText}` : '💵 Sent a tip'
90
+ const isPaid = lastMessage?.metadata?.custom_type === 'MESSAGE_PAID'
91
+ if (isPaid) return displayText ? `💰 ${displayText}` : '💰 Sent a message'
92
+ const isPaidAttachment =
93
+ lastMessage?.metadata?.custom_type === 'MESSAGE_ATTACHMENT'
94
+ if (isPaidAttachment)
95
+ return displayText ? `📎 ${displayText}` : '📎 Sent an attachment'
108
96
 
109
97
  if (displayText) return displayText
110
98
 
@@ -126,7 +126,6 @@ interface TemplateProps {
126
126
  attachment_mime_type?: string
127
127
  attachment_thumbnail?: string
128
128
  attachment_detail?: string
129
- attachment_content_type?: 'text' | 'media'
130
129
  }
131
130
  }>
132
131
  }
@@ -417,59 +416,7 @@ LockedAttachment.args = {
417
416
  ],
418
417
  }
419
418
 
420
- export const LockedTextAttachment: StoryFn<TemplateProps> = Template.bind({})
421
- LockedTextAttachment.args = {
422
- messages: [
423
- {
424
- id: 'msg-1',
425
- text: 'Can you send me the details privately?',
426
- user: storyUsers.visitor,
427
- },
428
- {
429
- id: 'msg-2',
430
- // Empty text: the real content is redacted server-side until purchase,
431
- // so the bubble renders the blurred placeholder instead.
432
- text: '',
433
- user: storyUsers.creator,
434
- metadata: {
435
- custom_type: 'MESSAGE_ATTACHMENT',
436
- amount_text: 'AU$4.99',
437
- attachment_content_type: 'text',
438
- },
439
- },
440
- {
441
- id: 'msg-3',
442
- text: '',
443
- user: storyUsers.creator,
444
- metadata: {
445
- custom_type: 'MESSAGE_ATTACHMENT',
446
- amount_text: 'AU$4.99',
447
- payment_status: 'paid',
448
- attachment_content_type: 'text',
449
- },
450
- },
451
- {
452
- id: 'msg-4',
453
- // Buyer reveal: backend writes the real text back onto the message.
454
- text: "Here's the address — see you Thursday at 7!",
455
- user: storyUsers.creator,
456
- metadata: {
457
- custom_type: 'MESSAGE_ATTACHMENT',
458
- amount_text: 'AU$4.99',
459
- payment_status: 'paid',
460
- attachment_content_type: 'text',
461
- },
462
- },
463
- ],
464
- }
465
- LockedTextAttachment.parameters = {
466
- docs: {
467
- description: {
468
- story:
469
- 'A paid text-only message renders as a regular bubble with blurred placeholder copy (msg-2: pending, msg-3: purchased-but-not-yet-revealed) until the real text is revealed (msg-4).',
470
- },
471
- },
472
- }
419
+
473
420
 
474
421
  export const ChatbotVariants: StoryFn<TemplateProps> = Template.bind({})
475
422
  ChatbotVariants.args = {
@@ -47,14 +47,6 @@ export const isAttachmentMessage = (message: LocalMessage): boolean => {
47
47
  return message.metadata?.custom_type === 'MESSAGE_ATTACHMENT'
48
48
  }
49
49
 
50
- export const isTextAttachmentMessage = (message: LocalMessage): boolean => {
51
- return isAttachmentMessage(message) && message.metadata?.attachment_content_type === 'text'
52
- }
53
-
54
- export const isMediaAttachmentMessage = (message: LocalMessage): boolean => {
55
- return isAttachmentMessage(message) && message.metadata?.attachment_content_type !== 'text'
56
- }
57
-
58
50
  /** Check if a message has a tip/paid tag (both render the same) */
59
51
  export const isTipOrPaidMessage = (message: LocalMessage): boolean => {
60
52
  return isTipMessage(message) || isPaidMessage(message)
@@ -1,6 +1,6 @@
1
1
  import { createContext, useContext } from 'react'
2
2
 
3
- import { defaultLockedAttachmentContextValue, type LockedAttachmentContextValue } from './LockedAttachment/types'
3
+ import { defaultLockedAttachmentContextValue, type LockedAttachmentContextValue } from '../LockedAttachment/types'
4
4
 
5
5
  export interface CustomMessageRegistry {
6
6
  LockedAttachment: LockedAttachmentContextValue