@linktr.ee/messaging-react 1.33.2 → 1.33.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { A as e, a as t, C as i, b as n, c as o, d as g, F as r, e as m, L as u, f as M, h as c, i as l, j as h, P as C, k as P, u as d, l as L, m as p, n as v } from "./index-BePLvyvi.js";
1
+ import { A as e, a as t, C as i, b as n, c as o, d as g, F as r, e as m, L as u, f as M, h as c, i as l, j as h, P as C, k as P, u as d, l as L, m as p, n as v } from "./index-Ydi1pTAi.js";
2
2
  export {
3
3
  e as ActionButton,
4
4
  t as Avatar,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@linktr.ee/messaging-react",
3
- "version": "1.33.2",
3
+ "version": "1.33.3",
4
4
  "description": "React messaging components built on messaging-core for web applications",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -250,9 +250,11 @@ export const ChannelInfoDialog: React.FC<ChannelInfoDialogProps> = ({
250
250
  {followerStatusLabel}
251
251
  </span>
252
252
  )}
253
- {customProfileContent}
254
253
  </div>
255
254
  </div>
255
+ {customProfileContent && (
256
+ <div className="w-full">{customProfileContent}</div>
257
+ )}
256
258
  </div>
257
259
 
258
260
  <ul className="flex flex-col gap-2 mt-2">
@@ -1,4 +1,4 @@
1
- import { ArrowLeftIcon, DotsThreeIcon, StarIcon } from '@phosphor-icons/react'
1
+ import { ArrowLeftIcon, CaretRightIcon, DotsThreeIcon, StarIcon } from '@phosphor-icons/react'
2
2
  import classNames from 'classnames'
3
3
  import React, { useCallback, useRef } from 'react'
4
4
  import { Channel as ChannelType } from 'stream-chat'
@@ -96,9 +96,15 @@ const CustomChannelHeader: React.FC<{
96
96
  starred={showStarButton && isStarred}
97
97
  size={40}
98
98
  />
99
- <h1 className="text-xs font-medium text-black/90">
99
+ <button
100
+ type="button"
101
+ onClick={onShowInfo}
102
+ className="flex items-center gap-0.5 rounded-full bg-black/[0.05] px-3 py-1 text-xs font-medium text-black/90 hover:bg-black/[0.08] transition-colors"
103
+ aria-label={`View info for ${participantName}`}
104
+ >
100
105
  {participantName}
101
- </h1>
106
+ <CaretRightIcon className="size-3 shrink-0" />
107
+ </button>
102
108
  </div>
103
109
  <div className="flex justify-end items-center gap-2">
104
110
  {showStarButton && (
@@ -150,9 +156,21 @@ const CustomChannelHeader: React.FC<{
150
156
  size={40}
151
157
  />
152
158
  <div className="min-w-0">
153
- <h1 className="font-medium text-black/90 truncate">
154
- {participantName}
155
- </h1>
159
+ {canShowInfo ? (
160
+ <button
161
+ type="button"
162
+ onClick={onShowInfo}
163
+ className="flex items-center gap-1 font-medium text-black/90 truncate hover:text-black/70 transition-colors"
164
+ aria-label={`View info for ${participantName}`}
165
+ >
166
+ <span className="truncate">{participantName}</span>
167
+ <CaretRightIcon className="size-4 shrink-0" />
168
+ </button>
169
+ ) : (
170
+ <h1 className="font-medium text-black/90 truncate">
171
+ {participantName}
172
+ </h1>
173
+ )}
156
174
  </div>
157
175
  </div>
158
176
  <div className="flex items-center gap-2">
@@ -54,8 +54,8 @@ const CreatorCard: React.FC<CreatorCardProps> = ({
54
54
  <div className="relative w-[280px] select-none overflow-hidden rounded-[24px] bg-white shadow-[0_0_0_1px_rgba(0,0,0,0.04),0_4px_8px_rgba(0,0,0,0.06)]">
55
55
  <CardHeader
56
56
  onDismiss={onDismiss}
57
- onPreviewClick={onPreviewClick}
58
- sourceUrl={source?.sourceUrl}
57
+ onToggle={onPreviewClick ? handleToggle : undefined}
58
+ isExpanded={!!source}
59
59
  paymentStatus={paymentStatus}
60
60
  />
61
61
 
@@ -67,11 +67,11 @@ const CreatorCard: React.FC<CreatorCardProps> = ({
67
67
  onToggle={onPreviewClick ? handleToggle : undefined}
68
68
  />
69
69
 
70
- <div className="px-4 pb-3 pt-3">
70
+ <div className="px-4 pb-3 pt-3 bg-black">
71
71
  <p
72
72
  className={classNames('mb-1.5 truncate text-base font-medium', {
73
- 'text-black/30': !title,
74
- 'text-black': !!title,
73
+ 'text-white/30': !title,
74
+ 'text-white': !!title,
75
75
  })}
76
76
  >
77
77
  {title || placeholderTitle}
@@ -79,30 +79,30 @@ const CreatorCard: React.FC<CreatorCardProps> = ({
79
79
 
80
80
  <div className="flex items-center gap-1">
81
81
  {renderTypeIcon(mimeType, {
82
- className: 'size-5 shrink-0 text-black/55',
82
+ className: 'size-5 shrink-0 text-white/55',
83
83
  weight: 'regular',
84
84
  })}
85
85
 
86
86
  {detail && (
87
- <span className="text-xs font-medium text-black/55">{detail}</span>
87
+ <span className="text-xs font-medium text-white/55">{detail}</span>
88
88
  )}
89
89
 
90
90
  {paymentStatus === 'paid' ? (
91
91
  <React.Fragment>
92
- <span className="text-xs font-medium text-black/55">&bull;</span>
93
- <span className="text-xs font-medium text-[#008236]">Sold</span>
92
+ <span className="text-xs font-medium text-white/55">&bull;</span>
93
+ <span className="text-xs font-medium text-[#4ade80]">Sold</span>
94
94
  <CheckCircleIcon
95
- className="size-4 text-[#008236]"
95
+ className="size-4 text-[#4ade80]"
96
96
  weight="bold"
97
97
  />
98
98
  </React.Fragment>
99
99
  ) : (
100
100
  <React.Fragment>
101
- <span className="text-xs font-medium text-black/55">&bull;</span>
101
+ <span className="text-xs font-medium text-white/55">&bull;</span>
102
102
  <span
103
103
  className={classNames('text-xs font-medium', {
104
- 'text-black/30': !amountText,
105
- 'text-black/55': !!amountText,
104
+ 'text-white/30': !amountText,
105
+ 'text-white/55': !!amountText,
106
106
  })}
107
107
  >
108
108
  {amountText || placeholderAmountText}
@@ -117,15 +117,15 @@ const CreatorCard: React.FC<CreatorCardProps> = ({
117
117
 
118
118
  interface CardHeaderProps {
119
119
  onDismiss?: () => void
120
- onPreviewClick?: () => void
121
- sourceUrl?: string
120
+ onToggle?: () => void
121
+ isExpanded?: boolean
122
122
  paymentStatus?: PaymentStatus
123
123
  }
124
124
 
125
125
  const CardHeader: React.FC<CardHeaderProps> = ({
126
126
  onDismiss,
127
- onPreviewClick,
128
- sourceUrl,
127
+ onToggle,
128
+ isExpanded,
129
129
  paymentStatus,
130
130
  }) => {
131
131
  if (onDismiss) {
@@ -141,13 +141,22 @@ const CardHeader: React.FC<CardHeaderProps> = ({
141
141
  )
142
142
  }
143
143
 
144
- const Icon = onPreviewClick
145
- ? sourceUrl
146
- ? EyeIcon
147
- : EyeSlashIcon
148
- : paymentStatus === 'paid'
149
- ? LockOpenIcon
150
- : LockIcon
144
+ if (onToggle) {
145
+ const Icon = isExpanded ? EyeIcon : EyeSlashIcon
146
+ return (
147
+ <button
148
+ type="button"
149
+ onClick={onToggle}
150
+ className="absolute top-3 z-50 flex size-8 items-center justify-center rounded-full bg-black/60 text-white left-3"
151
+ aria-label={isExpanded ? 'Hide preview' : 'Show preview'}
152
+ aria-pressed={isExpanded}
153
+ >
154
+ <Icon className="size-4" weight="fill" />
155
+ </button>
156
+ )
157
+ }
158
+
159
+ const Icon = paymentStatus === 'paid' ? LockOpenIcon : LockIcon
151
160
 
152
161
  return (
153
162
  <div className="absolute top-3 z-50 flex size-8 items-center justify-center rounded-full bg-black/60 text-white left-3">
@@ -31,6 +31,12 @@ export interface MediaPlayerProps {
31
31
  showProgress?: boolean
32
32
  /** When true, requests muted playback (helps autoplay policies on video). */
33
33
  muted?: boolean
34
+ /**
35
+ * When provided, overrides the default click-to-play-toggle behaviour on the
36
+ * player container. The play/pause button (which calls stopPropagation) is
37
+ * unaffected, so inline playback still works.
38
+ */
39
+ onContainerClick?: (e: React.MouseEvent) => void
34
40
  }
35
41
 
36
42
  const MediaPlayer: React.FC<MediaPlayerProps> = ({
@@ -43,6 +49,7 @@ const MediaPlayer: React.FC<MediaPlayerProps> = ({
43
49
  controls = true,
44
50
  showProgress = false,
45
51
  muted = false,
52
+ onContainerClick,
46
53
  }) => {
47
54
  // --- Derived ---
48
55
  const sourceType = getSourceType(mimeType)
@@ -185,13 +192,15 @@ const MediaPlayer: React.FC<MediaPlayerProps> = ({
185
192
  tabIndex={0}
186
193
  className={`relative cursor-pointer overflow-hidden bg-black ${aspectClass}`}
187
194
  style={aspectStyle}
188
- onClick={() => {
195
+ onClick={(e) => {
196
+ if (onContainerClick) { onContainerClick(e); return }
189
197
  if (manualPlayRequired) return
190
198
  if (controls) setPlaying((p) => !p)
191
199
  }}
192
200
  onKeyDown={(e) => {
193
201
  if (e.key !== 'Enter' && e.key !== ' ') return
194
202
  e.preventDefault()
203
+ if (onContainerClick) { onContainerClick(e as unknown as React.MouseEvent); return }
195
204
  if (manualPlayRequired) return
196
205
  if (controls) setPlaying((p) => !p)
197
206
  }}
@@ -111,35 +111,35 @@ const VisitorCard: React.FC<VisitorCardProps> = ({
111
111
  paymentStatus={paymentStatus}
112
112
  />
113
113
 
114
- <div className="px-4 pb-3 pt-3">
115
- <p className="mb-1.5 truncate text-base font-medium text-black">
114
+ <div className="px-4 pb-3 pt-3 bg-black">
115
+ <p className="mb-1.5 truncate text-base font-medium text-white">
116
116
  {title}
117
117
  </p>
118
118
  <div className="flex items-center gap-1">
119
119
  {renderTypeIcon(mimeType, {
120
- className: 'size-5 shrink-0 text-black/55',
120
+ className: 'size-5 shrink-0 text-white/55',
121
121
  weight: 'regular',
122
122
  })}
123
123
 
124
124
  {detail && (
125
- <span className="text-xs font-medium text-black/55">{detail}</span>
125
+ <span className="text-xs font-medium text-white/55">{detail}</span>
126
126
  )}
127
127
 
128
128
  {paymentStatus === 'paid' ? (
129
129
  <React.Fragment>
130
- <span className="text-xs font-medium text-black/55">&bull;</span>
131
- <span className="text-xs font-medium text-[#008236]">
130
+ <span className="text-xs font-medium text-white/55">&bull;</span>
131
+ <span className="text-xs font-medium text-[#4ade80]">
132
132
  Purchased
133
133
  </span>
134
134
  <CheckCircleIcon
135
- className="size-4 text-[#008236]"
135
+ className="size-4 text-[#4ade80]"
136
136
  weight="bold"
137
137
  />
138
138
  </React.Fragment>
139
139
  ) : amountText != null ? (
140
140
  <React.Fragment>
141
- <span className="text-xs font-medium text-black/55">&bull;</span>
142
- <span className="text-xs font-medium text-black/55">
141
+ <span className="text-xs font-medium text-white/55">&bull;</span>
142
+ <span className="text-xs font-medium text-white/55">
143
143
  {amountText}
144
144
  </span>
145
145
  </React.Fragment>
@@ -26,7 +26,7 @@ const CardActions: React.FC<CardActionsProps> = (props) => {
26
26
  type="button"
27
27
  onClick={onUnlockClicked}
28
28
  disabled={isUnlocking}
29
- className="mt-3 inline-flex h-10 w-full items-center justify-center gap-2 rounded-full bg-[#121110] px-4 text-sm font-medium leading-none text-white hover:bg-[#2a2928] disabled:opacity-70"
29
+ className="mt-3 inline-flex h-10 w-full items-center justify-center gap-2 rounded-full bg-white px-4 text-sm font-medium leading-none text-[#121110] hover:bg-white/90 disabled:opacity-70"
30
30
  >
31
31
  {isUnlocking ? (
32
32
  <LoadingDots />
@@ -47,7 +47,7 @@ const CardActions: React.FC<CardActionsProps> = (props) => {
47
47
  target="_blank"
48
48
  rel="noopener noreferrer"
49
49
  onClick={onDownloadClicked}
50
- className="mt-3 inline-flex h-10 w-full items-center justify-center gap-2 rounded-full bg-[#121110] px-4 text-sm font-medium leading-none !text-white hover:bg-[#2a2928]"
50
+ className="mt-3 inline-flex h-10 w-full items-center justify-center gap-2 rounded-full bg-white px-4 text-sm font-medium leading-none !text-[#121110] hover:bg-white/90"
51
51
  >
52
52
  <DownloadSimpleIcon className="size-4" weight="bold" />
53
53
  Download
@@ -84,6 +84,43 @@ const VARIANTS = [
84
84
  },
85
85
  ] as const
86
86
 
87
+ const LINK_VARIANTS = [
88
+ {
89
+ label: 'With image',
90
+ attachment: {
91
+ type: 'link',
92
+ og_scrape_url: 'https://linktr.ee/brieparsons',
93
+ title: 'World Famous 3 Bottle Grey Wash Set',
94
+ text: 'When its time to shade, the World Famous Grey Wash set has you covered.',
95
+ image_url: 'https://picsum.photos/seed/linkcard/560/315',
96
+ },
97
+ },
98
+ {
99
+ label: 'No image',
100
+ attachment: {
101
+ type: 'link',
102
+ og_scrape_url: 'https://linktr.ee/brieparsons',
103
+ title: 'World Famous 3 Bottle Grey Wash Set',
104
+ text: 'When its time to shade, the World Famous Grey Wash set has you covered.',
105
+ },
106
+ },
107
+ {
108
+ label: 'Title only',
109
+ attachment: {
110
+ type: 'link',
111
+ og_scrape_url: 'https://linktr.ee/someone',
112
+ title: 'Check out my Linktree',
113
+ },
114
+ },
115
+ {
116
+ label: 'URL only',
117
+ attachment: {
118
+ type: 'link',
119
+ og_scrape_url: 'https://linktr.ee/someone',
120
+ },
121
+ },
122
+ ] as const
123
+
87
124
  // ---------------------------------------------------------------------------
88
125
  // Layout primitives
89
126
  // ---------------------------------------------------------------------------
@@ -94,11 +131,10 @@ const GridTable: React.FC<{ children: React.ReactNode }> = ({ children }) => (
94
131
  </div>
95
132
  )
96
133
 
97
- const GridHead = () => (
134
+ const GridHead: React.FC<{ labels: readonly string[] }> = ({ labels }) => (
98
135
  <thead>
99
136
  <tr>
100
- <th className="text-left text-xs font-medium text-black/40 pb-2 w-16" />
101
- {VARIANTS.map(({ label }) => (
137
+ {labels.map((label) => (
102
138
  <th key={label} className="text-left text-xs font-medium text-black/40 pb-2">
103
139
  {label}
104
140
  </th>
@@ -107,22 +143,15 @@ const GridHead = () => (
107
143
  </thead>
108
144
  )
109
145
 
110
- const RowLabel: React.FC<{ children: React.ReactNode }> = ({ children }) => (
111
- <td className="text-xs text-right font-medium text-black/40 pr-4 align-top pt-2">
112
- {children}
113
- </td>
114
- )
115
-
116
146
  // ---------------------------------------------------------------------------
117
147
  // Stories
118
148
  // ---------------------------------------------------------------------------
119
149
 
120
- export const Visitor: StoryFn = () => (
150
+ export const Received: StoryFn = () => (
121
151
  <GridTable>
122
- <GridHead />
152
+ <GridHead labels={VARIANTS.map((v) => v.label)} />
123
153
  <tbody>
124
154
  <tr>
125
- <RowLabel>Sent</RowLabel>
126
155
  {VARIANTS.map(({ label, attachment }) => (
127
156
  <td key={label} className="align-top">
128
157
  <MediaMessage
@@ -135,20 +164,19 @@ export const Visitor: StoryFn = () => (
135
164
  </tbody>
136
165
  </GridTable>
137
166
  )
138
- Visitor.parameters = {
167
+ Received.parameters = {
139
168
  docs: {
140
169
  description: {
141
- story: 'Visitor perspectivemessages from the creator, left-aligned with avatar.',
170
+ story: 'Received messages — left-aligned with avatar, light gray card background.',
142
171
  },
143
172
  },
144
173
  }
145
174
 
146
- export const Creator: StoryFn = () => (
175
+ export const Sent: StoryFn = () => (
147
176
  <GridTable>
148
- <GridHead />
177
+ <GridHead labels={VARIANTS.map((v) => v.label)} />
149
178
  <tbody>
150
179
  <tr>
151
- <RowLabel>Sent</RowLabel>
152
180
  {VARIANTS.map(({ label, attachment }) => (
153
181
  <td key={label} className="align-top">
154
182
  <MediaMessage
@@ -161,10 +189,45 @@ export const Creator: StoryFn = () => (
161
189
  </tbody>
162
190
  </GridTable>
163
191
  )
164
- Creator.parameters = {
192
+ Sent.parameters = {
193
+ docs: {
194
+ description: {
195
+ story: 'Sent messages — right-aligned, no avatar, black card background.',
196
+ },
197
+ },
198
+ }
199
+
200
+ export const Links: StoryFn = () => (
201
+ <GridTable>
202
+ <GridHead labels={LINK_VARIANTS.map((v) => v.label)} />
203
+ <tbody>
204
+ <tr>
205
+ {LINK_VARIANTS.map(({ label, attachment }) => (
206
+ <td key={label} className="align-top">
207
+ <MediaMessage
208
+ isMyMessage={false}
209
+ message={base({ user: SENDER, attachments: [attachment as LocalMessage['attachments'][number]] })}
210
+ />
211
+ </td>
212
+ ))}
213
+ </tr>
214
+ <tr>
215
+ {LINK_VARIANTS.map(({ label, attachment }) => (
216
+ <td key={label} className="align-top">
217
+ <MediaMessage
218
+ isMyMessage={true}
219
+ message={base({ user: ME, attachments: [attachment as LocalMessage['attachments'][number]] })}
220
+ />
221
+ </td>
222
+ ))}
223
+ </tr>
224
+ </tbody>
225
+ </GridTable>
226
+ )
227
+ Links.parameters = {
165
228
  docs: {
166
229
  description: {
167
- story: 'Creator perspectiveown messages, right-aligned, no avatar.',
230
+ story: 'Link preview cards top row received, bottom row sent. Shows thumbnail, title, description, and URL with image fallback.',
168
231
  },
169
232
  },
170
233
  }