@linktr.ee/messaging-react 1.31.0 → 1.32.1-rc-1777007852

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 (33) hide show
  1. package/dist/Card-1CQEn-OT.js +171 -0
  2. package/dist/Card-1CQEn-OT.js.map +1 -0
  3. package/dist/Card-ClE_iExA.js +177 -0
  4. package/dist/Card-ClE_iExA.js.map +1 -0
  5. package/dist/{MediaPlayer-BCsdmsON.js → MediaPlayer-B9Ws2NeE.js} +115 -135
  6. package/dist/MediaPlayer-B9Ws2NeE.js.map +1 -0
  7. package/dist/index.d.ts +3 -2
  8. package/dist/index.js +79 -63
  9. package/dist/index.js.map +1 -1
  10. package/package.json +1 -1
  11. package/src/components/ChannelView.stories.tsx +38 -7
  12. package/src/components/CustomMessageInput/CustomMessageInput.test.tsx +127 -0
  13. package/src/components/CustomMessageInput/index.tsx +25 -8
  14. package/src/components/LockedAttachment/LockedAttachment.stories.tsx +136 -93
  15. package/src/components/LockedAttachment/components/Creator/Card.tsx +106 -106
  16. package/src/components/LockedAttachment/components/Creator/CardThumbnail.tsx +114 -0
  17. package/src/components/LockedAttachment/components/MediaPlayer.tsx +80 -66
  18. package/src/components/LockedAttachment/components/Visitor/Card.tsx +53 -78
  19. package/src/components/LockedAttachment/components/Visitor/CardActions.tsx +3 -3
  20. package/src/components/LockedAttachment/components/Visitor/CardThumbnail.tsx +81 -0
  21. package/src/components/LockedAttachment/types.ts +2 -0
  22. package/dist/Card-C5t3dZ5q.js +0 -350
  23. package/dist/Card-C5t3dZ5q.js.map +0 -1
  24. package/dist/Card-Cn2va-Qr.js +0 -205
  25. package/dist/Card-Cn2va-Qr.js.map +0 -1
  26. package/dist/MediaPlayer-BCsdmsON.js.map +0 -1
  27. package/src/components/LockedAttachment/components/Creator/CardAudioPreview.tsx +0 -161
  28. package/src/components/LockedAttachment/components/Creator/CardCollapsedThumbnail.tsx +0 -58
  29. package/src/components/LockedAttachment/components/Creator/CardImagePreview.tsx +0 -56
  30. package/src/components/LockedAttachment/components/Creator/CardVideoPreview.tsx +0 -91
  31. package/src/components/LockedAttachment/components/Visitor/CardImagePreview.tsx +0 -39
  32. package/src/components/LockedAttachment/components/Visitor/CardMediaPreview.tsx +0 -36
  33. package/src/components/LockedAttachment/components/Visitor/CardThumbnailPreview.tsx +0 -45
@@ -1,22 +1,14 @@
1
- import {
2
- CheckCircleIcon,
3
- LockOpenIcon,
4
- LockSimpleIcon,
5
- } from '@phosphor-icons/react'
1
+ import { CheckCircleIcon } from '@phosphor-icons/react'
6
2
  import React, { useCallback, useEffect, useRef, useState } from 'react'
7
3
 
8
4
  import type {
9
5
  LockedAttachmentBaseProps,
10
6
  LockedAttachmentSource,
11
- PaymentStatus,
12
7
  } from '../../types'
13
8
  import { renderTypeIcon } from '../../utils/icons'
14
- import { getSourceType } from '../../utils/mimeType'
15
9
 
16
10
  import CardActions from './CardActions'
17
- import ImagePreview from './CardImagePreview'
18
- import MediaPreview from './CardMediaPreview'
19
- import ThumbnailPreview from './CardThumbnailPreview'
11
+ import CardThumbnail from './CardThumbnail'
20
12
 
21
13
  export interface VisitorCardProps extends LockedAttachmentBaseProps {
22
14
  /**
@@ -43,10 +35,6 @@ export interface VisitorCardProps extends LockedAttachmentBaseProps {
43
35
  isUnlocking?: boolean
44
36
  }
45
37
 
46
- function getLockIcon(paymentStatus?: PaymentStatus): React.ElementType {
47
- return paymentStatus === 'paid' ? LockOpenIcon : LockSimpleIcon
48
- }
49
-
50
38
  const VisitorCard: React.FC<VisitorCardProps> = ({
51
39
  title,
52
40
  amountText,
@@ -60,15 +48,16 @@ const VisitorCard: React.FC<VisitorCardProps> = ({
60
48
  isUnlocking = false,
61
49
  }) => {
62
50
  const [source, setSource] = useState<LockedAttachmentSource | undefined>()
63
- const hasMounted = useRef(false)
51
+
52
+ const cardRef = useRef<HTMLDivElement>(null)
64
53
  const fetchingRef = useRef(false)
65
- // Stable ref so fetchSource doesn't change identity when onFetchSource prop changes
54
+
66
55
  const onFetchSourceRef = useRef(onFetchSource)
67
56
  onFetchSourceRef.current = onFetchSource
68
57
 
69
- const isLocked = source === undefined
70
- const sourceType = getSourceType(mimeType)
71
- const LockIcon = isLocked ? getLockIcon(paymentStatus) : undefined
58
+ const effectiveSourceUrl = source?.sourceUrl
59
+ const effectiveThumbnail = source?.thumbnailUrl ?? thumbnailUrl
60
+ const effectiveRedeemUrl = source?.redeemUrl
72
61
 
73
62
  const fetchSource = useCallback(async (): Promise<void> => {
74
63
  if (fetchingRef.current) return
@@ -79,20 +68,7 @@ const VisitorCard: React.FC<VisitorCardProps> = ({
79
68
  } finally {
80
69
  fetchingRef.current = false
81
70
  }
82
- }, []) // stable — reads onFetchSource via ref
83
-
84
- // When paymentStatus transitions to 'paid' (e.g. after checkout completes),
85
- // automatically fetch the source. Skipped on mount.
86
- useEffect(() => {
87
- if (!hasMounted.current) {
88
- hasMounted.current = true
89
- return
90
- }
91
-
92
- if (paymentStatus === 'paid') {
93
- void fetchSource()
94
- }
95
- }, [paymentStatus, fetchSource])
71
+ }, [])
96
72
 
97
73
  const handleUnlockClick = useCallback(() => {
98
74
  if (paymentStatus === 'paid') {
@@ -100,44 +76,41 @@ const VisitorCard: React.FC<VisitorCardProps> = ({
100
76
  } else {
101
77
  onUnlockClick?.()
102
78
  }
103
- }, [paymentStatus, onUnlockClick, fetchSource])
104
-
105
- let mediaPreview: React.ReactNode
106
- if (sourceType === 'image') {
107
- mediaPreview = (
108
- <ImagePreview
109
- key={source?.sourceUrl}
110
- sourceUrl={source?.sourceUrl}
111
- thumbnailUrl={thumbnailUrl}
112
- mimeType={mimeType}
113
- title={title}
114
- LockIcon={LockIcon}
115
- />
116
- )
117
- } else if (sourceType === 'document') {
118
- mediaPreview = (
119
- <ThumbnailPreview
120
- key={source?.sourceUrl}
121
- thumbnailUrl={thumbnailUrl}
122
- mimeType={mimeType}
123
- LockIcon={LockIcon}
124
- />
79
+ }, [paymentStatus, fetchSource, onUnlockClick])
80
+
81
+ // Fetch source when card is in viewport
82
+ useEffect(() => {
83
+ if (!cardRef.current) return
84
+ if (paymentStatus !== 'paid' || source !== undefined) return
85
+
86
+ const observer = new IntersectionObserver(
87
+ ([entry]) => {
88
+ if (entry.isIntersecting) {
89
+ void fetchSource()
90
+ observer.disconnect()
91
+ }
92
+ },
93
+ { threshold: 1.0 }
125
94
  )
126
- } else {
127
- mediaPreview = (
128
- <MediaPreview
129
- key={source?.sourceUrl}
130
- sourceUrl={source?.sourceUrl}
131
- thumbnailUrl={thumbnailUrl}
95
+
96
+ observer.observe(cardRef.current)
97
+ return () => observer.disconnect()
98
+ }, [paymentStatus, source, fetchSource])
99
+
100
+ return (
101
+ <div
102
+ ref={cardRef}
103
+ data-testid="locked-attachment"
104
+ className="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)]"
105
+ >
106
+ <CardThumbnail
107
+ title={title}
108
+ sourceUrl={effectiveSourceUrl}
109
+ thumbnailUrl={effectiveThumbnail}
132
110
  mimeType={mimeType}
133
- LockIcon={LockIcon}
111
+ paymentStatus={paymentStatus}
134
112
  />
135
- )
136
- }
137
113
 
138
- return (
139
- <div className="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)]">
140
- {mediaPreview}
141
114
  <div className="px-4 pb-3 pt-3">
142
115
  <p className="mb-1.5 truncate text-base font-medium text-black">
143
116
  {title}
@@ -147,12 +120,14 @@ const VisitorCard: React.FC<VisitorCardProps> = ({
147
120
  className: 'size-5 shrink-0 text-black/55',
148
121
  weight: 'regular',
149
122
  })}
150
- {detail != null ? (
123
+
124
+ {detail && (
151
125
  <span className="text-xs font-medium text-black/55">{detail}</span>
152
- ) : null}
126
+ )}
127
+
153
128
  {paymentStatus === 'paid' ? (
154
- <>
155
- <span className="text-xs font-medium text-black/55">•</span>
129
+ <React.Fragment>
130
+ <span className="text-xs font-medium text-black/55">&bull;</span>
156
131
  <span className="text-xs font-medium text-[#008236]">
157
132
  Purchased
158
133
  </span>
@@ -160,21 +135,21 @@ const VisitorCard: React.FC<VisitorCardProps> = ({
160
135
  className="size-4 text-[#008236]"
161
136
  weight="bold"
162
137
  />
163
- </>
138
+ </React.Fragment>
164
139
  ) : amountText != null ? (
165
- <>
166
- <span className="text-xs font-medium text-black/55">•</span>
140
+ <React.Fragment>
141
+ <span className="text-xs font-medium text-black/55">&bull;</span>
167
142
  <span className="text-xs font-medium text-black/55">
168
143
  {amountText}
169
144
  </span>
170
- </>
145
+ </React.Fragment>
171
146
  ) : null}
172
147
  </div>
148
+
173
149
  <CardActions
174
- isLocked={isLocked}
175
150
  isUnlocking={isUnlocking}
176
- sourceUrl={source?.sourceUrl}
177
- redeemUrl={source?.redeemUrl}
151
+ sourceUrl={effectiveSourceUrl}
152
+ redeemUrl={effectiveRedeemUrl}
178
153
  onUnlockClicked={handleUnlockClick}
179
154
  onDownloadClicked={onDownloadClick}
180
155
  />
@@ -2,17 +2,15 @@ import { DownloadSimpleIcon, LockSimpleIcon } from '@phosphor-icons/react'
2
2
  import React from 'react'
3
3
 
4
4
  interface CardActionsProps {
5
- isLocked: boolean
6
- isUnlocking?: boolean
7
5
  sourceUrl?: string
8
6
  redeemUrl?: string
9
7
  onUnlockClicked?: () => void
10
8
  onDownloadClicked?: () => void
9
+ isUnlocking?: boolean
11
10
  }
12
11
 
13
12
  const CardActions: React.FC<CardActionsProps> = (props) => {
14
13
  const {
15
- isLocked,
16
14
  isUnlocking = false,
17
15
  sourceUrl,
18
16
  redeemUrl,
@@ -20,6 +18,8 @@ const CardActions: React.FC<CardActionsProps> = (props) => {
20
18
  onDownloadClicked,
21
19
  } = props
22
20
 
21
+ const isLocked = sourceUrl === undefined
22
+
23
23
  if (isLocked && onUnlockClicked != null) {
24
24
  return (
25
25
  <button
@@ -0,0 +1,81 @@
1
+ import { LockOpenIcon, LockSimpleIcon } from '@phosphor-icons/react'
2
+ import React, { useState } from 'react'
3
+
4
+ import { PaymentStatus } from '../../types'
5
+ import { renderTypeIcon } from '../../utils/icons'
6
+ import { getSourceType } from '../../utils/mimeType'
7
+ import MediaPlayer from '../MediaPlayer'
8
+
9
+ interface CardThumbnailProps {
10
+ title?: string
11
+ sourceUrl?: string
12
+ thumbnailUrl?: string
13
+ mimeType: string
14
+ paymentStatus?: PaymentStatus
15
+ }
16
+
17
+ const CardThumbnail: React.FC<CardThumbnailProps> = ({
18
+ title,
19
+ sourceUrl,
20
+ thumbnailUrl,
21
+ mimeType,
22
+ paymentStatus,
23
+ }) => {
24
+ const [sourceReady, setSourceReady] = useState(false)
25
+
26
+ const isLocked = sourceUrl === undefined
27
+ const sourceType = getSourceType(mimeType)
28
+
29
+ if (!isLocked) {
30
+ if (sourceType === 'audio' || sourceType === 'video') {
31
+ return (
32
+ <MediaPlayer
33
+ source={sourceUrl}
34
+ poster={thumbnailUrl}
35
+ mimeType={mimeType}
36
+ />
37
+ )
38
+ }
39
+
40
+ return (
41
+ <div className="relative overflow-hidden bg-black/5">
42
+ <img
43
+ src={sourceType === 'document' ? thumbnailUrl : sourceUrl}
44
+ alt={title}
45
+ className={`block w-full transition-opacity duration-300 ${sourceReady ? 'opacity-100' : 'opacity-0'}`}
46
+ draggable={false}
47
+ onLoad={() => setSourceReady(true)}
48
+ />
49
+ </div>
50
+ )
51
+ }
52
+
53
+ return (
54
+ <div className="relative aspect-video overflow-hidden bg-black/5">
55
+ {thumbnailUrl != null ? (
56
+ <img
57
+ src={thumbnailUrl}
58
+ alt=""
59
+ className="absolute inset-0 h-full w-full object-cover"
60
+ draggable={false}
61
+ />
62
+ ) : (
63
+ <div className="absolute inset-0 flex items-center justify-center">
64
+ {renderTypeIcon(mimeType, {
65
+ className: 'size-12 text-black/20',
66
+ weight: 'regular',
67
+ })}
68
+ </div>
69
+ )}
70
+ {isLocked && (
71
+ <div className="absolute inset-0 bg-black/30">
72
+ <div className="absolute left-3 top-3 flex size-8 items-center justify-center rounded-full bg-black/60 text-white">
73
+ {paymentStatus === 'paid' ? <LockOpenIcon /> : <LockSimpleIcon />}
74
+ </div>
75
+ </div>
76
+ )}
77
+ </div>
78
+ )
79
+ }
80
+
81
+ export default CardThumbnail
@@ -16,6 +16,8 @@ export interface LockedAttachmentSource {
16
16
  sourceUrl: string
17
17
  /** URL opened when the visitor clicks Download — may be a file or a web destination. */
18
18
  redeemUrl?: string
19
+ /** Thumbnail URL from the fetched asset — overrides the metadata thumbnail when present. */
20
+ thumbnailUrl?: string
19
21
  }
20
22
 
21
23
  export type { PaymentStatus }
@@ -1,350 +0,0 @@
1
- import { jsxs as m, jsx as e, Fragment as L } from "react/jsx-runtime";
2
- import { PauseIcon as _, PlayIcon as F, EyeSlashIcon as M, EyeIcon as R, XIcon as S, CheckCircleIcon as X, LockOpenIcon as D, LockIcon as B } from "@phosphor-icons/react";
3
- import C from "classnames";
4
- import { r as I, M as q, g as O } from "./MediaPlayer-BCsdmsON.js";
5
- import { useState as k, useRef as T, useEffect as z, useCallback as E } from "react";
6
- const P = ({
7
- thumbnailUrl: o,
8
- mimeType: a,
9
- overlayIcon: s,
10
- darkOverlay: r,
11
- onClick: n
12
- }) => /* @__PURE__ */ m(
13
- "button",
14
- {
15
- type: "button",
16
- disabled: !n,
17
- className: C(
18
- "relative aspect-video block w-full overflow-hidden border-0 bg-black/5 p-0 text-left appearance-none",
19
- { "cursor-pointer": !!n, "cursor-default": !n }
20
- ),
21
- onClick: n,
22
- "aria-label": s ? "Toggle preview" : void 0,
23
- children: [
24
- o ? /* @__PURE__ */ e(
25
- "img",
26
- {
27
- src: o,
28
- alt: "",
29
- className: "absolute inset-0 h-full w-full object-cover"
30
- }
31
- ) : /* @__PURE__ */ e("div", { className: "absolute inset-0 flex items-center justify-center", children: I(a, {
32
- className: "size-12 text-black/20",
33
- weight: "regular"
34
- }) }),
35
- r && /* @__PURE__ */ e("div", { className: "pointer-events-none absolute inset-0 bg-black/30" }),
36
- s && /* @__PURE__ */ e("div", { className: "pointer-events-none absolute left-3 top-3 flex size-8 items-center justify-center rounded-full bg-black/60 text-white", children: /* @__PURE__ */ e(s, { className: "size-4", weight: "fill" }) })
37
- ]
38
- }
39
- ), $ = (o) => {
40
- const { sourceUrl: a, thumbnailUrl: s, mimeType: r } = o, [n, c] = k(!1), [i, h] = k(0), [b, v] = k(!1), f = T(null), w = T(null), d = T(null);
41
- z(() => {
42
- const t = f.current;
43
- t && (n ? t.play().catch(() => c(!1)) : t.pause());
44
- }, [n]), z(() => {
45
- if (!n) {
46
- d.current !== null && cancelAnimationFrame(d.current);
47
- return;
48
- }
49
- const t = () => {
50
- const l = f.current;
51
- l && l.duration && !b && h(l.currentTime / l.duration), d.current = requestAnimationFrame(t);
52
- };
53
- return d.current = requestAnimationFrame(t), () => {
54
- d.current !== null && cancelAnimationFrame(d.current);
55
- };
56
- }, [n, b]);
57
- const [x, g] = k(!1), u = E(
58
- (t) => {
59
- var A, j;
60
- const l = w.current;
61
- if (!l) return 0;
62
- const y = "touches" in t ? ((A = t.touches[0]) == null ? void 0 : A.clientX) ?? ((j = t.changedTouches[0]) == null ? void 0 : j.clientX) ?? 0 : t.clientX, N = l.getBoundingClientRect();
63
- return Math.max(0, Math.min(1, (y - N.left) / N.width));
64
- },
65
- []
66
- ), p = E((t) => {
67
- const l = f.current;
68
- l && l.duration && (l.currentTime = t * l.duration);
69
- }, []);
70
- z(() => {
71
- if (!b) return;
72
- const t = (y) => {
73
- const N = u(y);
74
- h(N), p(N);
75
- }, l = (y) => {
76
- v(!1), p(u(y));
77
- };
78
- return window.addEventListener("mousemove", t), window.addEventListener("mouseup", l), window.addEventListener("touchmove", t, { passive: !0 }), window.addEventListener("touchend", l), () => {
79
- window.removeEventListener("mousemove", t), window.removeEventListener("mouseup", l), window.removeEventListener("touchmove", t), window.removeEventListener("touchend", l);
80
- };
81
- }, [b, u, p]);
82
- const U = E(() => c((t) => !t), []);
83
- return /* @__PURE__ */ m("div", { className: "relative", children: [
84
- a && /* @__PURE__ */ e(
85
- "audio",
86
- {
87
- ref: f,
88
- src: a,
89
- loop: !0,
90
- onCanPlay: () => g(!0),
91
- onEnded: () => {
92
- c(!1), h(0);
93
- },
94
- children: /* @__PURE__ */ e("track", { kind: "captions" })
95
- }
96
- ),
97
- /* @__PURE__ */ e(
98
- P,
99
- {
100
- thumbnailUrl: s,
101
- mimeType: r,
102
- overlayIcon: a && x ? n ? _ : F : void 0,
103
- onClick: a && x ? U : void 0
104
- }
105
- ),
106
- a && x && /* @__PURE__ */ e("div", { className: "absolute inset-x-0 bottom-0 px-3 pb-2.5 pt-6 bg-gradient-to-t from-black/40 to-transparent", children: /* @__PURE__ */ e(
107
- "div",
108
- {
109
- ref: w,
110
- role: "slider",
111
- "aria-label": "Playback position",
112
- "aria-valuenow": Math.round(i * 100),
113
- "aria-valuemin": 0,
114
- "aria-valuemax": 100,
115
- tabIndex: 0,
116
- className: "relative flex h-4 w-full cursor-pointer items-center",
117
- onMouseDown: (t) => {
118
- t.stopPropagation(), v(!0);
119
- const l = u(t);
120
- h(l), p(l);
121
- },
122
- onTouchStart: (t) => {
123
- t.stopPropagation(), v(!0);
124
- const l = u(t);
125
- h(l), p(l);
126
- },
127
- onClick: (t) => t.stopPropagation(),
128
- onKeyDown: (t) => {
129
- t.key === "ArrowRight" && p(Math.min(1, i + 0.05)), t.key === "ArrowLeft" && p(Math.max(0, i - 0.05));
130
- },
131
- children: /* @__PURE__ */ e("div", { className: "w-full overflow-hidden rounded-full bg-white/30 h-1", children: /* @__PURE__ */ e(
132
- "div",
133
- {
134
- className: "h-full rounded-full bg-white",
135
- style: { width: `${Math.round(i * 100)}%` }
136
- }
137
- ) })
138
- }
139
- ) })
140
- ] });
141
- }, K = (o) => {
142
- const { sourceUrl: a, thumbnailUrl: s, mimeType: r, title: n } = o, [c, i] = k(!1);
143
- return c && a ? /* @__PURE__ */ m("div", { className: "relative", children: [
144
- /* @__PURE__ */ e(
145
- "button",
146
- {
147
- type: "button",
148
- className: "block w-full cursor-pointer border-0 p-0 text-left appearance-none",
149
- onClick: () => i(!1),
150
- "aria-label": "Close preview",
151
- children: /* @__PURE__ */ e("img", { src: a, alt: n ?? "", className: "block w-full" })
152
- }
153
- ),
154
- /* @__PURE__ */ e(V, { onClose: () => i(!1) })
155
- ] }) : /* @__PURE__ */ e(
156
- P,
157
- {
158
- thumbnailUrl: s,
159
- mimeType: r,
160
- overlayIcon: a ? M : void 0,
161
- onClick: a ? () => i(!0) : void 0
162
- }
163
- );
164
- }, V = ({ onClose: o }) => /* @__PURE__ */ e(
165
- "button",
166
- {
167
- type: "button",
168
- onClick: o,
169
- className: "absolute left-3 top-3 z-40 flex size-8 items-center justify-center rounded-full bg-black/60 text-white",
170
- "aria-label": "Close preview",
171
- children: /* @__PURE__ */ e(R, { className: "size-4", weight: "fill" })
172
- }
173
- ), G = (o) => {
174
- const { sourceUrl: a, thumbnailUrl: s, mimeType: r } = o, [n, c] = k(!1), i = () => {
175
- c(!1);
176
- };
177
- return a ? /* @__PURE__ */ m(
178
- "div",
179
- {
180
- className: C("relative overflow-hidden", {
181
- "aspect-video": !n
182
- }),
183
- children: [
184
- /* @__PURE__ */ e(
185
- q,
186
- {
187
- source: a,
188
- mimeType: r,
189
- poster: s,
190
- playing: n,
191
- loop: !0,
192
- controls: !1,
193
- muted: !0,
194
- showProgress: !0,
195
- onContainerClick: i
196
- }
197
- ),
198
- !n && /* @__PURE__ */ m(
199
- "button",
200
- {
201
- type: "button",
202
- className: "absolute inset-0 block cursor-pointer border-0 p-0 text-left appearance-none",
203
- onClick: () => c(!0),
204
- "aria-label": "Expand video preview",
205
- children: [
206
- s ? /* @__PURE__ */ e(
207
- "img",
208
- {
209
- src: s,
210
- alt: "",
211
- className: "absolute inset-0 h-full w-full object-cover"
212
- }
213
- ) : /* @__PURE__ */ e("div", { className: "absolute inset-0 flex items-center justify-center", children: I(r, {
214
- className: "size-12 text-black/20",
215
- weight: "regular"
216
- }) }),
217
- /* @__PURE__ */ e("div", { className: "pointer-events-none absolute left-3 top-3 flex size-8 items-center justify-center rounded-full bg-black/60 text-white", children: /* @__PURE__ */ e(M, { className: "size-4", weight: "fill" }) })
218
- ]
219
- }
220
- ),
221
- n && /* @__PURE__ */ e(H, { onClose: i })
222
- ]
223
- }
224
- ) : /* @__PURE__ */ e(P, { thumbnailUrl: s, mimeType: r });
225
- }, H = ({ onClose: o }) => /* @__PURE__ */ e(
226
- "button",
227
- {
228
- type: "button",
229
- onClick: o,
230
- className: "absolute left-3 top-3 z-40 flex size-8 items-center justify-center rounded-full bg-black/60 text-white",
231
- "aria-label": "Close preview",
232
- children: /* @__PURE__ */ e(R, { className: "size-4", weight: "fill" })
233
- }
234
- ), ee = (o) => {
235
- const {
236
- title: a,
237
- mimeType: s = "application/octet-stream",
238
- thumbnailUrl: r,
239
- sourceUrl: n,
240
- detail: c,
241
- amountText: i,
242
- placeholderTitle: h = "Attachment title",
243
- placeholderAmountText: b,
244
- paymentStatus: v,
245
- onDismiss: f,
246
- isPreview: w = !1
247
- } = o, d = O(s), x = i ?? b, g = !i && !!b;
248
- let u;
249
- return w && d === "audio" ? u = /* @__PURE__ */ e(
250
- $,
251
- {
252
- sourceUrl: n,
253
- thumbnailUrl: r,
254
- mimeType: s
255
- },
256
- n
257
- ) : w && d === "video" ? u = /* @__PURE__ */ e(
258
- G,
259
- {
260
- sourceUrl: n,
261
- thumbnailUrl: r,
262
- mimeType: s
263
- },
264
- n
265
- ) : w && d === "image" ? u = /* @__PURE__ */ e(
266
- K,
267
- {
268
- sourceUrl: n,
269
- thumbnailUrl: r,
270
- mimeType: s,
271
- title: a
272
- },
273
- n
274
- ) : u = /* @__PURE__ */ e(
275
- P,
276
- {
277
- thumbnailUrl: r,
278
- mimeType: s,
279
- overlayIcon: f ? void 0 : v === "paid" ? D : B,
280
- darkOverlay: !0
281
- }
282
- ), /* @__PURE__ */ m("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)]", children: [
283
- f && /* @__PURE__ */ e(
284
- "button",
285
- {
286
- type: "button",
287
- onClick: f,
288
- className: "absolute right-3 top-3 z-50 flex size-8 items-center justify-center rounded-full bg-black/60 text-white",
289
- "aria-label": "Dismiss attachment",
290
- children: /* @__PURE__ */ e(S, { className: "size-4", weight: "bold" })
291
- }
292
- ),
293
- u,
294
- /* @__PURE__ */ m("div", { className: "px-4 pb-3 pt-3", children: [
295
- /* @__PURE__ */ e(
296
- "p",
297
- {
298
- className: C("mb-1.5 truncate text-base font-medium", {
299
- "text-black/30": !a,
300
- "text-black": !!a
301
- }),
302
- children: a || h
303
- }
304
- ),
305
- /* @__PURE__ */ m("div", { className: "flex items-center gap-1", children: [
306
- I(s, {
307
- className: "size-5 shrink-0 text-black/55",
308
- weight: "regular"
309
- }),
310
- c && /* @__PURE__ */ e("span", { className: "text-xs font-medium text-black/55", children: c }),
311
- v === "paid" ? /* @__PURE__ */ m(L, { children: [
312
- /* @__PURE__ */ e("span", { className: "text-xs font-medium text-black/55", children: "•" }),
313
- /* @__PURE__ */ e("span", { className: "text-xs font-medium text-[#008236]", children: "Purchased" }),
314
- /* @__PURE__ */ e(
315
- X,
316
- {
317
- className: "size-4 text-[#008236]",
318
- weight: "bold"
319
- }
320
- )
321
- ] }) : x && /* @__PURE__ */ m(L, { children: [
322
- /* @__PURE__ */ e(
323
- "span",
324
- {
325
- className: C("text-xs font-medium", {
326
- "text-black/30": g,
327
- "text-black/55": !g
328
- }),
329
- children: "•"
330
- }
331
- ),
332
- /* @__PURE__ */ e(
333
- "span",
334
- {
335
- className: C("text-xs font-medium", {
336
- "text-black/30": g,
337
- "text-black/55": !g
338
- }),
339
- children: x
340
- }
341
- )
342
- ] })
343
- ] })
344
- ] })
345
- ] });
346
- };
347
- export {
348
- ee as default
349
- };
350
- //# sourceMappingURL=Card-C5t3dZ5q.js.map