@linktr.ee/messaging-react 1.26.1 → 1.28.0-rc-1776225927

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/Creator-D38dWn2X.js +318 -0
  2. package/dist/Creator-D38dWn2X.js.map +1 -0
  3. package/dist/MediaPlayer-DE9MC6k6.js +599 -0
  4. package/dist/MediaPlayer-DE9MC6k6.js.map +1 -0
  5. package/dist/Preview-DqAv16NS.js +87 -0
  6. package/dist/Preview-DqAv16NS.js.map +1 -0
  7. package/dist/Visitor-BG-9-3HU.js +199 -0
  8. package/dist/Visitor-BG-9-3HU.js.map +1 -0
  9. package/dist/dash.all.min-Duv4lvGS.js +18858 -0
  10. package/dist/dash.all.min-Duv4lvGS.js.map +1 -0
  11. package/dist/hls-Bogc7CBn.js +21710 -0
  12. package/dist/hls-Bogc7CBn.js.map +1 -0
  13. package/dist/index-Da-xN4Yq.js +16142 -0
  14. package/dist/index-Da-xN4Yq.js.map +1 -0
  15. package/dist/index-Dj9rqWcU.js +69 -0
  16. package/dist/index-Dj9rqWcU.js.map +1 -0
  17. package/dist/index.d.ts +74 -10
  18. package/dist/index.js +979 -934
  19. package/dist/index.js.map +1 -1
  20. package/dist/mixin-B6jYfIcp.js +808 -0
  21. package/dist/mixin-B6jYfIcp.js.map +1 -0
  22. package/dist/react-BxlQMOfz.js +419 -0
  23. package/dist/react-BxlQMOfz.js.map +1 -0
  24. package/dist/react-COAP-MIW.js +377 -0
  25. package/dist/react-COAP-MIW.js.map +1 -0
  26. package/dist/react-Cn4WlMcl.js +3108 -0
  27. package/dist/react-Cn4WlMcl.js.map +1 -0
  28. package/dist/react-CwTJArKY.js +459 -0
  29. package/dist/react-CwTJArKY.js.map +1 -0
  30. package/dist/react-DkfS_atT.js +373 -0
  31. package/dist/react-DkfS_atT.js.map +1 -0
  32. package/dist/react-Pea5fum1.js +286 -0
  33. package/dist/react-Pea5fum1.js.map +1 -0
  34. package/dist/react-RiBbsUDd.js +534 -0
  35. package/dist/react-RiBbsUDd.js.map +1 -0
  36. package/dist/react-dS1WBxxz.js +238 -0
  37. package/dist/react-dS1WBxxz.js.map +1 -0
  38. package/package.json +2 -1
  39. package/src/components/ChannelView.tsx +12 -2
  40. package/src/components/CustomMessage/CustomMessage.stories.tsx +173 -41
  41. package/src/components/CustomMessage/MessageTag.tsx +5 -0
  42. package/src/components/CustomMessage/index.tsx +43 -4
  43. package/src/components/LockedAttachment/LockedAttachment.stories.tsx +343 -0
  44. package/src/components/LockedAttachment/components/Creator.tsx +469 -0
  45. package/src/components/LockedAttachment/components/MediaPlayer.tsx +359 -0
  46. package/src/components/LockedAttachment/components/Visitor.tsx +356 -0
  47. package/src/components/LockedAttachment/index.tsx +39 -0
  48. package/src/components/LockedAttachment/types.ts +17 -0
  49. package/src/components/LockedAttachment/utils/icons.ts +53 -0
  50. package/src/components/LockedAttachment/utils/mimeType.test.ts +119 -0
  51. package/src/components/LockedAttachment/utils/mimeType.ts +37 -0
  52. package/src/components/ParticipantPicker/index.tsx +8 -1
  53. package/src/hooks/useParticipants.ts +3 -2
  54. package/src/index.ts +4 -0
  55. package/src/stories/decorators/storyUser.tsx +37 -0
  56. package/src/stream-custom-data.ts +9 -3
  57. package/src/types.ts +20 -1
  58. package/src/utils/isDevBuild.ts +10 -0
@@ -0,0 +1,69 @@
1
+ var o = Object.defineProperty;
2
+ var g = (n, a, c) => a in n ? o(n, a, { enumerable: !0, configurable: !0, writable: !0, value: c }) : n[a] = c;
3
+ var l = (n, a, c) => g(n, typeof a != "symbol" ? a + "" : a, c);
4
+ function R(n) {
5
+ return class extends n {
6
+ constructor() {
7
+ super(...arguments);
8
+ l(this, "_playedRanges", []);
9
+ l(this, "_currentPlayedRange", null);
10
+ l(this, "_RANGE_EPSILON", 0.5);
11
+ l(this, "_seeking", !1);
12
+ }
13
+ connectedCallback() {
14
+ super.connectedCallback && super.connectedCallback(), this.addEventListener("play", () => this.onPlaybackStart({ time: this.currentTime })), this.addEventListener("pause", () => this.onPlaybackStop({ time: this.currentTime })), this.addEventListener("ended", () => this.onPlaybackStop({ time: this.currentTime })), this.addEventListener("seeking", () => this.onSeeking()), this.addEventListener("seeked", () => this.onSeeked({ time: this.currentTime }));
15
+ }
16
+ onPlaybackStart(e = {}) {
17
+ this._seeking = !1;
18
+ const { time: t } = e, s = typeof t == "number" ? t : this.currentTime;
19
+ this._currentPlayedRange || (this._currentPlayedRange = { start: s, end: s });
20
+ }
21
+ onSeeking() {
22
+ this._seeking = !0, this._commitCurrentRange();
23
+ }
24
+ onSeeked(e = {}) {
25
+ this._seeking = !1;
26
+ const { time: t } = e, s = typeof t == "number" ? t : this.currentTime;
27
+ this._currentPlayedRange = { start: s, end: s };
28
+ }
29
+ onPlaybackStop(e = {}) {
30
+ const { time: t } = e, s = typeof t == "number" ? t : this.currentTime;
31
+ this._commitCurrentRange(s);
32
+ }
33
+ _commitCurrentRange(e) {
34
+ if (!this._currentPlayedRange) return;
35
+ typeof e == "number" && (this._currentPlayedRange.end = e);
36
+ const { start: t, end: s } = this._currentPlayedRange;
37
+ this._currentPlayedRange = null, this.addPlayedRange(t, s);
38
+ }
39
+ addPlayedRange(e, t) {
40
+ if (e >= t) return;
41
+ const s = this._RANGE_EPSILON, h = [...this._playedRanges, { start: e, end: t }];
42
+ h.sort((i, r) => i.start - r.start);
43
+ const d = [];
44
+ for (const i of h) {
45
+ if (!d.length) {
46
+ d.push({ ...i });
47
+ continue;
48
+ }
49
+ const r = d[d.length - 1];
50
+ i.start <= r.end + s ? (r.start = Math.min(r.start, i.start), r.end = Math.max(r.end, i.end)) : d.push({ ...i });
51
+ }
52
+ this._playedRanges = d;
53
+ }
54
+ get played() {
55
+ const e = this.currentTime;
56
+ return !this.paused && !this._currentPlayedRange && typeof e == "number" && (this._currentPlayedRange = { start: e, end: e }), this._currentPlayedRange && typeof e == "number" && (e > this._currentPlayedRange.end && (this._currentPlayedRange.end = e), this.addPlayedRange(this._currentPlayedRange.start, this._currentPlayedRange.end)), this._playedRanges.length ? u(this._playedRanges.map((t) => [t.start, t.end])) : u([[0, 0]]);
57
+ }
58
+ };
59
+ }
60
+ function u(n) {
61
+ return Object.defineProperties(n, {
62
+ start: { value: (a) => n[a][0] },
63
+ end: { value: (a) => n[a][1] }
64
+ }), n;
65
+ }
66
+ export {
67
+ R as M
68
+ };
69
+ //# sourceMappingURL=index-Dj9rqWcU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-Dj9rqWcU.js","sources":["../../../node_modules/media-played-ranges-mixin/dist/index.js"],"sourcesContent":["function MediaPlayedRangesMixin(Base) {\n return class MediaPlayedRanges extends Base {\n _playedRanges = [];\n _currentPlayedRange = null;\n _RANGE_EPSILON = 0.5;\n _seeking = false;\n connectedCallback() {\n if (super.connectedCallback) super.connectedCallback();\n this.addEventListener(\"play\", () => this.onPlaybackStart({ time: this.currentTime }));\n this.addEventListener(\"pause\", () => this.onPlaybackStop({ time: this.currentTime }));\n this.addEventListener(\"ended\", () => this.onPlaybackStop({ time: this.currentTime }));\n this.addEventListener(\"seeking\", () => this.onSeeking());\n this.addEventListener(\"seeked\", () => this.onSeeked({ time: this.currentTime }));\n }\n onPlaybackStart(param = {}) {\n this._seeking = false;\n const { time } = param;\n const t = typeof time === \"number\" ? time : this.currentTime;\n if (!this._currentPlayedRange) {\n this._currentPlayedRange = { start: t, end: t };\n }\n }\n onSeeking() {\n this._seeking = true;\n this._commitCurrentRange();\n }\n onSeeked(param = {}) {\n this._seeking = false;\n const { time } = param;\n const t = typeof time === \"number\" ? time : this.currentTime;\n this._currentPlayedRange = { start: t, end: t };\n }\n onPlaybackStop(param = {}) {\n const { time } = param;\n const t = typeof time === \"number\" ? time : this.currentTime;\n this._commitCurrentRange(t);\n }\n _commitCurrentRange(time) {\n if (!this._currentPlayedRange) return;\n if (typeof time === \"number\") {\n this._currentPlayedRange.end = time;\n }\n const { start, end } = this._currentPlayedRange;\n this._currentPlayedRange = null;\n this.addPlayedRange(start, end);\n }\n addPlayedRange(start, end) {\n if (start >= end) return;\n const EPS = this._RANGE_EPSILON;\n const allRanges = [...this._playedRanges, { start, end }];\n allRanges.sort((a, b) => a.start - b.start);\n const merged = [];\n for (const range of allRanges) {\n if (!merged.length) {\n merged.push({ ...range });\n continue;\n }\n const last = merged[merged.length - 1];\n if (range.start <= last.end + EPS) {\n last.start = Math.min(last.start, range.start);\n last.end = Math.max(last.end, range.end);\n } else {\n merged.push({ ...range });\n }\n }\n this._playedRanges = merged;\n }\n get played() {\n const time = this.currentTime;\n if (!this.paused && !this._currentPlayedRange && typeof time === \"number\") {\n this._currentPlayedRange = { start: time, end: time };\n }\n if (this._currentPlayedRange && typeof time === \"number\") {\n if (time > this._currentPlayedRange.end) {\n this._currentPlayedRange.end = time;\n }\n this.addPlayedRange(this._currentPlayedRange.start, this._currentPlayedRange.end);\n }\n if (!this._playedRanges.length) {\n return createTimeRangesObj([[0, 0]]);\n }\n return createTimeRangesObj(this._playedRanges.map((r) => [r.start, r.end]));\n }\n };\n}\nfunction createTimeRangesObj(ranges) {\n Object.defineProperties(ranges, {\n start: { value: (i) => ranges[i][0] },\n end: { value: (i) => ranges[i][1] }\n });\n return ranges;\n}\nexport {\n MediaPlayedRangesMixin\n};\n"],"names":["MediaPlayedRangesMixin","Base","__publicField","param","time","t","start","end","EPS","allRanges","a","b","merged","range","last","createTimeRangesObj","r","ranges","i"],"mappings":";;;AAAA,SAASA,EAAuBC,GAAM;AACpC,SAAO,cAAgCA,EAAK;AAAA,IAArC;AAAA;AACL,MAAAC,EAAA,uBAAgB,CAAA;AAChB,MAAAA,EAAA,6BAAsB;AACtB,MAAAA,EAAA,wBAAiB;AACjB,MAAAA,EAAA,kBAAW;AAAA;AAAA,IACX,oBAAoB;AAClB,MAAI,MAAM,qBAAmB,MAAM,kBAAiB,GACpD,KAAK,iBAAiB,QAAQ,MAAM,KAAK,gBAAgB,EAAE,MAAM,KAAK,YAAW,CAAE,CAAC,GACpF,KAAK,iBAAiB,SAAS,MAAM,KAAK,eAAe,EAAE,MAAM,KAAK,YAAW,CAAE,CAAC,GACpF,KAAK,iBAAiB,SAAS,MAAM,KAAK,eAAe,EAAE,MAAM,KAAK,YAAW,CAAE,CAAC,GACpF,KAAK,iBAAiB,WAAW,MAAM,KAAK,UAAS,CAAE,GACvD,KAAK,iBAAiB,UAAU,MAAM,KAAK,SAAS,EAAE,MAAM,KAAK,YAAW,CAAE,CAAC;AAAA,IACjF;AAAA,IACA,gBAAgBC,IAAQ,IAAI;AAC1B,WAAK,WAAW;AAChB,YAAM,EAAE,MAAAC,EAAI,IAAKD,GACXE,IAAI,OAAOD,KAAS,WAAWA,IAAO,KAAK;AACjD,MAAK,KAAK,wBACR,KAAK,sBAAsB,EAAE,OAAOC,GAAG,KAAKA,EAAC;AAAA,IAEjD;AAAA,IACA,YAAY;AACV,WAAK,WAAW,IAChB,KAAK,oBAAmB;AAAA,IAC1B;AAAA,IACA,SAASF,IAAQ,IAAI;AACnB,WAAK,WAAW;AAChB,YAAM,EAAE,MAAAC,EAAI,IAAKD,GACXE,IAAI,OAAOD,KAAS,WAAWA,IAAO,KAAK;AACjD,WAAK,sBAAsB,EAAE,OAAOC,GAAG,KAAKA,EAAC;AAAA,IAC/C;AAAA,IACA,eAAeF,IAAQ,IAAI;AACzB,YAAM,EAAE,MAAAC,EAAI,IAAKD,GACXE,IAAI,OAAOD,KAAS,WAAWA,IAAO,KAAK;AACjD,WAAK,oBAAoBC,CAAC;AAAA,IAC5B;AAAA,IACA,oBAAoBD,GAAM;AACxB,UAAI,CAAC,KAAK,oBAAqB;AAC/B,MAAI,OAAOA,KAAS,aAClB,KAAK,oBAAoB,MAAMA;AAEjC,YAAM,EAAE,OAAAE,GAAO,KAAAC,EAAG,IAAK,KAAK;AAC5B,WAAK,sBAAsB,MAC3B,KAAK,eAAeD,GAAOC,CAAG;AAAA,IAChC;AAAA,IACA,eAAeD,GAAOC,GAAK;AACzB,UAAID,KAASC,EAAK;AAClB,YAAMC,IAAM,KAAK,gBACXC,IAAY,CAAC,GAAG,KAAK,eAAe,EAAE,OAAAH,GAAO,KAAAC,GAAK;AACxD,MAAAE,EAAU,KAAK,CAACC,GAAGC,MAAMD,EAAE,QAAQC,EAAE,KAAK;AAC1C,YAAMC,IAAS,CAAA;AACf,iBAAWC,KAASJ,GAAW;AAC7B,YAAI,CAACG,EAAO,QAAQ;AAClB,UAAAA,EAAO,KAAK,EAAE,GAAGC,GAAO;AACxB;AAAA,QACF;AACA,cAAMC,IAAOF,EAAOA,EAAO,SAAS,CAAC;AACrC,QAAIC,EAAM,SAASC,EAAK,MAAMN,KAC5BM,EAAK,QAAQ,KAAK,IAAIA,EAAK,OAAOD,EAAM,KAAK,GAC7CC,EAAK,MAAM,KAAK,IAAIA,EAAK,KAAKD,EAAM,GAAG,KAEvCD,EAAO,KAAK,EAAE,GAAGC,GAAO;AAAA,MAE5B;AACA,WAAK,gBAAgBD;AAAA,IACvB;AAAA,IACA,IAAI,SAAS;AACX,YAAMR,IAAO,KAAK;AAUlB,aATI,CAAC,KAAK,UAAU,CAAC,KAAK,uBAAuB,OAAOA,KAAS,aAC/D,KAAK,sBAAsB,EAAE,OAAOA,GAAM,KAAKA,EAAI,IAEjD,KAAK,uBAAuB,OAAOA,KAAS,aAC1CA,IAAO,KAAK,oBAAoB,QAClC,KAAK,oBAAoB,MAAMA,IAEjC,KAAK,eAAe,KAAK,oBAAoB,OAAO,KAAK,oBAAoB,GAAG,IAE7E,KAAK,cAAc,SAGjBW,EAAoB,KAAK,cAAc,IAAI,CAACC,MAAM,CAACA,EAAE,OAAOA,EAAE,GAAG,CAAC,CAAC,IAFjED,EAAoB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AAAA,IAGvC;AAAA,EACJ;AACA;AACA,SAASA,EAAoBE,GAAQ;AACnC,gBAAO,iBAAiBA,GAAQ;AAAA,IAC9B,OAAO,EAAE,OAAO,CAACC,MAAMD,EAAOC,CAAC,EAAE,CAAC,EAAC;AAAA,IACnC,KAAK,EAAE,OAAO,CAACA,MAAMD,EAAOC,CAAC,EAAE,CAAC,EAAC;AAAA,EACrC,CAAG,GACMD;AACT;","x_google_ignoreList":[0]}
package/dist/index.d.ts CHANGED
@@ -20,6 +20,8 @@ export declare interface ActionButtonProps extends default_2.ButtonHTMLAttribute
20
20
 
21
21
  declare type AgeSafetySystemType = 'SYSTEM_AGE_SAFETY_BLOCKED';
22
22
 
23
+ export declare type AttachmentSourceType = 'image' | 'audio' | 'video' | 'document';
24
+
23
25
  /**
24
26
  * Avatar component that displays a user image or colored initial fallback
25
27
  */
@@ -109,7 +111,7 @@ export declare const ChannelView: default_2.NamedExoticComponent<ChannelViewProp
109
111
  * Props that MessagingShell passes through to ChannelView.
110
112
  * ChannelViewProps is the source of truth for these props.
111
113
  */
112
- declare type ChannelViewPassthroughProps = Pick<ChannelViewProps, 'renderMessageInputActions' | 'renderConversationFooter' | 'CustomChannelEmptyState' | 'onDeleteConversationClick' | 'onBlockParticipantClick' | 'onReportParticipantClick' | 'dmAgentEnabled' | 'messageMetadata' | 'onMessageSent' | 'showStarButton' | 'chatbotVotingEnabled' | 'renderChannelBanner' | 'customProfileContent' | 'customChannelActions' | 'renderMessage'>;
114
+ declare type ChannelViewPassthroughProps = Pick<ChannelViewProps, 'renderMessageInputActions' | 'renderConversationFooter' | 'CustomChannelEmptyState' | 'onDeleteConversationClick' | 'onBlockParticipantClick' | 'onReportParticipantClick' | 'dmAgentEnabled' | 'messageMetadata' | 'onMessageSent' | 'showStarButton' | 'chatbotVotingEnabled' | 'renderChannelBanner' | 'customProfileContent' | 'customChannelActions' | 'renderMessage' | 'onAttachmentUnlock' | 'onAttachmentDownload'>;
113
115
 
114
116
  /**
115
117
  * ChannelView component props
@@ -155,7 +157,7 @@ export declare interface ChannelViewProps {
155
157
  * @example
156
158
  * messageMetadata={{ custom_type: 'MESSAGE_PAID', listing_id: '...' }}
157
159
  */
158
- messageMetadata?: Pick<MessageMetadata, 'custom_type' | 'listing_id'>;
160
+ messageMetadata?: Partial<MessageMetadata>;
159
161
  /**
160
162
  * Callback fired after a message is successfully sent.
161
163
  * Receives the full API response including message.id.
@@ -214,6 +216,26 @@ export declare interface ChannelViewProps {
214
216
  * )}
215
217
  */
216
218
  renderMessage?: (messageNode: React.ReactElement, message: LocalMessage) => React.ReactNode;
219
+ /**
220
+ * Called when the visitor clicks Unlock on a locked attachment message.
221
+ * Receives the message and channel. Show checkout, confirm payment, fetch
222
+ * the unlocked URL. `attachment_source` must NOT be stored on the Stream message metadata.
223
+ * The card shows a loading state for the full duration of the promise.
224
+ */
225
+ onAttachmentUnlock?: (message: LocalMessage, channel: Channel) => Promise<LockedAttachmentSource>;
226
+ /**
227
+ * Called when the visitor clicks Download on an unlocked attachment message.
228
+ */
229
+ onAttachmentDownload?: (message: LocalMessage, channel: Channel) => void;
230
+ }
231
+
232
+ declare interface CreatorCardProps extends LockedAttachmentBaseProps {
233
+ title?: string;
234
+ /** When true, shows interactive media preview (composing state). When false/omitted, shows static thumbnail (sent/sold state). */
235
+ isPreview?: boolean;
236
+ placeholderTitle?: string;
237
+ placeholderAmountText?: string;
238
+ onDismiss?: () => void;
217
239
  }
218
240
 
219
241
  declare type DmAgentSystemType = 'SYSTEM_DM_AGENT_PAUSED' | 'SYSTEM_DM_AGENT_RESUMED';
@@ -253,18 +275,42 @@ export declare interface FaqListProps {
253
275
  */
254
276
  export declare const formatRelativeTime: (date: Date) => string;
255
277
 
256
- declare type MessageCustomType = 'MESSAGE_TIP' | 'MESSAGE_PAID' | 'MESSAGE_CHATBOT' | AgeSafetySystemType | DmAgentSystemType;
278
+ export declare const LockedAttachment: (props: LockedAttachmentProps) => JSX_2.Element;
279
+
280
+ /** Shared fields for creator and visitor locked-attachment cards (internal). */
281
+ declare interface LockedAttachmentBaseProps {
282
+ title?: string;
283
+ mimeType?: string;
284
+ /** Preview image. Video/image: pass blurred version. Audio/document: pass unblurred version. */
285
+ thumbnail?: string;
286
+ /** Unlocked media URL. Undefined while locked or pending unlock. */
287
+ source?: string;
288
+ detail?: string;
289
+ amountText?: string;
290
+ paymentStatus?: PaymentStatus;
291
+ }
292
+
293
+ export declare type LockedAttachmentProps = ({
294
+ isCreator: true;
295
+ } & CreatorCardProps) | ({
296
+ isCreator?: false;
297
+ } & VisitorCardProps);
298
+
299
+ export declare interface LockedAttachmentSource {
300
+ source: string;
301
+ }
302
+
303
+ declare type MessageCustomType = 'MESSAGE_TIP' | 'MESSAGE_PAID' | 'MESSAGE_CHATBOT' | 'MESSAGE_ATTACHMENT' | AgeSafetySystemType | DmAgentSystemType;
257
304
 
258
- /**
259
- * Message metadata for paid messaging and chatbot flows.
260
- * Used to identify message types and payment status.
261
- */
262
305
  export declare interface MessageMetadata {
263
306
  custom_type?: MessageCustomType;
264
- amount_text?: string;
265
- payment_status?: string;
266
- payment_intent_id?: string;
267
307
  listing_id?: string;
308
+ amount_text?: string;
309
+ payment_status?: PaymentStatus;
310
+ attachment_title?: string;
311
+ attachment_mime_type?: string;
312
+ attachment_thumbnail?: string;
313
+ attachment_detail?: string;
268
314
  }
269
315
 
270
316
  export declare const MessageVoteButtons: default_2.FC<MessageVoteButtonsProps>;
@@ -431,6 +477,12 @@ export declare interface ParticipantSource {
431
477
  loading?: boolean;
432
478
  }
433
479
 
480
+ /**
481
+ * Message metadata for paid messaging and chatbot flows.
482
+ * Used to identify message types and payment status.
483
+ */
484
+ declare type PaymentStatus = 'pending' | 'paid' | 'failed' | 'refunded';
485
+
434
486
  /**
435
487
  * Hook that wraps Stream Chat reactions to provide toggle-style
436
488
  * upvote/downvote behavior on a message.
@@ -470,6 +522,18 @@ export declare const useParticipants: (participantSource: ParticipantSource, opt
470
522
  refresh: () => void;
471
523
  };
472
524
 
525
+ declare interface VisitorCardProps extends LockedAttachmentBaseProps {
526
+ title?: string;
527
+ /**
528
+ * Called when the visitor clicks Unlock. Return the resolved source URL.
529
+ * The component manages loading state and sets source internally on resolution.
530
+ * Omit to hide the Unlock button.
531
+ */
532
+ onUnlock?: () => Promise<LockedAttachmentSource>;
533
+ /** Called when the visitor clicks Download on an unlocked card. */
534
+ onDownload?: () => void;
535
+ }
536
+
473
537
  export declare type VoteSelection = 'up' | 'down' | null;
474
538
 
475
539
  export { }