@linktr.ee/messaging-react 2.4.0 → 2.4.2
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/{Card-3s62K02i.js → Card-B8CGfnPN.js} +16 -16
- package/dist/{Card-3s62K02i.js.map → Card-B8CGfnPN.js.map} +1 -1
- package/dist/{Card-LQWaY4ng.cjs → Card-BFTHMj8n.cjs} +2 -2
- package/dist/{Card-LQWaY4ng.cjs.map → Card-BFTHMj8n.cjs.map} +1 -1
- package/dist/{Card-CPl5CfCo.cjs → Card-CwFkVePn.cjs} +2 -2
- package/dist/{Card-CPl5CfCo.cjs.map → Card-CwFkVePn.cjs.map} +1 -1
- package/dist/{Card-pMjhg42K.js → Card-D8Z8WnS6.js} +6 -6
- package/dist/{Card-pMjhg42K.js.map → Card-D8Z8WnS6.js.map} +1 -1
- package/dist/{Card-Cp6OyEWg.cjs → Card-sogfIdhf.cjs} +2 -2
- package/dist/{Card-Cp6OyEWg.cjs.map → Card-sogfIdhf.cjs.map} +1 -1
- package/dist/{Card-CkyEIXm3.js → Card-tGCMHgKp.js} +19 -19
- package/dist/{Card-CkyEIXm3.js.map → Card-tGCMHgKp.js.map} +1 -1
- package/dist/{LockedThumbnail-DbGrvo6R.cjs → LockedThumbnail-DLtrbU8H.cjs} +2 -2
- package/dist/{LockedThumbnail-DbGrvo6R.cjs.map → LockedThumbnail-DLtrbU8H.cjs.map} +1 -1
- package/dist/{LockedThumbnail-CjznOfiC.js → LockedThumbnail-WG8CysWx.js} +8 -8
- package/dist/{LockedThumbnail-CjznOfiC.js.map → LockedThumbnail-WG8CysWx.js.map} +1 -1
- package/dist/index-C541s_4h.js +4740 -0
- package/dist/index-C541s_4h.js.map +1 -0
- package/dist/index-DYLdOjSj.cjs +2 -0
- package/dist/index-DYLdOjSj.cjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +17 -2
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/components/ChannelView.test.tsx +58 -2
- package/src/components/ChannelView.tsx +10 -3
- package/src/components/CustomMessage/index.tsx +1 -1
- package/src/components/LinkAttachment/LinkAttachment.test.tsx +35 -1
- package/src/components/LinkAttachment/components/Sent/Card.tsx +66 -25
- package/src/components/LinkAttachment/components/_shared/CardShell.tsx +4 -3
- package/src/types.ts +8 -2
- package/dist/index-BX305h7q.cjs +0 -18
- package/dist/index-BX305h7q.cjs.map +0 -1
- package/dist/index-DVh2uNBI.js +0 -8142
- package/dist/index-DVh2uNBI.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-DYLdOjSj.cjs");exports.ActionButton=e.ActionButton;exports.Avatar=e.Avatar;exports.ChannelEmptyState=e.ChannelEmptyState;exports.ChannelList=e.ChannelList;exports.ChannelView=e.ChannelView;exports.CustomMessageProvider=e.CustomMessageProvider;exports.FaqList=e.FaqList;exports.FaqListItem=e.FaqListItem;exports.LinkAttachment=e.LinkAttachment;exports.LockedAttachment=e.LockedAttachment;exports.MediaMessage=e.MediaMessage;exports.MessageAttachment=e.MessageAttachment;exports.MessageVoteButtons=e.MessageVoteButtons;exports.MessagingProvider=e.MessagingProvider;exports.MessagingShell=e.MessagingShell;exports.buildCompactMetaLabel=e.buildCompactMetaLabel;exports.formatFileSize=e.formatFileSize;exports.formatRelativeTime=e.formatRelativeTime;exports.getFileExtensionLabel=e.getFileExtensionLabel;exports.getMessageDisplayText=e.getMessageDisplayText;exports.isLinkAttachment=e.isLinkAttachment;exports.isUuidLike=e.isUuidLike;exports.messageAttachmentGroupPositionFromStream=e.bubbleGroupPositionFromStream;exports.normalizeLanguageCode=e.normalizeLanguageCode;exports.resolveLinkAttachment=e.resolveLinkAttachment;exports.resolveMediaFromMessage=e.resolveMediaFromMessage;exports.resolveParticipantDisplayName=e.resolveParticipantDisplayName;exports.useCustomMessage=e.useCustomMessage;exports.useMessageVote=e.useMessageVote;exports.useMessaging=e.useMessaging;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.d.ts
CHANGED
|
@@ -610,6 +610,18 @@ export declare interface LinkAttachmentReceivedCardProps extends LinkAttachmentB
|
|
|
610
610
|
}
|
|
611
611
|
|
|
612
612
|
export declare interface LinkAttachmentSentCardProps extends LinkAttachmentBaseProps {
|
|
613
|
+
/**
|
|
614
|
+
* Fired when the sender activates their own posted card. Mirrors the
|
|
615
|
+
* `Received` variant so analytics fires symmetrically on both sides
|
|
616
|
+
* of the conversation. Behavior depends on configuration:
|
|
617
|
+
* - **Link app with a URL**: the card chrome is an `<a target="_blank">`
|
|
618
|
+
* opening `url`; `onClick` fires alongside the navigation.
|
|
619
|
+
* - **Link app with a CTA**: the CTA owns navigation; `onClick` is
|
|
620
|
+
* ignored (the CTA's own `onClick` is the analytics hook).
|
|
621
|
+
* - **Video / audio link previews**: the shell stays non-interactive
|
|
622
|
+
* so the native media controls remain operable; `onClick` is ignored.
|
|
623
|
+
*/
|
|
624
|
+
onClick?: () => void;
|
|
613
625
|
}
|
|
614
626
|
|
|
615
627
|
export declare const LockedAttachment: {
|
|
@@ -1054,10 +1066,13 @@ declare type MessageCustomType = 'MESSAGE_TIP' | 'MESSAGE_PAID' | 'MESSAGE_CHATB
|
|
|
1054
1066
|
|
|
1055
1067
|
/**
|
|
1056
1068
|
* Callback invoked when a user clicks a link inside the channel view.
|
|
1057
|
-
* Receives the clicked URL
|
|
1069
|
+
* Receives the clicked URL and, when resolvable, the message the link
|
|
1070
|
+
* was rendered in (so consumers can filter on sender or metadata).
|
|
1071
|
+
* `message` is `undefined` when the click happens on a link outside a
|
|
1072
|
+
* resolvable message wrapper. Fires alongside the native navigation,
|
|
1058
1073
|
* not in place of it.
|
|
1059
1074
|
*/
|
|
1060
|
-
export declare type MessageLinkClickHandler = (url: string) => void;
|
|
1075
|
+
export declare type MessageLinkClickHandler = (url: string, message: LocalMessage | undefined) => void;
|
|
1061
1076
|
|
|
1062
1077
|
export declare interface MessageMetadata {
|
|
1063
1078
|
custom_type?: MessageCustomType;
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as e, b as t, C as i, c as n, d as o, e as m, F as g, f as l, L as r, h as M, M as u, i as L, j as c, k as h, l as d, m as p, n as v, o as A, p as C, q as F, s as k, t as b, u as f, v as x, w as y, x as P, y as S, z as q, B as z, D as B } from "./index-
|
|
1
|
+
import { a as e, b as t, C as i, c as n, d as o, e as m, F as g, f as l, L as r, h as M, M as u, i as L, j as c, k as h, l as d, m as p, n as v, o as A, p as C, q as F, s as k, t as b, u as f, v as x, w as y, x as P, y as S, z as q, B as z, D as B } from "./index-C541s_4h.js";
|
|
2
2
|
export {
|
|
3
3
|
e as ActionButton,
|
|
4
4
|
t as Avatar,
|
package/package.json
CHANGED
|
@@ -357,7 +357,7 @@ describe('ChannelView', () => {
|
|
|
357
357
|
expect(screen.getAllByText('Custom Label').length).toBeGreaterThan(0)
|
|
358
358
|
})
|
|
359
359
|
|
|
360
|
-
it('fires onMessageLinkClick with the href when
|
|
360
|
+
it('fires onMessageLinkClick with the href and undefined message when the link is not inside a message wrapper', () => {
|
|
361
361
|
const handler = vi.fn()
|
|
362
362
|
const { container } = renderWithProviders(
|
|
363
363
|
<ChannelView channel={createChannel()} onMessageLinkClick={handler} />
|
|
@@ -372,7 +372,63 @@ describe('ChannelView', () => {
|
|
|
372
372
|
anchor.click()
|
|
373
373
|
|
|
374
374
|
expect(handler).toHaveBeenCalledOnce()
|
|
375
|
-
expect(handler).toHaveBeenCalledWith(
|
|
375
|
+
expect(handler).toHaveBeenCalledWith(
|
|
376
|
+
'https://example.com/clicked',
|
|
377
|
+
undefined
|
|
378
|
+
)
|
|
379
|
+
})
|
|
380
|
+
|
|
381
|
+
it('resolves the surrounding message from channel state and passes it to onMessageLinkClick', () => {
|
|
382
|
+
const handler = vi.fn()
|
|
383
|
+
const message = {
|
|
384
|
+
id: 'message-42',
|
|
385
|
+
text: 'check this out https://example.com/clicked',
|
|
386
|
+
metadata: { custom_type: 'MESSAGE_CHATBOT' },
|
|
387
|
+
} as unknown as ReturnType<
|
|
388
|
+
Channel['state']['formatMessage']
|
|
389
|
+
>
|
|
390
|
+
const channel = createChannel()
|
|
391
|
+
;(
|
|
392
|
+
channel.state as unknown as { messages: typeof message[] }
|
|
393
|
+
).messages = [message]
|
|
394
|
+
|
|
395
|
+
const { container } = renderWithProviders(
|
|
396
|
+
<ChannelView channel={channel} onMessageLinkClick={handler} />
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
const wrapper = document.createElement('div')
|
|
400
|
+
wrapper.setAttribute('data-message-id', 'message-42')
|
|
401
|
+
const anchor = document.createElement('a')
|
|
402
|
+
anchor.href = 'https://example.com/clicked'
|
|
403
|
+
anchor.addEventListener('click', (e) => e.preventDefault())
|
|
404
|
+
wrapper.appendChild(anchor)
|
|
405
|
+
container.querySelector('.messaging-channel-view')?.appendChild(wrapper)
|
|
406
|
+
anchor.click()
|
|
407
|
+
|
|
408
|
+
expect(handler).toHaveBeenCalledOnce()
|
|
409
|
+
expect(handler).toHaveBeenCalledWith('https://example.com/clicked', message)
|
|
410
|
+
})
|
|
411
|
+
|
|
412
|
+
it('passes undefined when the wrapper data-message-id does not match any message in state', () => {
|
|
413
|
+
const handler = vi.fn()
|
|
414
|
+
const { container } = renderWithProviders(
|
|
415
|
+
<ChannelView channel={createChannel()} onMessageLinkClick={handler} />
|
|
416
|
+
)
|
|
417
|
+
|
|
418
|
+
const wrapper = document.createElement('div')
|
|
419
|
+
wrapper.setAttribute('data-message-id', 'unknown-id')
|
|
420
|
+
const anchor = document.createElement('a')
|
|
421
|
+
anchor.href = 'https://example.com/clicked'
|
|
422
|
+
anchor.addEventListener('click', (e) => e.preventDefault())
|
|
423
|
+
wrapper.appendChild(anchor)
|
|
424
|
+
container.querySelector('.messaging-channel-view')?.appendChild(wrapper)
|
|
425
|
+
anchor.click()
|
|
426
|
+
|
|
427
|
+
expect(handler).toHaveBeenCalledOnce()
|
|
428
|
+
expect(handler).toHaveBeenCalledWith(
|
|
429
|
+
'https://example.com/clicked',
|
|
430
|
+
undefined
|
|
431
|
+
)
|
|
376
432
|
})
|
|
377
433
|
|
|
378
434
|
it('does not throw when a link is clicked without onMessageLinkClick set', () => {
|
|
@@ -538,13 +538,20 @@ export const ChannelView = React.memo<ChannelViewProps>(
|
|
|
538
538
|
const container = containerRef.current
|
|
539
539
|
if (!container) return
|
|
540
540
|
const handler = (event: MouseEvent) => {
|
|
541
|
-
const
|
|
541
|
+
const target = event.target as HTMLElement | null
|
|
542
|
+
const anchor = target?.closest('a[href]')
|
|
542
543
|
const href = anchor?.getAttribute('href')
|
|
543
|
-
if (href)
|
|
544
|
+
if (!href) return
|
|
545
|
+
const messageWrapper = anchor?.closest<HTMLElement>('[data-message-id]')
|
|
546
|
+
const messageId = messageWrapper?.getAttribute('data-message-id')
|
|
547
|
+
const message = messageId
|
|
548
|
+
? channel.state.messages.find((m) => m.id === messageId)
|
|
549
|
+
: undefined
|
|
550
|
+
onMessageLinkClick(href, message)
|
|
544
551
|
}
|
|
545
552
|
container.addEventListener('click', handler)
|
|
546
553
|
return () => container.removeEventListener('click', handler)
|
|
547
|
-
}, [onMessageLinkClick])
|
|
554
|
+
}, [onMessageLinkClick, channel])
|
|
548
555
|
|
|
549
556
|
return (
|
|
550
557
|
<div
|
|
@@ -194,7 +194,7 @@ const CustomMessageWithContext = (props: CustomMessageWithContextProps) => {
|
|
|
194
194
|
open={isBounceDialogOpen}
|
|
195
195
|
/>
|
|
196
196
|
)}
|
|
197
|
-
<div className={rootClassName} key={message.id}>
|
|
197
|
+
<div className={rootClassName} key={message.id} data-message-id={message.id}>
|
|
198
198
|
{PinIndicator && <PinIndicator />}
|
|
199
199
|
{!!reminder && <ReminderNotification reminder={reminder} />}
|
|
200
200
|
{message.user && (
|
|
@@ -54,16 +54,50 @@ describe('LinkAttachment.Received (link previews)', () => {
|
|
|
54
54
|
})
|
|
55
55
|
|
|
56
56
|
describe('LinkAttachment.Sent', () => {
|
|
57
|
-
it('renders the dark variant
|
|
57
|
+
it('renders the dark variant as an external link when url is set', async () => {
|
|
58
|
+
const handleClick = vi.fn()
|
|
58
59
|
renderWithProviders(
|
|
59
60
|
<LinkAttachment.Sent
|
|
60
61
|
title="My Playlist"
|
|
61
62
|
description="A handpicked workout mix"
|
|
62
63
|
url="tr.ee/briemix"
|
|
64
|
+
onClick={handleClick}
|
|
65
|
+
/>
|
|
66
|
+
)
|
|
67
|
+
const link = await screen.findByRole('link', { name: /My Playlist/i })
|
|
68
|
+
expect(link.tagName).toBe('A')
|
|
69
|
+
expect(link.getAttribute('href')).toBe('https://tr.ee/briemix')
|
|
70
|
+
expect(link.getAttribute('target')).toBe('_blank')
|
|
71
|
+
expect(link.getAttribute('rel')).toBe('noopener noreferrer')
|
|
72
|
+
fireEvent.click(link)
|
|
73
|
+
expect(handleClick).toHaveBeenCalledTimes(1)
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
it('stays non-interactive when no url is set', async () => {
|
|
77
|
+
renderWithProviders(
|
|
78
|
+
<LinkAttachment.Sent
|
|
79
|
+
title="My Playlist"
|
|
80
|
+
description="A handpicked workout mix"
|
|
63
81
|
/>
|
|
64
82
|
)
|
|
65
83
|
expect(await screen.findByText('My Playlist')).toBeInTheDocument()
|
|
66
84
|
expect(screen.queryByRole('button')).toBeNull()
|
|
67
85
|
expect(screen.queryByRole('link')).toBeNull()
|
|
68
86
|
})
|
|
87
|
+
|
|
88
|
+
it('lets the CTA own navigation when one is set (shell stays non-interactive)', async () => {
|
|
89
|
+
renderWithProviders(
|
|
90
|
+
<LinkAttachment.Sent
|
|
91
|
+
title="FAQ"
|
|
92
|
+
description="Get answers"
|
|
93
|
+
url="tr.ee/briemix"
|
|
94
|
+
cta={{ label: 'View FAQs', href: 'tr.ee/faq' }}
|
|
95
|
+
/>
|
|
96
|
+
)
|
|
97
|
+
expect(await screen.findByText('FAQ')).toBeInTheDocument()
|
|
98
|
+
const links = screen.getAllByRole('link')
|
|
99
|
+
expect(links).toHaveLength(1)
|
|
100
|
+
expect(links[0].getAttribute('href')).toBe('https://tr.ee/faq')
|
|
101
|
+
expect(links[0]).toHaveTextContent('View FAQs')
|
|
102
|
+
})
|
|
69
103
|
})
|
|
@@ -6,14 +6,32 @@ import CardShell from '../_shared/CardShell'
|
|
|
6
6
|
import CardThumbnail, {
|
|
7
7
|
AUDIO_BG_CLASS,
|
|
8
8
|
isPlayableAudio,
|
|
9
|
+
isPlayableMedia,
|
|
9
10
|
} from '../_shared/CardThumbnail'
|
|
11
|
+
import { normalizeExternalHref } from '../_shared/normalizeExternalHref'
|
|
10
12
|
|
|
11
|
-
export interface SentCardProps extends LinkAttachmentBaseProps {
|
|
13
|
+
export interface SentCardProps extends LinkAttachmentBaseProps {
|
|
14
|
+
/**
|
|
15
|
+
* Fired when the sender activates their own posted card. Mirrors the
|
|
16
|
+
* `Received` variant so analytics fires symmetrically on both sides
|
|
17
|
+
* of the conversation. Behavior depends on configuration:
|
|
18
|
+
* - **Link app with a URL**: the card chrome is an `<a target="_blank">`
|
|
19
|
+
* opening `url`; `onClick` fires alongside the navigation.
|
|
20
|
+
* - **Link app with a CTA**: the CTA owns navigation; `onClick` is
|
|
21
|
+
* ignored (the CTA's own `onClick` is the analytics hook).
|
|
22
|
+
* - **Video / audio link previews**: the shell stays non-interactive
|
|
23
|
+
* so the native media controls remain operable; `onClick` is ignored.
|
|
24
|
+
*/
|
|
25
|
+
onClick?: () => void
|
|
26
|
+
}
|
|
12
27
|
|
|
13
28
|
/**
|
|
14
29
|
* The card the sender sees in chat after a link attachment has been posted.
|
|
15
30
|
* Matches the Sent column of the messaging design system in Figma — same
|
|
16
31
|
* dark chrome as the Composer card minus the dismiss / edit affordances.
|
|
32
|
+
*
|
|
33
|
+
* The sender's own copy is clickable when a `url` is set so they can open
|
|
34
|
+
* the link they just sent — symmetric with `LinkAttachment.Received`.
|
|
17
35
|
*/
|
|
18
36
|
const SentCard: React.FC<SentCardProps> = ({
|
|
19
37
|
title,
|
|
@@ -26,32 +44,55 @@ const SentCard: React.FC<SentCardProps> = ({
|
|
|
26
44
|
layout = 'featured',
|
|
27
45
|
appIcon,
|
|
28
46
|
cta,
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
47
|
+
onClick,
|
|
48
|
+
}) => {
|
|
49
|
+
// Video / audio link previews wrap the native media element — render a
|
|
50
|
+
// plain non-interactive shell and let the media controls own clicks so
|
|
51
|
+
// taps on play/pause/scrubber don't fire the outer card action. Same
|
|
52
|
+
// rationale as `ReceivedCard`.
|
|
53
|
+
const isPlayingMedia = isPlayableMedia(mimeType, sourceUrl)
|
|
54
|
+
// Normalize the URL so a bare hostname like `tr.ee/briemix` is treated
|
|
55
|
+
// as an external link instead of resolving against the current host.
|
|
56
|
+
// Returns `undefined` for empty / whitespace-only values, so those fall
|
|
57
|
+
// through to a non-navigational shell instead of producing an empty
|
|
58
|
+
// `href` on the anchor.
|
|
59
|
+
const normalizedUrl = normalizeExternalHref(url)
|
|
60
|
+
const shellHref =
|
|
61
|
+
cta == null && normalizedUrl != null && !isPlayingMedia
|
|
62
|
+
? normalizedUrl
|
|
63
|
+
: undefined
|
|
64
|
+
const shellOnClick =
|
|
65
|
+
cta == null && !isPlayingMedia && shellHref != null ? onClick : undefined
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
<CardShell
|
|
69
|
+
variant="dark"
|
|
70
|
+
href={shellHref}
|
|
71
|
+
onClick={shellOnClick}
|
|
72
|
+
bgClassName={
|
|
73
|
+
isPlayableAudio(mimeType, sourceUrl) ? AUDIO_BG_CLASS : undefined
|
|
74
|
+
}
|
|
75
|
+
>
|
|
76
|
+
{layout === 'featured' && (
|
|
77
|
+
<CardThumbnail
|
|
78
|
+
variant="dark"
|
|
79
|
+
thumbnailUrl={thumbnailUrl}
|
|
80
|
+
sourceUrl={sourceUrl}
|
|
81
|
+
title={title}
|
|
82
|
+
mimeType={mimeType}
|
|
83
|
+
/>
|
|
84
|
+
)}
|
|
85
|
+
<CardBody
|
|
38
86
|
variant="dark"
|
|
39
|
-
thumbnailUrl={thumbnailUrl}
|
|
40
|
-
sourceUrl={sourceUrl}
|
|
41
87
|
title={title}
|
|
42
|
-
|
|
88
|
+
placeholderTitle={placeholderTitle}
|
|
89
|
+
description={description}
|
|
90
|
+
url={url}
|
|
91
|
+
appIcon={appIcon}
|
|
92
|
+
cta={cta}
|
|
43
93
|
/>
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
title={title}
|
|
48
|
-
placeholderTitle={placeholderTitle}
|
|
49
|
-
description={description}
|
|
50
|
-
url={url}
|
|
51
|
-
appIcon={appIcon}
|
|
52
|
-
cta={cta}
|
|
53
|
-
/>
|
|
54
|
-
</CardShell>
|
|
55
|
-
)
|
|
94
|
+
</CardShell>
|
|
95
|
+
)
|
|
96
|
+
}
|
|
56
97
|
|
|
57
98
|
export default SentCard
|
|
@@ -7,9 +7,10 @@ export interface CardShellProps {
|
|
|
7
7
|
variant: LinkAttachmentVariant
|
|
8
8
|
children: React.ReactNode
|
|
9
9
|
/**
|
|
10
|
-
* When provided, the entire card chrome is rendered as an anchor (used
|
|
11
|
-
*
|
|
12
|
-
* `<div>` when omitted so Composer
|
|
10
|
+
* When provided, the entire card chrome is rendered as an anchor (used
|
|
11
|
+
* by Sent / Received cards to open the link target on click). Falls
|
|
12
|
+
* back to a `<div>` when omitted so Composer cards stay
|
|
13
|
+
* non-navigational while drafting.
|
|
13
14
|
*/
|
|
14
15
|
href?: string
|
|
15
16
|
/**
|
package/src/types.ts
CHANGED
|
@@ -22,10 +22,16 @@ export type { LockedAttachmentSource } from './components/LockedAttachment'
|
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* Callback invoked when a user clicks a link inside the channel view.
|
|
25
|
-
* Receives the clicked URL
|
|
25
|
+
* Receives the clicked URL and, when resolvable, the message the link
|
|
26
|
+
* was rendered in (so consumers can filter on sender or metadata).
|
|
27
|
+
* `message` is `undefined` when the click happens on a link outside a
|
|
28
|
+
* resolvable message wrapper. Fires alongside the native navigation,
|
|
26
29
|
* not in place of it.
|
|
27
30
|
*/
|
|
28
|
-
export type MessageLinkClickHandler = (
|
|
31
|
+
export type MessageLinkClickHandler = (
|
|
32
|
+
url: string,
|
|
33
|
+
message: LocalMessage | undefined
|
|
34
|
+
) => void
|
|
29
35
|
|
|
30
36
|
/**
|
|
31
37
|
* Generic participant interface for different host environments
|