@linktr.ee/messaging-react 2.0.1-rc-1778656305 → 2.0.1-rc-1778694826
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-_StSlnYh.js → Card-CFFNq49v.js} +3 -3
- package/dist/{Card-_StSlnYh.js.map → Card-CFFNq49v.js.map} +1 -1
- package/dist/{Card-CAC3fPjy.js → Card-CsJvUF_b.js} +2 -2
- package/dist/{Card-CAC3fPjy.js.map → Card-CsJvUF_b.js.map} +1 -1
- package/dist/Card-D32U6KfZ.js +85 -0
- package/dist/Card-D32U6KfZ.js.map +1 -0
- package/dist/{Card-DLUBUg_w.js → Card-DlMSDSdm.js} +2 -2
- package/dist/{Card-DLUBUg_w.js.map → Card-DlMSDSdm.js.map} +1 -1
- package/dist/Card-DlSSJPip.js +60 -0
- package/dist/Card-DlSSJPip.js.map +1 -0
- package/dist/Card-zGbhRBwv.js +48 -0
- package/dist/Card-zGbhRBwv.js.map +1 -0
- package/dist/CardThumbnail-DTBuRQHF.js +239 -0
- package/dist/CardThumbnail-DTBuRQHF.js.map +1 -0
- package/dist/{LockedThumbnail-p5RsFOug.js → LockedThumbnail-DpJx169C.js} +3 -3
- package/dist/LockedThumbnail-DpJx169C.js.map +1 -0
- package/dist/{index-B1h46F9x.js → index-DfcRe-Hj.js} +545 -534
- package/dist/index-DfcRe-Hj.js.map +1 -0
- package/dist/index.d.ts +130 -0
- package/dist/index.js +15 -14
- package/package.json +1 -1
- package/src/components/LinkAttachment/LinkAttachment.stories.tsx +307 -0
- package/src/components/LinkAttachment/components/Composer/Card.tsx +117 -0
- package/src/components/LinkAttachment/components/Composer/index.ts +2 -0
- package/src/components/LinkAttachment/components/Received/Card.tsx +132 -0
- package/src/components/LinkAttachment/components/Received/index.ts +2 -0
- package/src/components/LinkAttachment/components/Sent/Card.tsx +57 -0
- package/src/components/LinkAttachment/components/Sent/index.ts +2 -0
- package/src/components/LinkAttachment/components/_shared/CardBody.tsx +117 -0
- package/src/components/LinkAttachment/components/_shared/CardCta.tsx +69 -0
- package/src/components/LinkAttachment/components/_shared/CardShell.tsx +120 -0
- package/src/components/LinkAttachment/components/_shared/CardThumbnail.tsx +156 -0
- package/src/components/LinkAttachment/components/_shared/normalizeExternalHref.ts +56 -0
- package/src/components/LinkAttachment/index.tsx +68 -0
- package/src/components/LinkAttachment/types.ts +69 -0
- package/src/components/LockedAttachment/components/_shared/LockedCardShell.tsx +1 -1
- package/src/components/LockedAttachment/index.tsx +1 -1
- package/src/components/MediaMessage/index.tsx +6 -0
- package/src/index.ts +9 -0
- package/dist/LockedThumbnail-p5RsFOug.js.map +0 -1
- package/dist/index-B1h46F9x.js.map +0 -1
|
@@ -2,8 +2,8 @@ import { jsx as e, jsxs as o } from "react/jsx-runtime";
|
|
|
2
2
|
import { LockSimpleIcon as A, DownloadSimpleIcon as R, CheckCircleIcon as E, ImagesIcon as F } from "@phosphor-icons/react";
|
|
3
3
|
import N, { useState as O, useRef as v, useCallback as z, useEffect as P } from "react";
|
|
4
4
|
import "classnames";
|
|
5
|
-
import { g as S } from "./index-
|
|
6
|
-
import { L as T, G as _, a as $, C as q } from "./LockedThumbnail-
|
|
5
|
+
import { g as S } from "./index-DfcRe-Hj.js";
|
|
6
|
+
import { L as T, G as _, a as $, C as q } from "./LockedThumbnail-DpJx169C.js";
|
|
7
7
|
const w = "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", H = ({
|
|
8
8
|
isLocked: i,
|
|
9
9
|
sourceUrl: d,
|
|
@@ -160,4 +160,4 @@ const w = "mt-3 inline-flex h-10 w-full items-center justify-center gap-2 rounde
|
|
|
160
160
|
export {
|
|
161
161
|
Y as default
|
|
162
162
|
};
|
|
163
|
-
//# sourceMappingURL=Card-
|
|
163
|
+
//# sourceMappingURL=Card-CFFNq49v.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Card-_StSlnYh.js","sources":["../src/components/LockedAttachment/components/Received/CardActions.tsx","../src/components/LockedAttachment/components/Received/Card.tsx"],"sourcesContent":["import { DownloadSimpleIcon, LockSimpleIcon } from '@phosphor-icons/react'\nimport React from 'react'\n\nexport interface ReceivedCardActionsProps {\n /** Whether the card is currently locked. Drives which CTA we render. */\n isLocked: boolean\n /**\n * When unlocked, the URL used as the Download link's `href` (opens in a new\n * tab). When omitted, the Download CTA falls back to a plain `<button>`\n * that just calls `onDownloadClicked` — useful for galleries where the\n * single-source URL doesn't exist.\n */\n sourceUrl?: string\n /** Optional alternate href that takes precedence over `sourceUrl`. */\n redeemUrl?: string\n onUnlockClicked?: () => void\n onDownloadClicked?: () => void\n isUnlocking?: boolean\n}\n\nconst buttonClass =\n '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'\n\n/**\n * Renders the primary CTA below the body of a Received card.\n * - Locked + onUnlockClicked → \"Unlock\" button\n * - Unlocked + onDownloadClicked + (redeemUrl || sourceUrl) → \"Download\" link\n * - Unlocked + onDownloadClicked + no URL → \"Download\" button (e.g. gallery)\n * Otherwise renders nothing.\n */\nconst ReceivedCardActions: React.FC<ReceivedCardActionsProps> = ({\n isLocked,\n sourceUrl,\n redeemUrl,\n onUnlockClicked,\n onDownloadClicked,\n isUnlocking = false,\n}) => {\n if (isLocked && onUnlockClicked != null) {\n return (\n <button\n type=\"button\"\n onClick={onUnlockClicked}\n disabled={isUnlocking}\n className={buttonClass}\n >\n {isUnlocking ? (\n <span className=\"size-4 animate-spin rounded-full border-2 border-white/30 border-t-white\" />\n ) : (\n <React.Fragment>\n <LockSimpleIcon className=\"size-4\" weight=\"fill\" />\n Unlock\n </React.Fragment>\n )}\n </button>\n )\n }\n\n if (!isLocked && onDownloadClicked != null) {\n const href = redeemUrl ?? sourceUrl\n if (href != null) {\n return (\n <a\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n onClick={onDownloadClicked}\n className={`${buttonClass} !text-white`}\n >\n <DownloadSimpleIcon className=\"size-4\" weight=\"bold\" />\n Download\n </a>\n )\n }\n\n return (\n <button\n type=\"button\"\n onClick={onDownloadClicked}\n className={buttonClass}\n >\n <DownloadSimpleIcon className=\"size-4\" weight=\"bold\" />\n Download\n </button>\n )\n }\n\n return null\n}\n\nexport default ReceivedCardActions\n","import { CheckCircleIcon, ImagesIcon } from '@phosphor-icons/react'\nimport React, { useCallback, useEffect, useRef, useState } from 'react'\n\nimport { getSourceType } from '../../../AttachmentCard'\nimport type {\n LockedAttachmentBaseProps,\n LockedAttachmentSource,\n} from '../../types'\nimport CardBody from '../_shared/CardBody'\nimport GalleryThumbnail from '../_shared/GalleryThumbnail'\nimport LockedCardShell from '../_shared/LockedCardShell'\nimport LockedThumbnail from '../_shared/LockedThumbnail'\n\nimport ReceivedCardActions from './CardActions'\n\nexport interface ReceivedCardProps extends LockedAttachmentBaseProps {\n /**\n * Called when the recipient clicks Unlock on an unpaid attachment.\n * Use this to open a checkout flow. Omit to hide the Unlock button.\n */\n onUnlockClick?: () => void\n /**\n * Called to fetch the attachment source — fired automatically when\n * `paymentStatus` transitions to `'paid'`, or immediately on click when\n * `paymentStatus` is already `'paid'`. Return a `LockedAttachmentSource`\n * to unlock the card.\n */\n onFetchSource?: () => Promise<LockedAttachmentSource | void>\n /**\n * Called when the recipient clicks Download on an unlocked card.\n * Omit to hide the Download button.\n */\n onDownloadClick?: () => void\n /**\n * When true, shows a loading spinner on the Unlock button.\n * Driven by the LockedAttachmentContext (e.g. checkout in progress).\n */\n isUnlocking?: boolean\n}\n\n/**\n * The card the recipient sees in chat for a paid attachment.\n * Matches the Received column of the messaging design system in Figma:\n * locked → blurred thumbnail + Unlock CTA, unlocked → clear image + Download CTA.\n */\nconst ReceivedCard: React.FC<ReceivedCardProps> = ({\n title,\n amountText,\n thumbnailUrl,\n mimeType = 'application/octet-stream',\n detail,\n gallery,\n onUnlockClick,\n onFetchSource,\n onDownloadClick,\n paymentStatus,\n isUnlocking = false,\n}) => {\n const isGallery = (gallery?.length ?? 0) >= 2\n const [source, setSource] = useState<LockedAttachmentSource | undefined>()\n\n const cardRef = useRef<HTMLDivElement>(null)\n const fetchingRef = useRef(false)\n\n const onFetchSourceRef = useRef(onFetchSource)\n onFetchSourceRef.current = onFetchSource\n\n const effectiveSourceUrl = source?.sourceUrl\n const effectiveRedeemUrl = source?.redeemUrl\n\n const fetchSource = useCallback(async (): Promise<void> => {\n if (fetchingRef.current) return\n fetchingRef.current = true\n try {\n const result = await onFetchSourceRef.current?.()\n if (result) setSource(result)\n } finally {\n fetchingRef.current = false\n }\n }, [])\n\n const handleUnlockClick = useCallback(() => {\n if (paymentStatus === 'paid') {\n void fetchSource()\n } else {\n onUnlockClick?.()\n }\n }, [paymentStatus, fetchSource, onUnlockClick])\n\n // Auto-fetch the source once the paid card scrolls into view.\n useEffect(() => {\n if (!cardRef.current) return\n if (paymentStatus !== 'paid' || source !== undefined) return\n\n const observer = new IntersectionObserver(\n ([entry]) => {\n if (entry.isIntersecting) {\n void fetchSource()\n observer.disconnect()\n }\n },\n { threshold: 1.0 }\n )\n\n observer.observe(cardRef.current)\n return () => observer.disconnect()\n }, [paymentStatus, source, fetchSource])\n\n // For gallery, the per-item sources are carried by `gallery` itself, so\n // the lock state is driven by paymentStatus rather than the single\n // `effectiveSourceUrl`. Everything else still respects the source fetch.\n const isLocked = isGallery\n ? paymentStatus !== 'paid'\n : effectiveSourceUrl === undefined\n const sourceType = getSourceType(mimeType)\n\n const statusBadge =\n paymentStatus === 'paid' ? (\n <React.Fragment>\n <span className=\"text-xs font-medium text-black/55\">•</span>\n <span className=\"text-xs font-medium text-[#008236]\">Purchased</span>\n <CheckCircleIcon className=\"size-4 text-[#008236]\" weight=\"bold\" />\n </React.Fragment>\n ) : amountText != null ? (\n <React.Fragment>\n <span className=\"text-xs font-medium text-black/55\">•</span>\n <span className=\"text-xs font-medium text-black/55\">{amountText}</span>\n </React.Fragment>\n ) : null\n\n // For gallery, ReceivedCardActions falls back to a plain <button>\n // (no anchor) because the gallery has no single sourceUrl to link to —\n // the per-item sources live on `gallery` itself.\n const actionSourceUrl = isGallery ? undefined : effectiveSourceUrl\n\n return (\n <LockedCardShell\n variant=\"light\"\n rootRef={cardRef}\n data-testid=\"locked-attachment\"\n >\n {isGallery ? (\n <GalleryThumbnail\n variant=\"light\"\n gallery={gallery!}\n title={title}\n showLocked={isLocked}\n paymentStatus={paymentStatus}\n />\n ) : (\n <LockedThumbnail\n variant=\"light\"\n mimeType={mimeType}\n thumbnailUrl={thumbnailUrl}\n title={title}\n source={source}\n showLocked={isLocked}\n paymentStatus={paymentStatus}\n containedImage={\n !isLocked && (sourceType === 'image' || sourceType === 'document')\n }\n />\n )}\n\n <CardBody\n variant=\"light\"\n title={title}\n mimeType={mimeType}\n detail={detail}\n statusBadge={statusBadge}\n icon={\n isGallery ? (\n <ImagesIcon className=\"size-5 shrink-0 text-black/55\" />\n ) : undefined\n }\n action={\n <ReceivedCardActions\n isLocked={isLocked}\n isUnlocking={isUnlocking}\n sourceUrl={actionSourceUrl}\n redeemUrl={effectiveRedeemUrl}\n onUnlockClicked={handleUnlockClick}\n onDownloadClicked={onDownloadClick}\n />\n }\n />\n </LockedCardShell>\n )\n}\n\nexport default ReceivedCard\n"],"names":["buttonClass","ReceivedCardActions","isLocked","sourceUrl","redeemUrl","onUnlockClicked","onDownloadClicked","isUnlocking","jsx","jsxs","React","LockSimpleIcon","href","DownloadSimpleIcon","ReceivedCard","title","amountText","thumbnailUrl","mimeType","detail","gallery","onUnlockClick","onFetchSource","onDownloadClick","paymentStatus","isGallery","source","setSource","useState","cardRef","useRef","fetchingRef","onFetchSourceRef","effectiveSourceUrl","effectiveRedeemUrl","fetchSource","useCallback","result","_a","handleUnlockClick","useEffect","observer","entry","sourceType","getSourceType","statusBadge","CheckCircleIcon","LockedCardShell","GalleryThumbnail","LockedThumbnail","CardBody","ImagesIcon"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Card-CFFNq49v.js","sources":["../src/components/LockedAttachment/components/Received/CardActions.tsx","../src/components/LockedAttachment/components/Received/Card.tsx"],"sourcesContent":["import { DownloadSimpleIcon, LockSimpleIcon } from '@phosphor-icons/react'\nimport React from 'react'\n\nexport interface ReceivedCardActionsProps {\n /** Whether the card is currently locked. Drives which CTA we render. */\n isLocked: boolean\n /**\n * When unlocked, the URL used as the Download link's `href` (opens in a new\n * tab). When omitted, the Download CTA falls back to a plain `<button>`\n * that just calls `onDownloadClicked` — useful for galleries where the\n * single-source URL doesn't exist.\n */\n sourceUrl?: string\n /** Optional alternate href that takes precedence over `sourceUrl`. */\n redeemUrl?: string\n onUnlockClicked?: () => void\n onDownloadClicked?: () => void\n isUnlocking?: boolean\n}\n\nconst buttonClass =\n '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'\n\n/**\n * Renders the primary CTA below the body of a Received card.\n * - Locked + onUnlockClicked → \"Unlock\" button\n * - Unlocked + onDownloadClicked + (redeemUrl || sourceUrl) → \"Download\" link\n * - Unlocked + onDownloadClicked + no URL → \"Download\" button (e.g. gallery)\n * Otherwise renders nothing.\n */\nconst ReceivedCardActions: React.FC<ReceivedCardActionsProps> = ({\n isLocked,\n sourceUrl,\n redeemUrl,\n onUnlockClicked,\n onDownloadClicked,\n isUnlocking = false,\n}) => {\n if (isLocked && onUnlockClicked != null) {\n return (\n <button\n type=\"button\"\n onClick={onUnlockClicked}\n disabled={isUnlocking}\n className={buttonClass}\n >\n {isUnlocking ? (\n <span className=\"size-4 animate-spin rounded-full border-2 border-white/30 border-t-white\" />\n ) : (\n <React.Fragment>\n <LockSimpleIcon className=\"size-4\" weight=\"fill\" />\n Unlock\n </React.Fragment>\n )}\n </button>\n )\n }\n\n if (!isLocked && onDownloadClicked != null) {\n const href = redeemUrl ?? sourceUrl\n if (href != null) {\n return (\n <a\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n onClick={onDownloadClicked}\n className={`${buttonClass} !text-white`}\n >\n <DownloadSimpleIcon className=\"size-4\" weight=\"bold\" />\n Download\n </a>\n )\n }\n\n return (\n <button\n type=\"button\"\n onClick={onDownloadClicked}\n className={buttonClass}\n >\n <DownloadSimpleIcon className=\"size-4\" weight=\"bold\" />\n Download\n </button>\n )\n }\n\n return null\n}\n\nexport default ReceivedCardActions\n","import { CheckCircleIcon, ImagesIcon } from '@phosphor-icons/react'\nimport React, { useCallback, useEffect, useRef, useState } from 'react'\n\nimport { getSourceType } from '../../../AttachmentCard'\nimport type {\n LockedAttachmentBaseProps,\n LockedAttachmentSource,\n} from '../../types'\nimport CardBody from '../_shared/CardBody'\nimport GalleryThumbnail from '../_shared/GalleryThumbnail'\nimport LockedCardShell from '../_shared/LockedCardShell'\nimport LockedThumbnail from '../_shared/LockedThumbnail'\n\nimport ReceivedCardActions from './CardActions'\n\nexport interface ReceivedCardProps extends LockedAttachmentBaseProps {\n /**\n * Called when the recipient clicks Unlock on an unpaid attachment.\n * Use this to open a checkout flow. Omit to hide the Unlock button.\n */\n onUnlockClick?: () => void\n /**\n * Called to fetch the attachment source — fired automatically when\n * `paymentStatus` transitions to `'paid'`, or immediately on click when\n * `paymentStatus` is already `'paid'`. Return a `LockedAttachmentSource`\n * to unlock the card.\n */\n onFetchSource?: () => Promise<LockedAttachmentSource | void>\n /**\n * Called when the recipient clicks Download on an unlocked card.\n * Omit to hide the Download button.\n */\n onDownloadClick?: () => void\n /**\n * When true, shows a loading spinner on the Unlock button.\n * Driven by the LockedAttachmentContext (e.g. checkout in progress).\n */\n isUnlocking?: boolean\n}\n\n/**\n * The card the recipient sees in chat for a paid attachment.\n * Matches the Received column of the messaging design system in Figma:\n * locked → blurred thumbnail + Unlock CTA, unlocked → clear image + Download CTA.\n */\nconst ReceivedCard: React.FC<ReceivedCardProps> = ({\n title,\n amountText,\n thumbnailUrl,\n mimeType = 'application/octet-stream',\n detail,\n gallery,\n onUnlockClick,\n onFetchSource,\n onDownloadClick,\n paymentStatus,\n isUnlocking = false,\n}) => {\n const isGallery = (gallery?.length ?? 0) >= 2\n const [source, setSource] = useState<LockedAttachmentSource | undefined>()\n\n const cardRef = useRef<HTMLDivElement>(null)\n const fetchingRef = useRef(false)\n\n const onFetchSourceRef = useRef(onFetchSource)\n onFetchSourceRef.current = onFetchSource\n\n const effectiveSourceUrl = source?.sourceUrl\n const effectiveRedeemUrl = source?.redeemUrl\n\n const fetchSource = useCallback(async (): Promise<void> => {\n if (fetchingRef.current) return\n fetchingRef.current = true\n try {\n const result = await onFetchSourceRef.current?.()\n if (result) setSource(result)\n } finally {\n fetchingRef.current = false\n }\n }, [])\n\n const handleUnlockClick = useCallback(() => {\n if (paymentStatus === 'paid') {\n void fetchSource()\n } else {\n onUnlockClick?.()\n }\n }, [paymentStatus, fetchSource, onUnlockClick])\n\n // Auto-fetch the source once the paid card scrolls into view.\n useEffect(() => {\n if (!cardRef.current) return\n if (paymentStatus !== 'paid' || source !== undefined) return\n\n const observer = new IntersectionObserver(\n ([entry]) => {\n if (entry.isIntersecting) {\n void fetchSource()\n observer.disconnect()\n }\n },\n { threshold: 1.0 }\n )\n\n observer.observe(cardRef.current)\n return () => observer.disconnect()\n }, [paymentStatus, source, fetchSource])\n\n // For gallery, the per-item sources are carried by `gallery` itself, so\n // the lock state is driven by paymentStatus rather than the single\n // `effectiveSourceUrl`. Everything else still respects the source fetch.\n const isLocked = isGallery\n ? paymentStatus !== 'paid'\n : effectiveSourceUrl === undefined\n const sourceType = getSourceType(mimeType)\n\n const statusBadge =\n paymentStatus === 'paid' ? (\n <React.Fragment>\n <span className=\"text-xs font-medium text-black/55\">•</span>\n <span className=\"text-xs font-medium text-[#008236]\">Purchased</span>\n <CheckCircleIcon className=\"size-4 text-[#008236]\" weight=\"bold\" />\n </React.Fragment>\n ) : amountText != null ? (\n <React.Fragment>\n <span className=\"text-xs font-medium text-black/55\">•</span>\n <span className=\"text-xs font-medium text-black/55\">{amountText}</span>\n </React.Fragment>\n ) : null\n\n // For gallery, ReceivedCardActions falls back to a plain <button>\n // (no anchor) because the gallery has no single sourceUrl to link to —\n // the per-item sources live on `gallery` itself.\n const actionSourceUrl = isGallery ? undefined : effectiveSourceUrl\n\n return (\n <LockedCardShell\n variant=\"light\"\n rootRef={cardRef}\n data-testid=\"locked-attachment\"\n >\n {isGallery ? (\n <GalleryThumbnail\n variant=\"light\"\n gallery={gallery!}\n title={title}\n showLocked={isLocked}\n paymentStatus={paymentStatus}\n />\n ) : (\n <LockedThumbnail\n variant=\"light\"\n mimeType={mimeType}\n thumbnailUrl={thumbnailUrl}\n title={title}\n source={source}\n showLocked={isLocked}\n paymentStatus={paymentStatus}\n containedImage={\n !isLocked && (sourceType === 'image' || sourceType === 'document')\n }\n />\n )}\n\n <CardBody\n variant=\"light\"\n title={title}\n mimeType={mimeType}\n detail={detail}\n statusBadge={statusBadge}\n icon={\n isGallery ? (\n <ImagesIcon className=\"size-5 shrink-0 text-black/55\" />\n ) : undefined\n }\n action={\n <ReceivedCardActions\n isLocked={isLocked}\n isUnlocking={isUnlocking}\n sourceUrl={actionSourceUrl}\n redeemUrl={effectiveRedeemUrl}\n onUnlockClicked={handleUnlockClick}\n onDownloadClicked={onDownloadClick}\n />\n }\n />\n </LockedCardShell>\n )\n}\n\nexport default ReceivedCard\n"],"names":["buttonClass","ReceivedCardActions","isLocked","sourceUrl","redeemUrl","onUnlockClicked","onDownloadClicked","isUnlocking","jsx","jsxs","React","LockSimpleIcon","href","DownloadSimpleIcon","ReceivedCard","title","amountText","thumbnailUrl","mimeType","detail","gallery","onUnlockClick","onFetchSource","onDownloadClick","paymentStatus","isGallery","source","setSource","useState","cardRef","useRef","fetchingRef","onFetchSourceRef","effectiveSourceUrl","effectiveRedeemUrl","fetchSource","useCallback","result","_a","handleUnlockClick","useEffect","observer","entry","sourceType","getSourceType","statusBadge","CheckCircleIcon","LockedCardShell","GalleryThumbnail","LockedThumbnail","CardBody","ImagesIcon"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsxs as x, jsx as e } from "react/jsx-runtime";
|
|
2
2
|
import { CheckCircleIcon as T, ImagesIcon as j } from "@phosphor-icons/react";
|
|
3
3
|
import k, { useState as b, useRef as z, useCallback as C } from "react";
|
|
4
|
-
import { L as D, C as V, G as A, a as E } from "./LockedThumbnail-
|
|
4
|
+
import { L as D, C as V, G as A, a as E } from "./LockedThumbnail-DpJx169C.js";
|
|
5
5
|
const M = ({
|
|
6
6
|
title: o,
|
|
7
7
|
mimeType: p = "application/octet-stream",
|
|
@@ -104,4 +104,4 @@ const M = ({
|
|
|
104
104
|
export {
|
|
105
105
|
M as default
|
|
106
106
|
};
|
|
107
|
-
//# sourceMappingURL=Card-
|
|
107
|
+
//# sourceMappingURL=Card-CsJvUF_b.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Card-
|
|
1
|
+
{"version":3,"file":"Card-CsJvUF_b.js","sources":["../src/components/LockedAttachment/components/Sent/Card.tsx"],"sourcesContent":["import { CheckCircleIcon, ImagesIcon } from '@phosphor-icons/react'\nimport React, { useCallback, useRef, useState } from 'react'\n\nimport type {\n LockedAttachmentBaseProps,\n LockedAttachmentSource,\n} from '../../types'\nimport CardBody from '../_shared/CardBody'\nimport GalleryThumbnail from '../_shared/GalleryThumbnail'\nimport LockedCardShell from '../_shared/LockedCardShell'\nimport LockedThumbnail from '../_shared/LockedThumbnail'\n\nexport interface SentCardProps extends LockedAttachmentBaseProps {\n /** Placeholder shown in the title slot when no title is set. */\n placeholderTitle?: string\n /** Fired the first time the sender taps the thumbnail to preview their own attachment. */\n onPreviewClick?: () => void\n /**\n * Lazily loads the underlying source so the sender can preview the attachment.\n * Called the first time the thumbnail is tapped; the returned source is cached\n * and reused on subsequent toggles.\n */\n onFetchSource?: () => Promise<LockedAttachmentSource | void>\n}\n\n/**\n * The card the sender sees in chat after a paid attachment has been posted.\n * Matches the Sent column of the messaging design system in Figma.\n */\nconst SentCard: React.FC<SentCardProps> = ({\n title,\n mimeType = 'application/octet-stream',\n thumbnailUrl,\n detail,\n amountText,\n placeholderTitle = 'Attachment title',\n paymentStatus,\n gallery,\n onPreviewClick,\n onFetchSource,\n}) => {\n const [source, setSource] = useState<LockedAttachmentSource | undefined>()\n const [isPreviewVisible, setIsPreviewVisible] = useState(false)\n const [isLoadingPreview, setIsLoadingPreview] = useState(false)\n const fetchingRef = useRef(false)\n\n const isGallery = (gallery?.length ?? 0) >= 2\n\n const handleToggle = useCallback(async () => {\n onPreviewClick?.()\n if (isPreviewVisible) {\n setIsPreviewVisible(false)\n return\n }\n // Gallery items carry their own per-item sources on the `gallery` prop, so\n // we just flip visibility — no async source fetch is needed.\n if (isGallery) {\n setIsPreviewVisible(true)\n return\n }\n if (source) {\n setIsPreviewVisible(true)\n return\n }\n if (!onFetchSource) return\n if (fetchingRef.current) return\n fetchingRef.current = true\n setIsLoadingPreview(true)\n try {\n const result = await onFetchSource()\n if (result) {\n setSource(result)\n setIsPreviewVisible(true)\n }\n } finally {\n fetchingRef.current = false\n setIsLoadingPreview(false)\n }\n }, [isPreviewVisible, isGallery, source, onPreviewClick, onFetchSource])\n\n // Gallery is always previewable for the sender because each item's source\n // is already provided up-front via `gallery[*].sourceUrl`.\n const togglePreview =\n isGallery || onFetchSource || onPreviewClick ? handleToggle : undefined\n const showLocked = !isPreviewVisible\n const isBusy = isLoadingPreview\n\n const statusBadge =\n paymentStatus === 'paid' ? (\n <React.Fragment>\n <span className=\"text-xs font-medium text-white/55\">•</span>\n <span className=\"text-xs font-medium text-[#34c759]\">Sold</span>\n <CheckCircleIcon className=\"size-4 text-[#34c759]\" weight=\"bold\" />\n </React.Fragment>\n ) : amountText ? (\n <React.Fragment>\n <span className=\"text-xs font-medium text-white/55\">•</span>\n <span className=\"text-xs font-medium text-white/55\">{amountText}</span>\n </React.Fragment>\n ) : null\n\n const thumbnail = isGallery ? (\n <GalleryThumbnail\n variant=\"dark\"\n gallery={gallery!}\n title={title}\n showLocked={showLocked}\n paymentStatus={paymentStatus}\n />\n ) : (\n <LockedThumbnail\n variant=\"dark\"\n mimeType={mimeType}\n thumbnailUrl={thumbnailUrl}\n title={title}\n source={source}\n showLocked={showLocked}\n paymentStatus={paymentStatus}\n />\n )\n\n return (\n <LockedCardShell variant=\"dark\">\n {togglePreview ? (\n // Uses a `<div role=\"button\">` rather than a native `<button>` so the\n // gallery's carousel arrow `<button>`s rendered inside `thumbnail`\n // don't produce invalid nested interactive elements.\n <div\n role=\"button\"\n tabIndex={isBusy ? -1 : 0}\n aria-label=\"Toggle preview\"\n aria-busy={isBusy}\n aria-pressed={!showLocked}\n aria-disabled={isBusy || undefined}\n onClick={isBusy ? undefined : togglePreview}\n onKeyDown={(e) => {\n if (isBusy) return\n // Only handle keys that originate on the wrapper itself, not on\n // inner interactive elements (gallery carousel arrows). Without\n // this guard, pressing Enter/Space on a focused child would bubble\n // up and toggle the preview in addition to activating the child.\n if (e.target !== e.currentTarget) return\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n void togglePreview()\n }\n }}\n className={\n !isBusy\n ? 'block w-full cursor-pointer text-left'\n : 'block w-full text-left'\n }\n >\n {thumbnail}\n </div>\n ) : (\n thumbnail\n )}\n\n <CardBody\n variant=\"dark\"\n title={title}\n placeholderTitle={placeholderTitle}\n mimeType={mimeType}\n detail={detail}\n statusBadge={statusBadge}\n icon={\n isGallery ? (\n <ImagesIcon className=\"size-5 shrink-0 text-white/55\" />\n ) : undefined\n }\n />\n </LockedCardShell>\n )\n}\n\nexport default SentCard\n"],"names":["SentCard","title","mimeType","thumbnailUrl","detail","amountText","placeholderTitle","paymentStatus","gallery","onPreviewClick","onFetchSource","source","setSource","useState","isPreviewVisible","setIsPreviewVisible","isLoadingPreview","setIsLoadingPreview","fetchingRef","useRef","isGallery","handleToggle","useCallback","result","togglePreview","showLocked","isBusy","statusBadge","jsxs","React","jsx","CheckCircleIcon","thumbnail","GalleryThumbnail","LockedThumbnail","LockedCardShell","e","CardBody","ImagesIcon"],"mappings":"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"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { jsx as a, jsxs as d } from "react/jsx-runtime";
|
|
2
|
+
import { XIcon as x, PencilSimpleIcon as N } from "@phosphor-icons/react";
|
|
3
|
+
import { i as k, C as o, A as w, a as c, b as A } from "./CardThumbnail-DTBuRQHF.js";
|
|
4
|
+
const B = ({
|
|
5
|
+
title: e,
|
|
6
|
+
placeholderTitle: h,
|
|
7
|
+
description: m,
|
|
8
|
+
url: u,
|
|
9
|
+
mimeType: i,
|
|
10
|
+
thumbnailUrl: b,
|
|
11
|
+
sourceUrl: s,
|
|
12
|
+
layout: f = "featured",
|
|
13
|
+
appIcon: v,
|
|
14
|
+
cta: g,
|
|
15
|
+
onDismiss: r,
|
|
16
|
+
onEditClick: n
|
|
17
|
+
}) => {
|
|
18
|
+
const l = f === "classic", p = k(i, s), t = r ? /* @__PURE__ */ a(
|
|
19
|
+
"button",
|
|
20
|
+
{
|
|
21
|
+
type: "button",
|
|
22
|
+
onClick: r,
|
|
23
|
+
"aria-label": "Dismiss attachment",
|
|
24
|
+
className: "flex size-6 items-center justify-center rounded-full bg-[#121110] text-white",
|
|
25
|
+
children: /* @__PURE__ */ a(x, { className: "size-3", weight: "bold" })
|
|
26
|
+
}
|
|
27
|
+
) : void 0, C = n ? /* @__PURE__ */ a(
|
|
28
|
+
"button",
|
|
29
|
+
{
|
|
30
|
+
type: "button",
|
|
31
|
+
onClick: n,
|
|
32
|
+
"aria-label": "Edit attachment",
|
|
33
|
+
className: "flex size-10 items-center justify-center rounded-full bg-white/10 text-white hover:bg-white/15",
|
|
34
|
+
children: /* @__PURE__ */ a(N, { className: "size-5", weight: "regular" })
|
|
35
|
+
}
|
|
36
|
+
) : void 0;
|
|
37
|
+
return p ? /* @__PURE__ */ a(o, { variant: "dark", bgClassName: w, children: /* @__PURE__ */ d("div", { className: "flex items-center gap-2 pr-3", children: [
|
|
38
|
+
/* @__PURE__ */ a("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ a(
|
|
39
|
+
c,
|
|
40
|
+
{
|
|
41
|
+
variant: "dark",
|
|
42
|
+
sourceUrl: s,
|
|
43
|
+
title: e,
|
|
44
|
+
mimeType: i
|
|
45
|
+
}
|
|
46
|
+
) }),
|
|
47
|
+
t && /* @__PURE__ */ a("div", { className: "shrink-0", children: t })
|
|
48
|
+
] }) }) : /* @__PURE__ */ d(
|
|
49
|
+
o,
|
|
50
|
+
{
|
|
51
|
+
variant: "dark",
|
|
52
|
+
topRight: l ? t : void 0,
|
|
53
|
+
children: [
|
|
54
|
+
!l && /* @__PURE__ */ a(
|
|
55
|
+
c,
|
|
56
|
+
{
|
|
57
|
+
variant: "dark",
|
|
58
|
+
thumbnailUrl: b,
|
|
59
|
+
sourceUrl: s,
|
|
60
|
+
title: e,
|
|
61
|
+
mimeType: i,
|
|
62
|
+
topRight: t
|
|
63
|
+
}
|
|
64
|
+
),
|
|
65
|
+
/* @__PURE__ */ a(
|
|
66
|
+
A,
|
|
67
|
+
{
|
|
68
|
+
variant: "dark",
|
|
69
|
+
title: e,
|
|
70
|
+
placeholderTitle: h,
|
|
71
|
+
description: m,
|
|
72
|
+
url: u,
|
|
73
|
+
appIcon: v,
|
|
74
|
+
cta: g,
|
|
75
|
+
trailingAction: C
|
|
76
|
+
}
|
|
77
|
+
)
|
|
78
|
+
]
|
|
79
|
+
}
|
|
80
|
+
);
|
|
81
|
+
};
|
|
82
|
+
export {
|
|
83
|
+
B as default
|
|
84
|
+
};
|
|
85
|
+
//# sourceMappingURL=Card-D32U6KfZ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Card-D32U6KfZ.js","sources":["../src/components/LinkAttachment/components/Composer/Card.tsx"],"sourcesContent":["import { PencilSimpleIcon, XIcon } from '@phosphor-icons/react'\nimport React from 'react'\n\nimport type { LinkAttachmentBaseProps } from '../../types'\nimport CardBody from '../_shared/CardBody'\nimport CardShell from '../_shared/CardShell'\nimport CardThumbnail, {\n AUDIO_BG_CLASS,\n isPlayableAudio,\n} from '../_shared/CardThumbnail'\n\nexport interface ComposerCardProps extends LinkAttachmentBaseProps {\n /**\n * When provided, renders a dismiss X in the thumbnail corner. Called when\n * the composer clicks it to remove the attachment.\n */\n onDismiss?: () => void\n /**\n * When provided, renders a pencil button to the right of the description\n * that the composer can use to edit the attachment metadata.\n */\n onEditClick?: () => void\n}\n\n/**\n * The card the composer sees while drafting a link attachment.\n * Matches the Composer column of the messaging design system in Figma.\n */\nconst ComposerCard: React.FC<ComposerCardProps> = ({\n title,\n placeholderTitle,\n description,\n url,\n mimeType,\n thumbnailUrl,\n sourceUrl,\n layout = 'featured',\n appIcon,\n cta,\n onDismiss,\n onEditClick,\n}) => {\n const isClassic = layout === 'classic'\n const isAudio = isPlayableAudio(mimeType, sourceUrl)\n const dismissButton = onDismiss ? (\n <button\n type=\"button\"\n onClick={onDismiss}\n aria-label=\"Dismiss attachment\"\n className=\"flex size-6 items-center justify-center rounded-full bg-[#121110] text-white\"\n >\n <XIcon className=\"size-3\" weight=\"bold\" />\n </button>\n ) : undefined\n\n const editButton = onEditClick ? (\n <button\n type=\"button\"\n onClick={onEditClick}\n aria-label=\"Edit attachment\"\n className=\"flex size-10 items-center justify-center rounded-full bg-white/10 text-white hover:bg-white/15\"\n >\n <PencilSimpleIcon className=\"size-5\" weight=\"regular\" />\n </button>\n ) : undefined\n\n // Audio cards collapse to just the native player — render the dismiss\n // button as an inline sibling so it always has its own space and never\n // overlaps the audio control's volume/menu buttons.\n if (isAudio) {\n return (\n <CardShell variant=\"dark\" bgClassName={AUDIO_BG_CLASS}>\n <div className=\"flex items-center gap-2 pr-3\">\n <div className=\"min-w-0 flex-1\">\n <CardThumbnail\n variant=\"dark\"\n sourceUrl={sourceUrl}\n title={title}\n mimeType={mimeType}\n />\n </div>\n {dismissButton && <div className=\"shrink-0\">{dismissButton}</div>}\n </div>\n </CardShell>\n )\n }\n\n return (\n <CardShell\n variant=\"dark\"\n topRight={isClassic ? dismissButton : undefined}\n >\n {!isClassic && (\n <CardThumbnail\n variant=\"dark\"\n thumbnailUrl={thumbnailUrl}\n sourceUrl={sourceUrl}\n title={title}\n mimeType={mimeType}\n topRight={dismissButton}\n />\n )}\n <CardBody\n variant=\"dark\"\n title={title}\n placeholderTitle={placeholderTitle}\n description={description}\n url={url}\n appIcon={appIcon}\n cta={cta}\n trailingAction={editButton}\n />\n </CardShell>\n )\n}\n\nexport default ComposerCard\n"],"names":["ComposerCard","title","placeholderTitle","description","url","mimeType","thumbnailUrl","sourceUrl","layout","appIcon","cta","onDismiss","onEditClick","isClassic","isAudio","isPlayableAudio","dismissButton","jsx","XIcon","editButton","PencilSimpleIcon","CardShell","AUDIO_BG_CLASS","jsxs","CardThumbnail","CardBody"],"mappings":";;;AA4BA,MAAMA,IAA4C,CAAC;AAAA,EACjD,OAAAC;AAAA,EACA,kBAAAC;AAAA,EACA,aAAAC;AAAA,EACA,KAAAC;AAAA,EACA,UAAAC;AAAA,EACA,cAAAC;AAAA,EACA,WAAAC;AAAA,EACA,QAAAC,IAAS;AAAA,EACT,SAAAC;AAAA,EACA,KAAAC;AAAA,EACA,WAAAC;AAAA,EACA,aAAAC;AACF,MAAM;AACJ,QAAMC,IAAYL,MAAW,WACvBM,IAAUC,EAAgBV,GAAUE,CAAS,GAC7CS,IAAgBL,IACpB,gBAAAM;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAK;AAAA,MACL,SAASN;AAAA,MACT,cAAW;AAAA,MACX,WAAU;AAAA,MAEV,UAAA,gBAAAM,EAACC,GAAA,EAAM,WAAU,UAAS,QAAO,OAAA,CAAO;AAAA,IAAA;AAAA,EAAA,IAExC,QAEEC,IAAaP,IACjB,gBAAAK;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAK;AAAA,MACL,SAASL;AAAA,MACT,cAAW;AAAA,MACX,WAAU;AAAA,MAEV,UAAA,gBAAAK,EAACG,GAAA,EAAiB,WAAU,UAAS,QAAO,UAAA,CAAU;AAAA,IAAA;AAAA,EAAA,IAEtD;AAKJ,SAAIN,IAEA,gBAAAG,EAACI,KAAU,SAAQ,QAAO,aAAaC,GACrC,UAAA,gBAAAC,EAAC,OAAA,EAAI,WAAU,gCACb,UAAA;AAAA,IAAA,gBAAAN,EAAC,OAAA,EAAI,WAAU,kBACb,UAAA,gBAAAA;AAAA,MAACO;AAAA,MAAA;AAAA,QACC,SAAQ;AAAA,QACR,WAAAjB;AAAA,QACA,OAAAN;AAAA,QACA,UAAAI;AAAA,MAAA;AAAA,IAAA,GAEJ;AAAA,IACCW,KAAiB,gBAAAC,EAAC,OAAA,EAAI,WAAU,YAAY,UAAAD,EAAA,CAAc;AAAA,EAAA,EAAA,CAC7D,EAAA,CACF,IAKF,gBAAAO;AAAA,IAACF;AAAA,IAAA;AAAA,MACC,SAAQ;AAAA,MACR,UAAUR,IAAYG,IAAgB;AAAA,MAErC,UAAA;AAAA,QAAA,CAACH,KACA,gBAAAI;AAAA,UAACO;AAAA,UAAA;AAAA,YACC,SAAQ;AAAA,YACR,cAAAlB;AAAA,YACA,WAAAC;AAAA,YACA,OAAAN;AAAA,YACA,UAAAI;AAAA,YACA,UAAUW;AAAA,UAAA;AAAA,QAAA;AAAA,QAGd,gBAAAC;AAAA,UAACQ;AAAA,UAAA;AAAA,YACC,SAAQ;AAAA,YACR,OAAAxB;AAAA,YACA,kBAAAC;AAAA,YACA,aAAAC;AAAA,YACA,KAAAC;AAAA,YACA,SAAAK;AAAA,YACA,KAAAC;AAAA,YACA,gBAAgBS;AAAA,UAAA;AAAA,QAAA;AAAA,MAClB;AAAA,IAAA;AAAA,EAAA;AAGN;"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsxs as y, jsx as t } from "react/jsx-runtime";
|
|
2
2
|
import { ImagesIcon as A, PencilSimpleIcon as C, XIcon as D } from "@phosphor-icons/react";
|
|
3
3
|
import V, { useState as h, useRef as E, useCallback as K } from "react";
|
|
4
|
-
import { L as P, C as S, G as X, a as q } from "./LockedThumbnail-
|
|
4
|
+
import { L as P, C as S, G as X, a as q } from "./LockedThumbnail-DpJx169C.js";
|
|
5
5
|
const Q = ({
|
|
6
6
|
title: l,
|
|
7
7
|
mimeType: b = "application/octet-stream",
|
|
@@ -129,4 +129,4 @@ const Q = ({
|
|
|
129
129
|
export {
|
|
130
130
|
Q as default
|
|
131
131
|
};
|
|
132
|
-
//# sourceMappingURL=Card-
|
|
132
|
+
//# sourceMappingURL=Card-DlMSDSdm.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Card-DLUBUg_w.js","sources":["../src/components/LockedAttachment/components/Composer/Card.tsx"],"sourcesContent":["import { ImagesIcon, PencilSimpleIcon, XIcon } from '@phosphor-icons/react'\nimport React, { useCallback, useRef, useState } from 'react'\n\nimport type {\n LockedAttachmentBaseProps,\n LockedAttachmentSource,\n} from '../../types'\nimport CardBody from '../_shared/CardBody'\nimport GalleryThumbnail from '../_shared/GalleryThumbnail'\nimport LockedCardShell from '../_shared/LockedCardShell'\nimport LockedThumbnail from '../_shared/LockedThumbnail'\n\nexport interface ComposerCardProps extends LockedAttachmentBaseProps {\n /** Placeholder shown in the title slot before the composer types one. */\n placeholderTitle?: string\n /** Placeholder shown in the amount slot before one is configured. */\n placeholderAmountText?: string\n /**\n * When provided, renders a dismiss X in the thumbnail corner. Called when\n * the composer clicks it to remove the attachment.\n */\n onDismiss?: () => void\n /** Fired the first time the composer taps the thumbnail to preview. */\n onPreviewClick?: () => void\n /**\n * Lazily loads the underlying source so the composer can preview the\n * attachment they're about to send. Called the first time the thumbnail is\n * tapped; the returned source is cached and reused on subsequent toggles.\n */\n onFetchSource?: () => Promise<LockedAttachmentSource | void>\n /**\n * When provided, renders a pencil button in the body bottom-right that the\n * composer can use to edit the attachment metadata (e.g. open the price /\n * gallery editor). Matches the Composer \"Button\" instance in Figma.\n */\n onEditClick?: () => void\n}\n\n/**\n * The card the composer sees while drafting a paid attachment.\n * Matches the Composer column of the messaging design system in Figma.\n */\nconst ComposerCard: React.FC<ComposerCardProps> = ({\n title,\n mimeType = 'application/octet-stream',\n thumbnailUrl,\n detail,\n amountText,\n placeholderTitle = 'Attachment title',\n placeholderAmountText,\n gallery,\n onDismiss,\n onPreviewClick,\n onFetchSource,\n onEditClick,\n}) => {\n const [source, setSource] = useState<LockedAttachmentSource | undefined>()\n const [isPreviewVisible, setIsPreviewVisible] = useState(false)\n const [isLoadingPreview, setIsLoadingPreview] = useState(false)\n const fetchingRef = useRef(false)\n\n const isGallery = (gallery?.length ?? 0) >= 2\n\n const handleToggle = useCallback(async () => {\n onPreviewClick?.()\n if (isPreviewVisible) {\n setIsPreviewVisible(false)\n return\n }\n // Gallery items carry their own per-item sources on the `gallery` prop, so\n // we just flip visibility — no async source fetch is needed.\n if (isGallery) {\n setIsPreviewVisible(true)\n return\n }\n if (source) {\n setIsPreviewVisible(true)\n return\n }\n if (!onFetchSource) return\n if (fetchingRef.current) return\n fetchingRef.current = true\n setIsLoadingPreview(true)\n try {\n const result = await onFetchSource()\n if (result) {\n setSource(result)\n setIsPreviewVisible(true)\n }\n } finally {\n fetchingRef.current = false\n setIsLoadingPreview(false)\n }\n }, [isPreviewVisible, isGallery, source, onPreviewClick, onFetchSource])\n\n // Gallery is always previewable in the composer because each item's source\n // is already provided up-front via `gallery[*].sourceUrl`.\n const togglePreview =\n isGallery || onFetchSource || onPreviewClick ? handleToggle : undefined\n const showLocked = !isPreviewVisible\n const isBusy = isLoadingPreview\n\n const statusBadge = (\n <React.Fragment>\n <span className=\"text-xs font-medium text-white/55\">•</span>\n <span\n className={\n amountText\n ? 'text-xs font-medium text-white/55'\n : 'text-xs font-medium text-white/30'\n }\n >\n {amountText || placeholderAmountText}\n </span>\n </React.Fragment>\n )\n\n const dismissButton = onDismiss ? (\n <button\n type=\"button\"\n onClick={(e) => {\n // Stop the click from bubbling up into the outer preview-toggle\n // wrapper when both are wired up at the same time.\n e.stopPropagation()\n onDismiss()\n }}\n className=\"flex size-6 items-center justify-center rounded-full bg-[#121110] text-white\"\n aria-label=\"Dismiss attachment\"\n >\n <XIcon className=\"size-3\" weight=\"bold\" />\n </button>\n ) : undefined\n\n const editButton = onEditClick ? (\n <button\n type=\"button\"\n onClick={onEditClick}\n aria-label=\"Edit attachment\"\n className=\"flex size-10 items-center justify-center rounded-full bg-white/10 text-white hover:bg-white/15\"\n >\n <PencilSimpleIcon className=\"size-5\" weight=\"regular\" />\n </button>\n ) : undefined\n\n const thumbnail = isGallery ? (\n <GalleryThumbnail\n variant=\"dark\"\n gallery={gallery!}\n title={title}\n showLocked={showLocked}\n topRight={dismissButton}\n />\n ) : (\n <LockedThumbnail\n variant=\"dark\"\n mimeType={mimeType}\n thumbnailUrl={thumbnailUrl}\n title={title}\n source={source}\n showLocked={showLocked}\n topRight={dismissButton}\n />\n )\n\n return (\n <LockedCardShell variant=\"dark\">\n {togglePreview ? (\n // Uses a `<div role=\"button\">` rather than a native `<button>` so the\n // dismiss control rendered inside `thumbnail` (also a `<button>`)\n // doesn't produce invalid nested interactive elements.\n <div\n role=\"button\"\n tabIndex={isBusy ? -1 : 0}\n aria-label=\"Toggle preview\"\n aria-busy={isBusy}\n aria-pressed={!showLocked}\n aria-disabled={isBusy || undefined}\n onClick={isBusy ? undefined : togglePreview}\n onKeyDown={(e) => {\n if (isBusy) return\n // Only handle keys that originate on the wrapper itself, not on\n // inner interactive elements (dismiss X, carousel arrows). Without\n // this guard, pressing Enter/Space on a focused child would bubble\n // up and toggle the preview in addition to activating the child.\n if (e.target !== e.currentTarget) return\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n void togglePreview()\n }\n }}\n className={\n !isBusy\n ? 'block w-full cursor-pointer text-left'\n : 'block w-full text-left'\n }\n >\n {thumbnail}\n </div>\n ) : (\n thumbnail\n )}\n\n <CardBody\n variant=\"dark\"\n title={title}\n placeholderTitle={placeholderTitle}\n mimeType={mimeType}\n detail={detail}\n statusBadge={statusBadge}\n icon={\n isGallery ? (\n <ImagesIcon className=\"size-5 shrink-0 text-white/55\" />\n ) : undefined\n }\n trailingAction={editButton}\n />\n </LockedCardShell>\n )\n}\n\nexport default ComposerCard\n"],"names":["ComposerCard","title","mimeType","thumbnailUrl","detail","amountText","placeholderTitle","placeholderAmountText","gallery","onDismiss","onPreviewClick","onFetchSource","onEditClick","source","setSource","useState","isPreviewVisible","setIsPreviewVisible","isLoadingPreview","setIsLoadingPreview","fetchingRef","useRef","isGallery","handleToggle","useCallback","result","togglePreview","showLocked","isBusy","statusBadge","jsxs","React","jsx","dismissButton","XIcon","editButton","PencilSimpleIcon","thumbnail","GalleryThumbnail","LockedThumbnail","LockedCardShell","CardBody","ImagesIcon"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Card-DlMSDSdm.js","sources":["../src/components/LockedAttachment/components/Composer/Card.tsx"],"sourcesContent":["import { ImagesIcon, PencilSimpleIcon, XIcon } from '@phosphor-icons/react'\nimport React, { useCallback, useRef, useState } from 'react'\n\nimport type {\n LockedAttachmentBaseProps,\n LockedAttachmentSource,\n} from '../../types'\nimport CardBody from '../_shared/CardBody'\nimport GalleryThumbnail from '../_shared/GalleryThumbnail'\nimport LockedCardShell from '../_shared/LockedCardShell'\nimport LockedThumbnail from '../_shared/LockedThumbnail'\n\nexport interface ComposerCardProps extends LockedAttachmentBaseProps {\n /** Placeholder shown in the title slot before the composer types one. */\n placeholderTitle?: string\n /** Placeholder shown in the amount slot before one is configured. */\n placeholderAmountText?: string\n /**\n * When provided, renders a dismiss X in the thumbnail corner. Called when\n * the composer clicks it to remove the attachment.\n */\n onDismiss?: () => void\n /** Fired the first time the composer taps the thumbnail to preview. */\n onPreviewClick?: () => void\n /**\n * Lazily loads the underlying source so the composer can preview the\n * attachment they're about to send. Called the first time the thumbnail is\n * tapped; the returned source is cached and reused on subsequent toggles.\n */\n onFetchSource?: () => Promise<LockedAttachmentSource | void>\n /**\n * When provided, renders a pencil button in the body bottom-right that the\n * composer can use to edit the attachment metadata (e.g. open the price /\n * gallery editor). Matches the Composer \"Button\" instance in Figma.\n */\n onEditClick?: () => void\n}\n\n/**\n * The card the composer sees while drafting a paid attachment.\n * Matches the Composer column of the messaging design system in Figma.\n */\nconst ComposerCard: React.FC<ComposerCardProps> = ({\n title,\n mimeType = 'application/octet-stream',\n thumbnailUrl,\n detail,\n amountText,\n placeholderTitle = 'Attachment title',\n placeholderAmountText,\n gallery,\n onDismiss,\n onPreviewClick,\n onFetchSource,\n onEditClick,\n}) => {\n const [source, setSource] = useState<LockedAttachmentSource | undefined>()\n const [isPreviewVisible, setIsPreviewVisible] = useState(false)\n const [isLoadingPreview, setIsLoadingPreview] = useState(false)\n const fetchingRef = useRef(false)\n\n const isGallery = (gallery?.length ?? 0) >= 2\n\n const handleToggle = useCallback(async () => {\n onPreviewClick?.()\n if (isPreviewVisible) {\n setIsPreviewVisible(false)\n return\n }\n // Gallery items carry their own per-item sources on the `gallery` prop, so\n // we just flip visibility — no async source fetch is needed.\n if (isGallery) {\n setIsPreviewVisible(true)\n return\n }\n if (source) {\n setIsPreviewVisible(true)\n return\n }\n if (!onFetchSource) return\n if (fetchingRef.current) return\n fetchingRef.current = true\n setIsLoadingPreview(true)\n try {\n const result = await onFetchSource()\n if (result) {\n setSource(result)\n setIsPreviewVisible(true)\n }\n } finally {\n fetchingRef.current = false\n setIsLoadingPreview(false)\n }\n }, [isPreviewVisible, isGallery, source, onPreviewClick, onFetchSource])\n\n // Gallery is always previewable in the composer because each item's source\n // is already provided up-front via `gallery[*].sourceUrl`.\n const togglePreview =\n isGallery || onFetchSource || onPreviewClick ? handleToggle : undefined\n const showLocked = !isPreviewVisible\n const isBusy = isLoadingPreview\n\n const statusBadge = (\n <React.Fragment>\n <span className=\"text-xs font-medium text-white/55\">•</span>\n <span\n className={\n amountText\n ? 'text-xs font-medium text-white/55'\n : 'text-xs font-medium text-white/30'\n }\n >\n {amountText || placeholderAmountText}\n </span>\n </React.Fragment>\n )\n\n const dismissButton = onDismiss ? (\n <button\n type=\"button\"\n onClick={(e) => {\n // Stop the click from bubbling up into the outer preview-toggle\n // wrapper when both are wired up at the same time.\n e.stopPropagation()\n onDismiss()\n }}\n className=\"flex size-6 items-center justify-center rounded-full bg-[#121110] text-white\"\n aria-label=\"Dismiss attachment\"\n >\n <XIcon className=\"size-3\" weight=\"bold\" />\n </button>\n ) : undefined\n\n const editButton = onEditClick ? (\n <button\n type=\"button\"\n onClick={onEditClick}\n aria-label=\"Edit attachment\"\n className=\"flex size-10 items-center justify-center rounded-full bg-white/10 text-white hover:bg-white/15\"\n >\n <PencilSimpleIcon className=\"size-5\" weight=\"regular\" />\n </button>\n ) : undefined\n\n const thumbnail = isGallery ? (\n <GalleryThumbnail\n variant=\"dark\"\n gallery={gallery!}\n title={title}\n showLocked={showLocked}\n topRight={dismissButton}\n />\n ) : (\n <LockedThumbnail\n variant=\"dark\"\n mimeType={mimeType}\n thumbnailUrl={thumbnailUrl}\n title={title}\n source={source}\n showLocked={showLocked}\n topRight={dismissButton}\n />\n )\n\n return (\n <LockedCardShell variant=\"dark\">\n {togglePreview ? (\n // Uses a `<div role=\"button\">` rather than a native `<button>` so the\n // dismiss control rendered inside `thumbnail` (also a `<button>`)\n // doesn't produce invalid nested interactive elements.\n <div\n role=\"button\"\n tabIndex={isBusy ? -1 : 0}\n aria-label=\"Toggle preview\"\n aria-busy={isBusy}\n aria-pressed={!showLocked}\n aria-disabled={isBusy || undefined}\n onClick={isBusy ? undefined : togglePreview}\n onKeyDown={(e) => {\n if (isBusy) return\n // Only handle keys that originate on the wrapper itself, not on\n // inner interactive elements (dismiss X, carousel arrows). Without\n // this guard, pressing Enter/Space on a focused child would bubble\n // up and toggle the preview in addition to activating the child.\n if (e.target !== e.currentTarget) return\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n void togglePreview()\n }\n }}\n className={\n !isBusy\n ? 'block w-full cursor-pointer text-left'\n : 'block w-full text-left'\n }\n >\n {thumbnail}\n </div>\n ) : (\n thumbnail\n )}\n\n <CardBody\n variant=\"dark\"\n title={title}\n placeholderTitle={placeholderTitle}\n mimeType={mimeType}\n detail={detail}\n statusBadge={statusBadge}\n icon={\n isGallery ? (\n <ImagesIcon className=\"size-5 shrink-0 text-white/55\" />\n ) : undefined\n }\n trailingAction={editButton}\n />\n </LockedCardShell>\n )\n}\n\nexport default ComposerCard\n"],"names":["ComposerCard","title","mimeType","thumbnailUrl","detail","amountText","placeholderTitle","placeholderAmountText","gallery","onDismiss","onPreviewClick","onFetchSource","onEditClick","source","setSource","useState","isPreviewVisible","setIsPreviewVisible","isLoadingPreview","setIsLoadingPreview","fetchingRef","useRef","isGallery","handleToggle","useCallback","result","togglePreview","showLocked","isBusy","statusBadge","jsxs","React","jsx","dismissButton","XIcon","editButton","PencilSimpleIcon","thumbnail","GalleryThumbnail","LockedThumbnail","LockedCardShell","CardBody","ImagesIcon"],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { jsxs as p, jsx as t } from "react/jsx-runtime";
|
|
2
|
+
import { c, n as x, i as A, A as k, C as B, a as O, b as P } from "./CardThumbnail-DTBuRQHF.js";
|
|
3
|
+
const w = ({
|
|
4
|
+
title: i,
|
|
5
|
+
description: h,
|
|
6
|
+
url: s,
|
|
7
|
+
mimeType: l,
|
|
8
|
+
thumbnailUrl: C,
|
|
9
|
+
sourceUrl: n,
|
|
10
|
+
layout: f = "featured",
|
|
11
|
+
appIcon: v,
|
|
12
|
+
cta: a,
|
|
13
|
+
onClick: e
|
|
14
|
+
}) => {
|
|
15
|
+
const r = c(l, n), d = x(s), u = a == null && d != null && !r ? d : void 0, b = a == null && !r ? e : void 0, g = A(l, n) ? k : void 0, m = a && e ? {
|
|
16
|
+
...a,
|
|
17
|
+
onClick: () => {
|
|
18
|
+
var o;
|
|
19
|
+
e(), (o = a.onClick) == null || o.call(a);
|
|
20
|
+
}
|
|
21
|
+
} : a;
|
|
22
|
+
return /* @__PURE__ */ p(
|
|
23
|
+
B,
|
|
24
|
+
{
|
|
25
|
+
variant: "light",
|
|
26
|
+
href: u,
|
|
27
|
+
onClick: b,
|
|
28
|
+
ariaLabel: i ?? "Open attachment preview",
|
|
29
|
+
bgClassName: g,
|
|
30
|
+
"data-testid": "link-attachment",
|
|
31
|
+
children: [
|
|
32
|
+
f === "featured" && /* @__PURE__ */ t(
|
|
33
|
+
O,
|
|
34
|
+
{
|
|
35
|
+
variant: "light",
|
|
36
|
+
thumbnailUrl: C,
|
|
37
|
+
sourceUrl: n,
|
|
38
|
+
title: i,
|
|
39
|
+
mimeType: l
|
|
40
|
+
}
|
|
41
|
+
),
|
|
42
|
+
/* @__PURE__ */ t(
|
|
43
|
+
P,
|
|
44
|
+
{
|
|
45
|
+
variant: "light",
|
|
46
|
+
title: i,
|
|
47
|
+
description: h,
|
|
48
|
+
url: s,
|
|
49
|
+
appIcon: v,
|
|
50
|
+
cta: m
|
|
51
|
+
}
|
|
52
|
+
)
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
);
|
|
56
|
+
};
|
|
57
|
+
export {
|
|
58
|
+
w as default
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=Card-DlSSJPip.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Card-DlSSJPip.js","sources":["../src/components/LinkAttachment/components/Received/Card.tsx"],"sourcesContent":["import React from 'react'\n\nimport type { LinkAttachmentBaseProps } from '../../types'\nimport CardBody from '../_shared/CardBody'\nimport CardShell from '../_shared/CardShell'\nimport CardThumbnail, {\n AUDIO_BG_CLASS,\n isPlayableAudio,\n isPlayableMedia,\n} from '../_shared/CardThumbnail'\nimport { normalizeExternalHref } from '../_shared/normalizeExternalHref'\n\nexport interface ReceivedCardProps extends LinkAttachmentBaseProps {\n /**\n * Fired when the recipient activates the card. Behavior depends on how\n * the card is configured:\n * - **Link app with a CTA** (FAQ / Form): the CTA owns navigation;\n * `onClick` fires when the recipient taps the CTA itself, alongside\n * `cta.onClick` (use for analytics).\n * - **Link app with a URL** (Spotify / TikTok / generic link): the card\n * chrome is an `<a target=\"_blank\">` opening `url` — `onClick` fires\n * alongside the navigation (use for analytics).\n * - **Image / file / placeholder attachment**: the card has no URL, so\n * it renders as a button. `onClick` is the consumer's hook for\n * opening an image / file preview (lightbox).\n * - **Video / audio attachment**: the shell stays non-interactive so\n * the native media controls remain operable — `onClick` is ignored\n * in this configuration.\n */\n onClick?: () => void\n}\n\n/**\n * The card the recipient sees in chat for a link attachment. Matches the\n * Received column of the messaging design system in Figma.\n *\n * The chrome adapts to its content:\n * - Link previews / link apps render the light card body and either\n * navigate via `url` or surface a CTA button when `cta` is set.\n * - Image / file attachments render as media-only cards — the 180px\n * thumbnail (or type-icon placeholder) fills the card with no title /\n * description body. `onClick` fires when the recipient taps the card\n * so consumers can open an image preview / lightbox.\n */\nconst ReceivedCard: React.FC<ReceivedCardProps> = ({\n title,\n description,\n url,\n mimeType,\n thumbnailUrl,\n sourceUrl,\n layout = 'featured',\n appIcon,\n cta,\n onClick,\n}) => {\n // The Received card is opened by either the CTA (FAQ / Form), the URL\n // (link previews / Spotify / TikTok), or — for media-only attachments —\n // by tapping the entire card chrome to open a preview. We hand the\n // anchor behavior off to CardShell only when there's no CTA so we don't\n // end up with nested anchors when a CTA is present.\n //\n // Video / audio attachments are an exception: wrapping the shell in\n // either a `<button>` or an `<a>` around `<video controls>` /\n // `<audio controls>` creates nested interactive elements, and clicks on\n // the native media controls can bubble up to fire the outer card\n // action (preview / link navigation). For those, we render a plain\n // non-interactive shell and let the media element own clicks — both\n // `shellHref` and `shellOnClick` are suppressed even when `url` is set.\n const isPlayingMedia = isPlayableMedia(mimeType, sourceUrl)\n // Normalize the URL so a bare hostname like `tr.ee/briemix` (used in\n // our own docs / stories) is treated as an external link instead of a\n // relative path. Returns `undefined` for empty / whitespace-only\n // values, so those fall through to the media-preview path instead of\n // producing an empty `href` on the shell anchor.\n const normalizedUrl = normalizeExternalHref(url)\n const shellHref =\n cta == null && normalizedUrl != null && !isPlayingMedia\n ? normalizedUrl\n : undefined\n const shellOnClick =\n cta == null && !isPlayingMedia ? onClick : undefined\n const audioBg = isPlayableAudio(mimeType, sourceUrl)\n ? AUDIO_BG_CLASS\n : undefined\n\n // When a CTA is set the shell isn't interactive — the CTA owns the\n // click target. Forward the card-level `onClick` to the CTA so\n // analytics / side-effect consumers still fire on activation while\n // preserving the CTA's own `onClick` callback.\n const wrappedCta =\n cta && onClick\n ? {\n ...cta,\n onClick: () => {\n onClick()\n cta.onClick?.()\n },\n }\n : cta\n\n return (\n <CardShell\n variant=\"light\"\n href={shellHref}\n onClick={shellOnClick}\n ariaLabel={title ?? 'Open attachment preview'}\n bgClassName={audioBg}\n data-testid=\"link-attachment\"\n >\n {layout === 'featured' && (\n <CardThumbnail\n variant=\"light\"\n thumbnailUrl={thumbnailUrl}\n sourceUrl={sourceUrl}\n title={title}\n mimeType={mimeType}\n />\n )}\n <CardBody\n variant=\"light\"\n title={title}\n description={description}\n url={url}\n appIcon={appIcon}\n cta={wrappedCta}\n />\n </CardShell>\n )\n}\n\nexport default ReceivedCard\n"],"names":["ReceivedCard","title","description","url","mimeType","thumbnailUrl","sourceUrl","layout","appIcon","cta","onClick","isPlayingMedia","isPlayableMedia","normalizedUrl","normalizeExternalHref","shellHref","shellOnClick","audioBg","isPlayableAudio","AUDIO_BG_CLASS","wrappedCta","_a","jsxs","CardShell","jsx","CardThumbnail","CardBody"],"mappings":";;AA4CA,MAAMA,IAA4C,CAAC;AAAA,EACjD,OAAAC;AAAA,EACA,aAAAC;AAAA,EACA,KAAAC;AAAA,EACA,UAAAC;AAAA,EACA,cAAAC;AAAA,EACA,WAAAC;AAAA,EACA,QAAAC,IAAS;AAAA,EACT,SAAAC;AAAA,EACA,KAAAC;AAAA,EACA,SAAAC;AACF,MAAM;AAcJ,QAAMC,IAAiBC,EAAgBR,GAAUE,CAAS,GAMpDO,IAAgBC,EAAsBX,CAAG,GACzCY,IACJN,KAAO,QAAQI,KAAiB,QAAQ,CAACF,IACrCE,IACA,QACAG,IACJP,KAAO,QAAQ,CAACE,IAAiBD,IAAU,QACvCO,IAAUC,EAAgBd,GAAUE,CAAS,IAC/Ca,IACA,QAMEC,IACJX,KAAOC,IACH;AAAA,IACE,GAAGD;AAAA,IACH,SAAS,MAAM;;AACb,MAAAC,EAAA,IACAW,IAAAZ,EAAI,YAAJ,QAAAY,EAAA,KAAAZ;AAAA,IACF;AAAA,EAAA,IAEFA;AAEN,SACE,gBAAAa;AAAA,IAACC;AAAA,IAAA;AAAA,MACC,SAAQ;AAAA,MACR,MAAMR;AAAA,MACN,SAASC;AAAA,MACT,WAAWf,KAAS;AAAA,MACpB,aAAagB;AAAA,MACb,eAAY;AAAA,MAEX,UAAA;AAAA,QAAAV,MAAW,cACV,gBAAAiB;AAAA,UAACC;AAAA,UAAA;AAAA,YACC,SAAQ;AAAA,YACR,cAAApB;AAAA,YACA,WAAAC;AAAA,YACA,OAAAL;AAAA,YACA,UAAAG;AAAA,UAAA;AAAA,QAAA;AAAA,QAGJ,gBAAAoB;AAAA,UAACE;AAAA,UAAA;AAAA,YACC,SAAQ;AAAA,YACR,OAAAzB;AAAA,YACA,aAAAC;AAAA,YACA,KAAAC;AAAA,YACA,SAAAK;AAAA,YACA,KAAKY;AAAA,UAAA;AAAA,QAAA;AAAA,MACP;AAAA,IAAA;AAAA,EAAA;AAGN;"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { jsxs as f, jsx as s } from "react/jsx-runtime";
|
|
2
|
+
import { C as b, A as m, a as u, b as v, i as A } from "./CardThumbnail-DTBuRQHF.js";
|
|
3
|
+
const k = ({
|
|
4
|
+
title: a,
|
|
5
|
+
placeholderTitle: i,
|
|
6
|
+
description: t,
|
|
7
|
+
url: o,
|
|
8
|
+
mimeType: r,
|
|
9
|
+
thumbnailUrl: e,
|
|
10
|
+
sourceUrl: d,
|
|
11
|
+
layout: n = "featured",
|
|
12
|
+
appIcon: C,
|
|
13
|
+
cta: l
|
|
14
|
+
}) => /* @__PURE__ */ f(
|
|
15
|
+
b,
|
|
16
|
+
{
|
|
17
|
+
variant: "dark",
|
|
18
|
+
bgClassName: A(r, d) ? m : void 0,
|
|
19
|
+
children: [
|
|
20
|
+
n === "featured" && /* @__PURE__ */ s(
|
|
21
|
+
u,
|
|
22
|
+
{
|
|
23
|
+
variant: "dark",
|
|
24
|
+
thumbnailUrl: e,
|
|
25
|
+
sourceUrl: d,
|
|
26
|
+
title: a,
|
|
27
|
+
mimeType: r
|
|
28
|
+
}
|
|
29
|
+
),
|
|
30
|
+
/* @__PURE__ */ s(
|
|
31
|
+
v,
|
|
32
|
+
{
|
|
33
|
+
variant: "dark",
|
|
34
|
+
title: a,
|
|
35
|
+
placeholderTitle: i,
|
|
36
|
+
description: t,
|
|
37
|
+
url: o,
|
|
38
|
+
appIcon: C,
|
|
39
|
+
cta: l
|
|
40
|
+
}
|
|
41
|
+
)
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
);
|
|
45
|
+
export {
|
|
46
|
+
k as default
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=Card-zGbhRBwv.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Card-zGbhRBwv.js","sources":["../src/components/LinkAttachment/components/Sent/Card.tsx"],"sourcesContent":["import React from 'react'\n\nimport type { LinkAttachmentBaseProps } from '../../types'\nimport CardBody from '../_shared/CardBody'\nimport CardShell from '../_shared/CardShell'\nimport CardThumbnail, {\n AUDIO_BG_CLASS,\n isPlayableAudio,\n} from '../_shared/CardThumbnail'\n\nexport interface SentCardProps extends LinkAttachmentBaseProps {}\n\n/**\n * The card the sender sees in chat after a link attachment has been posted.\n * Matches the Sent column of the messaging design system in Figma — same\n * dark chrome as the Composer card minus the dismiss / edit affordances.\n */\nconst SentCard: React.FC<SentCardProps> = ({\n title,\n placeholderTitle,\n description,\n url,\n mimeType,\n thumbnailUrl,\n sourceUrl,\n layout = 'featured',\n appIcon,\n cta,\n}) => (\n <CardShell\n variant=\"dark\"\n bgClassName={\n isPlayableAudio(mimeType, sourceUrl) ? AUDIO_BG_CLASS : undefined\n }\n >\n {layout === 'featured' && (\n <CardThumbnail\n variant=\"dark\"\n thumbnailUrl={thumbnailUrl}\n sourceUrl={sourceUrl}\n title={title}\n mimeType={mimeType}\n />\n )}\n <CardBody\n variant=\"dark\"\n title={title}\n placeholderTitle={placeholderTitle}\n description={description}\n url={url}\n appIcon={appIcon}\n cta={cta}\n />\n </CardShell>\n)\n\nexport default SentCard\n"],"names":["SentCard","title","placeholderTitle","description","url","mimeType","thumbnailUrl","sourceUrl","layout","appIcon","cta","jsxs","CardShell","isPlayableAudio","AUDIO_BG_CLASS","jsx","CardThumbnail","CardBody"],"mappings":";;AAiBA,MAAMA,IAAoC,CAAC;AAAA,EACzC,OAAAC;AAAA,EACA,kBAAAC;AAAA,EACA,aAAAC;AAAA,EACA,KAAAC;AAAA,EACA,UAAAC;AAAA,EACA,cAAAC;AAAA,EACA,WAAAC;AAAA,EACA,QAAAC,IAAS;AAAA,EACT,SAAAC;AAAA,EACA,KAAAC;AACF,MACE,gBAAAC;AAAA,EAACC;AAAA,EAAA;AAAA,IACC,SAAQ;AAAA,IACR,aACEC,EAAgBR,GAAUE,CAAS,IAAIO,IAAiB;AAAA,IAGzD,UAAA;AAAA,MAAAN,MAAW,cACV,gBAAAO;AAAA,QAACC;AAAA,QAAA;AAAA,UACC,SAAQ;AAAA,UACR,cAAAV;AAAA,UACA,WAAAC;AAAA,UACA,OAAAN;AAAA,UACA,UAAAI;AAAA,QAAA;AAAA,MAAA;AAAA,MAGJ,gBAAAU;AAAA,QAACE;AAAA,QAAA;AAAA,UACC,SAAQ;AAAA,UACR,OAAAhB;AAAA,UACA,kBAAAC;AAAA,UACA,aAAAC;AAAA,UACA,KAAAC;AAAA,UACA,SAAAK;AAAA,UACA,KAAAC;AAAA,QAAA;AAAA,MAAA;AAAA,IACF;AAAA,EAAA;AACF;"}
|