@linktr.ee/messaging-react 3.9.0-rc-1783406511 → 3.9.0-rc-1783407048
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-CmRzkuPw.cjs → Card-D8yiJ8Uw.cjs} +2 -2
- package/dist/{Card-CmRzkuPw.cjs.map → Card-D8yiJ8Uw.cjs.map} +1 -1
- package/dist/{Card-DVEuTlf_.cjs → Card-DVfSiq9b.cjs} +2 -2
- package/dist/{Card-DVEuTlf_.cjs.map → Card-DVfSiq9b.cjs.map} +1 -1
- package/dist/{Card-BG-Mg_ss.js → Card-DX9nBx1S.js} +3 -3
- package/dist/{Card-BG-Mg_ss.js.map → Card-DX9nBx1S.js.map} +1 -1
- package/dist/{Card-K9ky-G-t.js → Card-qDLtjK6u.js} +2 -2
- package/dist/{Card-K9ky-G-t.js.map → Card-qDLtjK6u.js.map} +1 -1
- package/dist/{index-DO_dYsIf.js → index-CZTUyiPe.js} +4 -4
- package/dist/index-CZTUyiPe.js.map +1 -0
- package/dist/{index-DpzmKL5U.cjs → index-DwUOvMxg.cjs} +2 -2
- package/dist/index-DwUOvMxg.cjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/{usePreviewToggle-D27Xw9Xx.js → usePreviewToggle-BG-pfsgP.js} +2 -2
- package/dist/{usePreviewToggle-D27Xw9Xx.js.map → usePreviewToggle-BG-pfsgP.js.map} +1 -1
- package/dist/{usePreviewToggle-B5kmPELX.cjs → usePreviewToggle-DXQT07ws.cjs} +2 -2
- package/dist/{usePreviewToggle-B5kmPELX.cjs.map → usePreviewToggle-DXQT07ws.cjs.map} +1 -1
- package/package.json +2 -2
- package/src/components/CustomMessage/CustomMessage.stories.tsx +4 -4
- package/src/components/CustomMessage/MessageTag.tsx +2 -2
- package/src/stream-custom-data.ts +1 -1
- package/dist/index-DO_dYsIf.js.map +0 -1
- package/dist/index-DpzmKL5U.cjs.map +0 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),a=require("@phosphor-icons/react"),T=require("react"),s=require("./usePreviewToggle-
|
|
2
|
-
//# sourceMappingURL=Card-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),a=require("@phosphor-icons/react"),T=require("react"),s=require("./usePreviewToggle-DXQT07ws.cjs"),u=require("./TextShell-Bnzh0T75.cjs"),z=({text:t,amountText:i,placeholderAmountText:n,onDismiss:r})=>e.jsxs(u.TextShell,{children:[e.jsx("div",{className:"pr-8",children:t}),e.jsx(u.PriceLockRow,{children:e.jsx("span",{className:i?"text-white/55":"text-white/30",children:i||n})}),r&&e.jsx("button",{type:"button",onClick:r,className:"absolute right-3 top-3 flex size-6 shrink-0 items-center justify-center rounded-full bg-white/10 text-white hover:bg-white/15","aria-label":"Dismiss attachment",children:e.jsx(a.XIcon,{className:"size-3",weight:"bold"})})]}),B=({title:t,mimeType:i="application/octet-stream",thumbnailUrl:n,detail:r,amountText:o,placeholderTitle:m="Attachment title",placeholderAmountText:g,gallery:l=[],onDismiss:c,onPreviewClick:j,onFetchSource:w,onEditClick:d})=>{const h=s.isGalleryCard(l),{source:b,isPreviewVisible:v,isLoadingPreview:f,togglePreview:p}=s.usePreviewToggle({isGallery:h,onFetchSource:w,onPreviewClick:j}),x=!v,y=f,C=e.jsxs(T.Fragment,{children:[e.jsx("span",{className:"text-xs font-medium text-white/55",children:"•"}),e.jsx("span",{className:o?"text-xs font-medium text-white/55":"text-xs font-medium text-white/30",children:o||g})]}),P=c?e.jsx("button",{type:"button",onClick:k=>{k.stopPropagation(),c()},className:"flex size-6 items-center justify-center rounded-full bg-[#121110] text-white","aria-label":"Dismiss attachment",children:e.jsx(a.XIcon,{className:"size-3",weight:"bold"})}):void 0,N=d?e.jsx("button",{type:"button",onClick:d,"aria-label":"Edit attachment",className:"flex size-10 items-center justify-center rounded-full bg-white/10 text-white hover:bg-white/15",children:e.jsx(a.PencilSimpleIcon,{className:"size-5",weight:"regular"})}):void 0;return e.jsxs(s.MediaShell,{variant:"dark",children:[e.jsx(s.PreviewToggle,{onToggle:p,isBusy:y,isPreviewVisible:!x,children:e.jsx(s.CardThumbnail,{variant:"dark",gallery:l,title:t,showLocked:x,mimeType:i,thumbnailUrl:n,source:b,topRight:P})}),e.jsx(s.CardBody,{variant:"dark",title:t,placeholderTitle:m,mimeType:i,detail:r,statusBadge:C,icon:h?s.galleryBodyIcon("dark"):void 0,trailingAction:N})]})},S=t=>t.contentType==="text"?e.jsx(z,{...t}):e.jsx(B,{...t});exports.default=S;
|
|
2
|
+
//# sourceMappingURL=Card-D8yiJ8Uw.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Card-
|
|
1
|
+
{"version":3,"file":"Card-D8yiJ8Uw.cjs","sources":["../src/components/LockedAttachment/components/Composer/Card.tsx"],"sourcesContent":["import { PencilSimpleIcon, XIcon } from '@phosphor-icons/react'\nimport React from 'react'\n\nimport type { FetchSourceHandler, LockedAttachmentBaseProps } from '../../types'\nimport CardBody from '../_shared/CardBody'\nimport CardThumbnail, {\n galleryBodyIcon,\n isGalleryCard,\n} from '../_shared/CardThumbnail'\nimport MediaShell from '../_shared/MediaShell'\nimport PreviewToggle from '../_shared/PreviewToggle'\nimport PriceLockRow from '../_shared/PriceLockRow'\nimport TextShell from '../_shared/TextShell'\nimport { usePreviewToggle } from '../_shared/usePreviewToggle'\n\nexport interface ComposerCardProps extends LockedAttachmentBaseProps {\n /**\n * The message's own text, shown as-is (not redacted yet — the message\n * hasn't been sent). Only used when `contentType` is `\"text\"`.\n */\n text?: string\n /** Placeholder shown in the amount slot before one is configured. */\n placeholderAmountText?: string\n /**\n * Renders a persistent dismiss X on the thumbnail (media) or next to the\n * text (text mode); called to remove the draft attachment. Unrelated to\n * `TextCardProps.onDismiss`, which only appears for `isMine` after a\n * failed payment.\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 * Ignored when `contentType` is `\"text\"`.\n */\n onFetchSource?: FetchSourceHandler\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 * Composer card in text mode: a normal outgoing chat bubble showing the real\n * draft text (it hasn't been sent/redacted yet) plus a dismiss X and a price\n * row. Media-only props are ignored here.\n */\nconst ComposerTextCard: React.FC<ComposerCardProps> = ({\n text,\n amountText,\n placeholderAmountText,\n onDismiss,\n}) => (\n <TextShell>\n <div className=\"pr-8\">{text}</div>\n <PriceLockRow>\n <span className={amountText ? 'text-white/55' : 'text-white/30'}>\n {amountText || placeholderAmountText}\n </span>\n </PriceLockRow>\n {onDismiss && (\n <button\n type=\"button\"\n onClick={onDismiss}\n className=\"absolute right-3 top-3 flex size-6 shrink-0 items-center justify-center rounded-full bg-white/10 text-white hover:bg-white/15\"\n aria-label=\"Dismiss attachment\"\n >\n <XIcon className=\"size-3\" weight=\"bold\" />\n </button>\n )}\n </TextShell>\n)\n\n/**\n * Composer card in media mode: the locked thumbnail (single or gallery) the\n * composer taps to preview the attachment they're about to send, plus the\n * title/price body with optional dismiss X and edit pencil.\n */\nconst ComposerMediaCard: 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 isGallery = isGalleryCard(gallery)\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 { source, isPreviewVisible, isLoadingPreview, togglePreview } =\n usePreviewToggle({ isGallery, onFetchSource, onPreviewClick })\n\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 return (\n <MediaShell variant=\"dark\">\n <PreviewToggle\n onToggle={togglePreview}\n isBusy={isBusy}\n isPreviewVisible={!showLocked}\n >\n <CardThumbnail\n variant=\"dark\"\n gallery={gallery}\n title={title}\n showLocked={showLocked}\n mimeType={mimeType}\n thumbnailUrl={thumbnailUrl}\n source={source}\n topRight={dismissButton}\n />\n </PreviewToggle>\n\n <CardBody\n variant=\"dark\"\n title={title}\n placeholderTitle={placeholderTitle}\n mimeType={mimeType}\n detail={detail}\n statusBadge={statusBadge}\n icon={isGallery ? galleryBodyIcon('dark') : undefined}\n trailingAction={editButton}\n />\n </MediaShell>\n )\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 *\n * When `contentType === \"text\"`, renders as a normal outgoing chat bubble\n * showing the real draft text (it hasn't been sent/redacted yet) plus a\n * dismiss X and a price row, instead of a media thumbnail card.\n */\nconst ComposerCard: React.FC<ComposerCardProps> = (props) =>\n props.contentType === 'text' ? (\n <ComposerTextCard {...props} />\n ) : (\n <ComposerMediaCard {...props} />\n )\n\nexport default ComposerCard\n"],"names":["ComposerTextCard","text","amountText","placeholderAmountText","onDismiss","TextShell","jsx","PriceLockRow","XIcon","ComposerMediaCard","title","mimeType","thumbnailUrl","detail","placeholderTitle","gallery","onPreviewClick","onFetchSource","onEditClick","isGallery","isGalleryCard","source","isPreviewVisible","isLoadingPreview","togglePreview","usePreviewToggle","showLocked","isBusy","statusBadge","jsxs","React","dismissButton","e","editButton","PencilSimpleIcon","MediaShell","PreviewToggle","CardThumbnail","CardBody","galleryBodyIcon","ComposerCard","props"],"mappings":"8PAoDMA,EAAgD,CAAC,CACrD,KAAAC,EACA,WAAAC,EACA,sBAAAC,EACA,UAAAC,CACF,WACGC,YAAA,CACC,SAAA,CAAAC,EAAAA,IAAC,MAAA,CAAI,UAAU,OAAQ,SAAAL,EAAK,EAC5BK,EAAAA,IAACC,EAAAA,aAAA,CACC,SAAAD,EAAAA,IAAC,OAAA,CAAK,UAAWJ,EAAa,gBAAkB,gBAC7C,SAAAA,GAAcC,CAAA,CACjB,CAAA,CACF,EACCC,GACCE,EAAAA,IAAC,SAAA,CACC,KAAK,SACL,QAASF,EACT,UAAU,gIACV,aAAW,qBAEX,SAAAE,EAAAA,IAACE,QAAA,CAAM,UAAU,SAAS,OAAO,MAAA,CAAO,CAAA,CAAA,CAC1C,EAEJ,EAQIC,EAAiD,CAAC,CACtD,MAAAC,EACA,SAAAC,EAAW,2BACX,aAAAC,EACA,OAAAC,EACA,WAAAX,EACA,iBAAAY,EAAmB,mBACnB,sBAAAX,EACA,QAAAY,EAAU,CAAA,EACV,UAAAX,EACA,eAAAY,EACA,cAAAC,EACA,YAAAC,CACF,IAAM,CACJ,MAAMC,EAAYC,EAAAA,cAAcL,CAAO,EAIjC,CAAE,OAAAM,EAAQ,iBAAAC,EAAkB,iBAAAC,EAAkB,cAAAC,CAAA,EAClDC,EAAAA,iBAAiB,CAAE,UAAAN,EAAW,cAAAF,EAAe,eAAAD,EAAgB,EAEzDU,EAAa,CAACJ,EACdK,EAASJ,EAETK,EACJC,EAAAA,KAACC,EAAM,SAAN,CACC,SAAA,CAAAxB,EAAAA,IAAC,OAAA,CAAK,UAAU,oCAAoC,SAAA,IAAM,EAC1DA,EAAAA,IAAC,OAAA,CACC,UACEJ,EACI,oCACA,oCAGL,SAAAA,GAAcC,CAAA,CAAA,CACjB,EACF,EAGI4B,EAAgB3B,EACpBE,EAAAA,IAAC,SAAA,CACC,KAAK,SACL,QAAU0B,GAAM,CAGdA,EAAE,gBAAA,EACF5B,EAAA,CACF,EACA,UAAU,+EACV,aAAW,qBAEX,SAAAE,EAAAA,IAACE,QAAA,CAAM,UAAU,SAAS,OAAO,MAAA,CAAO,CAAA,CAAA,EAExC,OAEEyB,EAAaf,EACjBZ,EAAAA,IAAC,SAAA,CACC,KAAK,SACL,QAASY,EACT,aAAW,kBACX,UAAU,iGAEV,SAAAZ,EAAAA,IAAC4B,mBAAA,CAAiB,UAAU,SAAS,OAAO,SAAA,CAAU,CAAA,CAAA,EAEtD,OAEJ,OACEL,EAAAA,KAACM,EAAAA,WAAA,CAAW,QAAQ,OAClB,SAAA,CAAA7B,EAAAA,IAAC8B,EAAAA,cAAA,CACC,SAAUZ,EACV,OAAAG,EACA,iBAAkB,CAACD,EAEnB,SAAApB,EAAAA,IAAC+B,EAAAA,cAAA,CACC,QAAQ,OACR,QAAAtB,EACA,MAAAL,EACA,WAAAgB,EACA,SAAAf,EACA,aAAAC,EACA,OAAAS,EACA,SAAUU,CAAA,CAAA,CACZ,CAAA,EAGFzB,EAAAA,IAACgC,EAAAA,SAAA,CACC,QAAQ,OACR,MAAA5B,EACA,iBAAAI,EACA,SAAAH,EACA,OAAAE,EACA,YAAAe,EACA,KAAMT,EAAYoB,kBAAgB,MAAM,EAAI,OAC5C,eAAgBN,CAAA,CAAA,CAClB,EACF,CAEJ,EAUMO,EAA6CC,GACjDA,EAAM,cAAgB,OACpBnC,EAAAA,IAACN,EAAA,CAAkB,GAAGyC,CAAA,CAAO,EAE7BnC,EAAAA,IAACG,EAAA,CAAmB,GAAGgC,CAAA,CAAO"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime");require("classnames");const C=require("@phosphor-icons/react"),v=require("react"),M=require("./index-
|
|
2
|
-
//# sourceMappingURL=Card-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime");require("classnames");const C=require("@phosphor-icons/react"),v=require("react"),M=require("./index-DwUOvMxg.cjs"),s=require("./usePreviewToggle-DXQT07ws.cjs"),y=require("./PurchaseStatusBadge-UjDzZhLj.cjs");function p({paymentStatus:r,onFetchSource:l,onUnlockClick:o}){const[t,d]=v.useState(),i=v.useRef(null),n=v.useRef(!1),u=v.useRef(l);u.current=l;const h=v.useCallback(async()=>{var a;if(!n.current){n.current=!0;try{const c=await((a=u.current)==null?void 0:a.call(u));c&&d(c)}finally{n.current=!1}}},[]),g=v.useCallback(()=>{r==="paid"?h():o==null||o()},[r,h,o]);return v.useEffect(()=>{if(!i.current||r!=="paid"||t!==void 0)return;const a=new IntersectionObserver(([c])=>{c.isIntersecting&&(h(),a.disconnect())},{threshold:1});return a.observe(i.current),()=>a.disconnect()},[r,t,h]),{source:t,cardRef:i,handleUnlockClick:g}}const P="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",I=({isLocked:r,sourceUrl:l,redeemUrl:o,onUnlockClicked:t,onDownloadClicked:d,isUnlocking:i=!1})=>{if(r&&t!=null)return e.jsx("button",{type:"button",onClick:t,disabled:i,className:P,children:i?e.jsx("span",{className:"size-4 animate-spin rounded-full border-2 border-white/30 border-t-white"}):e.jsxs(v.Fragment,{children:[e.jsx(C.LockSimpleIcon,{className:"size-4",weight:"fill"}),"Unlock"]})});if(!r&&d!=null){const n=o??l;return n!=null?e.jsxs("a",{href:n,target:"_blank",rel:"noopener noreferrer",onClick:d,className:`${P} !text-white`,children:[e.jsx(C.DownloadSimpleIcon,{className:"size-4",weight:"bold"}),"Download"]}):e.jsxs("button",{type:"button",onClick:d,className:P,children:[e.jsx(C.DownloadSimpleIcon,{className:"size-4",weight:"bold"}),"Download"]})}return null},S=({title:r,mimeType:l="application/octet-stream",thumbnailUrl:o,detail:t,amountText:d,placeholderTitle:i="Attachment title",paymentStatus:n="pending",gallery:u=[],onPreviewClick:h,onFetchSource:g})=>{const a=s.isGalleryCard(u),{source:c,isPreviewVisible:f,isLoadingPreview:b,togglePreview:j}=s.usePreviewToggle({isGallery:a,onFetchSource:g,onPreviewClick:h}),x=!f,w=b;return e.jsxs(s.MediaShell,{variant:"dark",children:[e.jsx(s.PreviewToggle,{onToggle:j,isBusy:w,isPreviewVisible:!x,children:e.jsx(s.CardThumbnail,{variant:"dark",gallery:u,title:r,showLocked:x,paymentStatus:n,mimeType:l,thumbnailUrl:o,source:c})}),e.jsx(s.CardBody,{variant:"dark",title:r,placeholderTitle:i,mimeType:l,detail:t,statusBadge:e.jsx(y.PurchaseStatusBadge,{isMine:!0,paymentStatus:n,amountText:d}),icon:a?s.galleryBodyIcon("dark"):void 0})]})},k=({title:r,amountText:l,thumbnailUrl:o,mimeType:t="application/octet-stream",detail:d,gallery:i=[],onUnlockClick:n,onFetchSource:u,onDownloadClick:h,paymentStatus:g,isUnlocking:a=!1})=>{const c=s.isGalleryCard(i),{source:f,cardRef:b,handleUnlockClick:j}=p({paymentStatus:g,onFetchSource:u,onUnlockClick:n}),x=f==null?void 0:f.sourceUrl,w=f==null?void 0:f.redeemUrl,m=c?g!=="paid":x===void 0,R=M.getSourceType(t),B=c?void 0:x;return e.jsxs(s.MediaShell,{variant:"light",rootRef:b,"data-testid":"locked-attachment",children:[e.jsx(s.CardThumbnail,{variant:"light",gallery:i,title:r,showLocked:m,paymentStatus:g,mimeType:t,thumbnailUrl:o,source:f,containedImage:!m&&(R==="image"||R==="document")}),e.jsx(s.CardBody,{variant:"light",title:r,mimeType:t,detail:d,statusBadge:e.jsx(y.PurchaseStatusBadge,{isMine:!1,paymentStatus:g,amountText:l}),icon:c?s.galleryBodyIcon("light"):void 0,action:e.jsx(I,{isLocked:m,isUnlocking:a,sourceUrl:B,redeemUrl:w,onUnlockClicked:j,onDownloadClicked:h})})]})},q=r=>r.isMine?e.jsx(S,{...r}):e.jsx(k,{...r});exports.default=q;
|
|
2
|
+
//# sourceMappingURL=Card-DVfSiq9b.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Card-DVEuTlf_.cjs","sources":["../src/components/LockedAttachment/components/_shared/useReceivedSource.ts","../src/components/LockedAttachment/components/Media/CardActions.tsx","../src/components/LockedAttachment/components/Media/Card.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react'\n\nimport type {\n FetchSourceHandler,\n LockedAttachmentSource,\n PaymentStatus,\n} from '../../types'\n\nexport interface UseReceivedSourceOptions {\n paymentStatus?: PaymentStatus\n onFetchSource?: FetchSourceHandler\n /** Called on Unlock click while the card is still unpaid (opens checkout). */\n onUnlockClick?: () => void\n}\n\nexport interface UseReceivedSourceResult {\n source: LockedAttachmentSource | undefined\n /** Attach to the card root so the paid-source auto-fetch can observe it. */\n cardRef: React.RefObject<HTMLDivElement>\n /** Fetches the source when already paid, else defers to `onUnlockClick`. */\n handleUnlockClick: () => void\n}\n\n/**\n * Media !isMine's source-reveal logic: unlike Composer/Media isMine's\n * tap-to-toggle (`usePreviewToggle`), the recipient's card reveals its source\n * by fetching once — on click when already paid, or automatically the first\n * time a paid card scrolls fully into view. The fetch is guarded so it runs\n * at most once in flight.\n */\nexport function useReceivedSource({\n paymentStatus,\n onFetchSource,\n onUnlockClick,\n}: UseReceivedSourceOptions): UseReceivedSourceResult {\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 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 return { source, cardRef, handleUnlockClick }\n}\n","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 type React from 'react'\n\nimport { getSourceType } from '../../../AttachmentCard'\nimport type {\n FetchSourceHandler,\n LockedAttachmentGalleryItem,\n PaymentStatus,\n} from '../../types'\nimport CardBody from '../_shared/CardBody'\nimport CardThumbnail, {\n galleryBodyIcon,\n isGalleryCard,\n} from '../_shared/CardThumbnail'\nimport MediaShell from '../_shared/MediaShell'\nimport PreviewToggle from '../_shared/PreviewToggle'\nimport PurchaseStatusBadge from '../_shared/PurchaseStatusBadge'\nimport { usePreviewToggle } from '../_shared/usePreviewToggle'\nimport { useReceivedSource } from '../_shared/useReceivedSource'\n\nimport ReceivedCardActions from './CardActions'\n\ninterface MediaCardSharedProps {\n title?: string\n mimeType?: string\n thumbnailUrl?: string\n detail?: string\n amountText?: string\n paymentStatus?: PaymentStatus\n gallery?: LockedAttachmentGalleryItem[]\n onFetchSource?: FetchSourceHandler\n}\n\nexport type MediaCardProps =\n | (MediaCardSharedProps & {\n isMine: true\n /** Dimmed fallback shown in the title slot when `title` is unset. */\n placeholderTitle?: string\n /** Fired the first time the sender taps the thumbnail to preview their own attachment. */\n onPreviewClick?: () => void\n })\n | (MediaCardSharedProps & {\n isMine: false\n /**\n * When true, shows a loading spinner on the Unlock button. Driven by\n * the LockedAttachmentContext (e.g. checkout in progress).\n */\n isUnlocking?: boolean\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 when the recipient clicks Download on an unlocked card.\n * Omit to hide the Download button.\n */\n onDownloadClick?: () => void\n })\n\n/**\n * The sender's ('mine') view of a paid media attachment: the locked\n * thumbnail (single or gallery) they can tap to preview their own\n * attachment, plus the title/purchase-status body.\n */\nconst OwnMediaCard: React.FC<\n MediaCardSharedProps & {\n isMine: true\n placeholderTitle?: string\n onPreviewClick?: () => void\n }\n> = ({\n title,\n mimeType = 'application/octet-stream',\n thumbnailUrl,\n detail,\n amountText,\n placeholderTitle = 'Attachment title',\n paymentStatus = 'pending',\n gallery = [],\n onPreviewClick,\n onFetchSource,\n}) => {\n const isGallery = isGalleryCard(gallery)\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 { source, isPreviewVisible, isLoadingPreview, togglePreview } =\n usePreviewToggle({ isGallery, onFetchSource, onPreviewClick })\n\n const showLocked = !isPreviewVisible\n const isBusy = isLoadingPreview\n\n return (\n <MediaShell variant=\"dark\">\n <PreviewToggle\n onToggle={togglePreview}\n isBusy={isBusy}\n isPreviewVisible={!showLocked}\n >\n <CardThumbnail\n variant=\"dark\"\n gallery={gallery}\n title={title}\n showLocked={showLocked}\n paymentStatus={paymentStatus}\n mimeType={mimeType}\n thumbnailUrl={thumbnailUrl}\n source={source}\n />\n </PreviewToggle>\n\n <CardBody\n variant=\"dark\"\n title={title}\n placeholderTitle={placeholderTitle}\n mimeType={mimeType}\n detail={detail}\n statusBadge={\n <PurchaseStatusBadge\n isMine={true}\n paymentStatus={paymentStatus}\n amountText={amountText}\n />\n }\n icon={isGallery ? galleryBodyIcon('dark') : undefined}\n />\n </MediaShell>\n )\n}\n\n/**\n * The recipient's ('other') view of a paid media attachment: the locked\n * thumbnail (single or gallery) with an Unlock/Download CTA. The source is\n * revealed by fetching once — on click when already paid, or automatically\n * the first time a paid card scrolls into view.\n */\nconst OtherMediaCard: React.FC<\n MediaCardSharedProps & {\n isMine: false\n onUnlockClick?: () => void\n onDownloadClick?: () => void\n isUnlocking?: boolean\n }\n> = ({\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 = isGalleryCard(gallery)\n\n const { source, cardRef, handleUnlockClick } = useReceivedSource({\n paymentStatus,\n onFetchSource,\n onUnlockClick,\n })\n\n const effectiveSourceUrl = source?.sourceUrl\n const effectiveRedeemUrl = source?.redeemUrl\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 // 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 <MediaShell\n variant=\"light\"\n rootRef={cardRef}\n data-testid=\"locked-attachment\"\n >\n <CardThumbnail\n variant=\"light\"\n gallery={gallery}\n title={title}\n showLocked={isLocked}\n paymentStatus={paymentStatus}\n mimeType={mimeType}\n thumbnailUrl={thumbnailUrl}\n source={source}\n containedImage={\n !isLocked && (sourceType === 'image' || sourceType === 'document')\n }\n />\n\n <CardBody\n variant=\"light\"\n title={title}\n mimeType={mimeType}\n detail={detail}\n statusBadge={\n <PurchaseStatusBadge\n isMine={false}\n paymentStatus={paymentStatus}\n amountText={amountText}\n />\n }\n icon={isGallery ? galleryBodyIcon('light') : undefined}\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 </MediaShell>\n )\n}\n\n/**\n * The card either party sees for a paid media attachment. `isMine` selects\n * the sender's preview view (tap-to-preview own draft) vs. the recipient's\n * unlock/download view.\n */\nconst MediaCard: React.FC<MediaCardProps> = (props) =>\n props.isMine ? <OwnMediaCard {...props} /> : <OtherMediaCard {...props} />\n\nexport default MediaCard\n"],"names":["useReceivedSource","paymentStatus","onFetchSource","onUnlockClick","source","setSource","useState","cardRef","useRef","fetchingRef","onFetchSourceRef","fetchSource","useCallback","result","_a","handleUnlockClick","useEffect","observer","entry","buttonClass","ReceivedCardActions","isLocked","sourceUrl","redeemUrl","onUnlockClicked","onDownloadClicked","isUnlocking","jsx","jsxs","React","LockSimpleIcon","href","DownloadSimpleIcon","OwnMediaCard","title","mimeType","thumbnailUrl","detail","amountText","placeholderTitle","gallery","onPreviewClick","isGallery","isGalleryCard","isPreviewVisible","isLoadingPreview","togglePreview","usePreviewToggle","showLocked","isBusy","MediaShell","PreviewToggle","CardThumbnail","CardBody","PurchaseStatusBadge","galleryBodyIcon","OtherMediaCard","onDownloadClick","effectiveSourceUrl","effectiveRedeemUrl","sourceType","getSourceType","actionSourceUrl","MediaCard","props"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Card-DVfSiq9b.cjs","sources":["../src/components/LockedAttachment/components/_shared/useReceivedSource.ts","../src/components/LockedAttachment/components/Media/CardActions.tsx","../src/components/LockedAttachment/components/Media/Card.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react'\n\nimport type {\n FetchSourceHandler,\n LockedAttachmentSource,\n PaymentStatus,\n} from '../../types'\n\nexport interface UseReceivedSourceOptions {\n paymentStatus?: PaymentStatus\n onFetchSource?: FetchSourceHandler\n /** Called on Unlock click while the card is still unpaid (opens checkout). */\n onUnlockClick?: () => void\n}\n\nexport interface UseReceivedSourceResult {\n source: LockedAttachmentSource | undefined\n /** Attach to the card root so the paid-source auto-fetch can observe it. */\n cardRef: React.RefObject<HTMLDivElement>\n /** Fetches the source when already paid, else defers to `onUnlockClick`. */\n handleUnlockClick: () => void\n}\n\n/**\n * Media !isMine's source-reveal logic: unlike Composer/Media isMine's\n * tap-to-toggle (`usePreviewToggle`), the recipient's card reveals its source\n * by fetching once — on click when already paid, or automatically the first\n * time a paid card scrolls fully into view. The fetch is guarded so it runs\n * at most once in flight.\n */\nexport function useReceivedSource({\n paymentStatus,\n onFetchSource,\n onUnlockClick,\n}: UseReceivedSourceOptions): UseReceivedSourceResult {\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 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 return { source, cardRef, handleUnlockClick }\n}\n","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 type React from 'react'\n\nimport { getSourceType } from '../../../AttachmentCard'\nimport type {\n FetchSourceHandler,\n LockedAttachmentGalleryItem,\n PaymentStatus,\n} from '../../types'\nimport CardBody from '../_shared/CardBody'\nimport CardThumbnail, {\n galleryBodyIcon,\n isGalleryCard,\n} from '../_shared/CardThumbnail'\nimport MediaShell from '../_shared/MediaShell'\nimport PreviewToggle from '../_shared/PreviewToggle'\nimport PurchaseStatusBadge from '../_shared/PurchaseStatusBadge'\nimport { usePreviewToggle } from '../_shared/usePreviewToggle'\nimport { useReceivedSource } from '../_shared/useReceivedSource'\n\nimport ReceivedCardActions from './CardActions'\n\ninterface MediaCardSharedProps {\n title?: string\n mimeType?: string\n thumbnailUrl?: string\n detail?: string\n amountText?: string\n paymentStatus?: PaymentStatus\n gallery?: LockedAttachmentGalleryItem[]\n onFetchSource?: FetchSourceHandler\n}\n\nexport type MediaCardProps =\n | (MediaCardSharedProps & {\n isMine: true\n /** Dimmed fallback shown in the title slot when `title` is unset. */\n placeholderTitle?: string\n /** Fired the first time the sender taps the thumbnail to preview their own attachment. */\n onPreviewClick?: () => void\n })\n | (MediaCardSharedProps & {\n isMine: false\n /**\n * When true, shows a loading spinner on the Unlock button. Driven by\n * the LockedAttachmentContext (e.g. checkout in progress).\n */\n isUnlocking?: boolean\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 when the recipient clicks Download on an unlocked card.\n * Omit to hide the Download button.\n */\n onDownloadClick?: () => void\n })\n\n/**\n * The sender's ('mine') view of a paid media attachment: the locked\n * thumbnail (single or gallery) they can tap to preview their own\n * attachment, plus the title/purchase-status body.\n */\nconst OwnMediaCard: React.FC<\n MediaCardSharedProps & {\n isMine: true\n placeholderTitle?: string\n onPreviewClick?: () => void\n }\n> = ({\n title,\n mimeType = 'application/octet-stream',\n thumbnailUrl,\n detail,\n amountText,\n placeholderTitle = 'Attachment title',\n paymentStatus = 'pending',\n gallery = [],\n onPreviewClick,\n onFetchSource,\n}) => {\n const isGallery = isGalleryCard(gallery)\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 { source, isPreviewVisible, isLoadingPreview, togglePreview } =\n usePreviewToggle({ isGallery, onFetchSource, onPreviewClick })\n\n const showLocked = !isPreviewVisible\n const isBusy = isLoadingPreview\n\n return (\n <MediaShell variant=\"dark\">\n <PreviewToggle\n onToggle={togglePreview}\n isBusy={isBusy}\n isPreviewVisible={!showLocked}\n >\n <CardThumbnail\n variant=\"dark\"\n gallery={gallery}\n title={title}\n showLocked={showLocked}\n paymentStatus={paymentStatus}\n mimeType={mimeType}\n thumbnailUrl={thumbnailUrl}\n source={source}\n />\n </PreviewToggle>\n\n <CardBody\n variant=\"dark\"\n title={title}\n placeholderTitle={placeholderTitle}\n mimeType={mimeType}\n detail={detail}\n statusBadge={\n <PurchaseStatusBadge\n isMine={true}\n paymentStatus={paymentStatus}\n amountText={amountText}\n />\n }\n icon={isGallery ? galleryBodyIcon('dark') : undefined}\n />\n </MediaShell>\n )\n}\n\n/**\n * The recipient's ('other') view of a paid media attachment: the locked\n * thumbnail (single or gallery) with an Unlock/Download CTA. The source is\n * revealed by fetching once — on click when already paid, or automatically\n * the first time a paid card scrolls into view.\n */\nconst OtherMediaCard: React.FC<\n MediaCardSharedProps & {\n isMine: false\n onUnlockClick?: () => void\n onDownloadClick?: () => void\n isUnlocking?: boolean\n }\n> = ({\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 = isGalleryCard(gallery)\n\n const { source, cardRef, handleUnlockClick } = useReceivedSource({\n paymentStatus,\n onFetchSource,\n onUnlockClick,\n })\n\n const effectiveSourceUrl = source?.sourceUrl\n const effectiveRedeemUrl = source?.redeemUrl\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 // 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 <MediaShell\n variant=\"light\"\n rootRef={cardRef}\n data-testid=\"locked-attachment\"\n >\n <CardThumbnail\n variant=\"light\"\n gallery={gallery}\n title={title}\n showLocked={isLocked}\n paymentStatus={paymentStatus}\n mimeType={mimeType}\n thumbnailUrl={thumbnailUrl}\n source={source}\n containedImage={\n !isLocked && (sourceType === 'image' || sourceType === 'document')\n }\n />\n\n <CardBody\n variant=\"light\"\n title={title}\n mimeType={mimeType}\n detail={detail}\n statusBadge={\n <PurchaseStatusBadge\n isMine={false}\n paymentStatus={paymentStatus}\n amountText={amountText}\n />\n }\n icon={isGallery ? galleryBodyIcon('light') : undefined}\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 </MediaShell>\n )\n}\n\n/**\n * The card either party sees for a paid media attachment. `isMine` selects\n * the sender's preview view (tap-to-preview own draft) vs. the recipient's\n * unlock/download view.\n */\nconst MediaCard: React.FC<MediaCardProps> = (props) =>\n props.isMine ? <OwnMediaCard {...props} /> : <OtherMediaCard {...props} />\n\nexport default MediaCard\n"],"names":["useReceivedSource","paymentStatus","onFetchSource","onUnlockClick","source","setSource","useState","cardRef","useRef","fetchingRef","onFetchSourceRef","fetchSource","useCallback","result","_a","handleUnlockClick","useEffect","observer","entry","buttonClass","ReceivedCardActions","isLocked","sourceUrl","redeemUrl","onUnlockClicked","onDownloadClicked","isUnlocking","jsx","jsxs","React","LockSimpleIcon","href","DownloadSimpleIcon","OwnMediaCard","title","mimeType","thumbnailUrl","detail","amountText","placeholderTitle","gallery","onPreviewClick","isGallery","isGalleryCard","isPreviewVisible","isLoadingPreview","togglePreview","usePreviewToggle","showLocked","isBusy","MediaShell","PreviewToggle","CardThumbnail","CardBody","PurchaseStatusBadge","galleryBodyIcon","OtherMediaCard","onDownloadClick","effectiveSourceUrl","effectiveRedeemUrl","sourceType","getSourceType","actionSourceUrl","MediaCard","props"],"mappings":"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"}
|
|
@@ -2,8 +2,8 @@ import { jsx as r, jsxs as m } from "react/jsx-runtime";
|
|
|
2
2
|
import "classnames";
|
|
3
3
|
import { LockSimpleIcon as U, DownloadSimpleIcon as M } from "@phosphor-icons/react";
|
|
4
4
|
import j, { useState as G, useRef as p, useCallback as R, useEffect as O } from "react";
|
|
5
|
-
import { g as T } from "./index-
|
|
6
|
-
import { i as B, u as A, M as N, P as D, C as k, a as I, g as y } from "./usePreviewToggle-
|
|
5
|
+
import { g as T } from "./index-CZTUyiPe.js";
|
|
6
|
+
import { i as B, u as A, M as N, P as D, C as k, a as I, g as y } from "./usePreviewToggle-BG-pfsgP.js";
|
|
7
7
|
import { P as z } from "./PurchaseStatusBadge-CJH4S-8Z.js";
|
|
8
8
|
function S({
|
|
9
9
|
paymentStatus: e,
|
|
@@ -218,4 +218,4 @@ const C = "mt-3 inline-flex h-10 w-full items-center justify-center gap-2 rounde
|
|
|
218
218
|
export {
|
|
219
219
|
X as default
|
|
220
220
|
};
|
|
221
|
-
//# sourceMappingURL=Card-
|
|
221
|
+
//# sourceMappingURL=Card-DX9nBx1S.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Card-BG-Mg_ss.js","sources":["../src/components/LockedAttachment/components/_shared/useReceivedSource.ts","../src/components/LockedAttachment/components/Media/CardActions.tsx","../src/components/LockedAttachment/components/Media/Card.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react'\n\nimport type {\n FetchSourceHandler,\n LockedAttachmentSource,\n PaymentStatus,\n} from '../../types'\n\nexport interface UseReceivedSourceOptions {\n paymentStatus?: PaymentStatus\n onFetchSource?: FetchSourceHandler\n /** Called on Unlock click while the card is still unpaid (opens checkout). */\n onUnlockClick?: () => void\n}\n\nexport interface UseReceivedSourceResult {\n source: LockedAttachmentSource | undefined\n /** Attach to the card root so the paid-source auto-fetch can observe it. */\n cardRef: React.RefObject<HTMLDivElement>\n /** Fetches the source when already paid, else defers to `onUnlockClick`. */\n handleUnlockClick: () => void\n}\n\n/**\n * Media !isMine's source-reveal logic: unlike Composer/Media isMine's\n * tap-to-toggle (`usePreviewToggle`), the recipient's card reveals its source\n * by fetching once — on click when already paid, or automatically the first\n * time a paid card scrolls fully into view. The fetch is guarded so it runs\n * at most once in flight.\n */\nexport function useReceivedSource({\n paymentStatus,\n onFetchSource,\n onUnlockClick,\n}: UseReceivedSourceOptions): UseReceivedSourceResult {\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 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 return { source, cardRef, handleUnlockClick }\n}\n","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 type React from 'react'\n\nimport { getSourceType } from '../../../AttachmentCard'\nimport type {\n FetchSourceHandler,\n LockedAttachmentGalleryItem,\n PaymentStatus,\n} from '../../types'\nimport CardBody from '../_shared/CardBody'\nimport CardThumbnail, {\n galleryBodyIcon,\n isGalleryCard,\n} from '../_shared/CardThumbnail'\nimport MediaShell from '../_shared/MediaShell'\nimport PreviewToggle from '../_shared/PreviewToggle'\nimport PurchaseStatusBadge from '../_shared/PurchaseStatusBadge'\nimport { usePreviewToggle } from '../_shared/usePreviewToggle'\nimport { useReceivedSource } from '../_shared/useReceivedSource'\n\nimport ReceivedCardActions from './CardActions'\n\ninterface MediaCardSharedProps {\n title?: string\n mimeType?: string\n thumbnailUrl?: string\n detail?: string\n amountText?: string\n paymentStatus?: PaymentStatus\n gallery?: LockedAttachmentGalleryItem[]\n onFetchSource?: FetchSourceHandler\n}\n\nexport type MediaCardProps =\n | (MediaCardSharedProps & {\n isMine: true\n /** Dimmed fallback shown in the title slot when `title` is unset. */\n placeholderTitle?: string\n /** Fired the first time the sender taps the thumbnail to preview their own attachment. */\n onPreviewClick?: () => void\n })\n | (MediaCardSharedProps & {\n isMine: false\n /**\n * When true, shows a loading spinner on the Unlock button. Driven by\n * the LockedAttachmentContext (e.g. checkout in progress).\n */\n isUnlocking?: boolean\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 when the recipient clicks Download on an unlocked card.\n * Omit to hide the Download button.\n */\n onDownloadClick?: () => void\n })\n\n/**\n * The sender's ('mine') view of a paid media attachment: the locked\n * thumbnail (single or gallery) they can tap to preview their own\n * attachment, plus the title/purchase-status body.\n */\nconst OwnMediaCard: React.FC<\n MediaCardSharedProps & {\n isMine: true\n placeholderTitle?: string\n onPreviewClick?: () => void\n }\n> = ({\n title,\n mimeType = 'application/octet-stream',\n thumbnailUrl,\n detail,\n amountText,\n placeholderTitle = 'Attachment title',\n paymentStatus = 'pending',\n gallery = [],\n onPreviewClick,\n onFetchSource,\n}) => {\n const isGallery = isGalleryCard(gallery)\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 { source, isPreviewVisible, isLoadingPreview, togglePreview } =\n usePreviewToggle({ isGallery, onFetchSource, onPreviewClick })\n\n const showLocked = !isPreviewVisible\n const isBusy = isLoadingPreview\n\n return (\n <MediaShell variant=\"dark\">\n <PreviewToggle\n onToggle={togglePreview}\n isBusy={isBusy}\n isPreviewVisible={!showLocked}\n >\n <CardThumbnail\n variant=\"dark\"\n gallery={gallery}\n title={title}\n showLocked={showLocked}\n paymentStatus={paymentStatus}\n mimeType={mimeType}\n thumbnailUrl={thumbnailUrl}\n source={source}\n />\n </PreviewToggle>\n\n <CardBody\n variant=\"dark\"\n title={title}\n placeholderTitle={placeholderTitle}\n mimeType={mimeType}\n detail={detail}\n statusBadge={\n <PurchaseStatusBadge\n isMine={true}\n paymentStatus={paymentStatus}\n amountText={amountText}\n />\n }\n icon={isGallery ? galleryBodyIcon('dark') : undefined}\n />\n </MediaShell>\n )\n}\n\n/**\n * The recipient's ('other') view of a paid media attachment: the locked\n * thumbnail (single or gallery) with an Unlock/Download CTA. The source is\n * revealed by fetching once — on click when already paid, or automatically\n * the first time a paid card scrolls into view.\n */\nconst OtherMediaCard: React.FC<\n MediaCardSharedProps & {\n isMine: false\n onUnlockClick?: () => void\n onDownloadClick?: () => void\n isUnlocking?: boolean\n }\n> = ({\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 = isGalleryCard(gallery)\n\n const { source, cardRef, handleUnlockClick } = useReceivedSource({\n paymentStatus,\n onFetchSource,\n onUnlockClick,\n })\n\n const effectiveSourceUrl = source?.sourceUrl\n const effectiveRedeemUrl = source?.redeemUrl\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 // 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 <MediaShell\n variant=\"light\"\n rootRef={cardRef}\n data-testid=\"locked-attachment\"\n >\n <CardThumbnail\n variant=\"light\"\n gallery={gallery}\n title={title}\n showLocked={isLocked}\n paymentStatus={paymentStatus}\n mimeType={mimeType}\n thumbnailUrl={thumbnailUrl}\n source={source}\n containedImage={\n !isLocked && (sourceType === 'image' || sourceType === 'document')\n }\n />\n\n <CardBody\n variant=\"light\"\n title={title}\n mimeType={mimeType}\n detail={detail}\n statusBadge={\n <PurchaseStatusBadge\n isMine={false}\n paymentStatus={paymentStatus}\n amountText={amountText}\n />\n }\n icon={isGallery ? galleryBodyIcon('light') : undefined}\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 </MediaShell>\n )\n}\n\n/**\n * The card either party sees for a paid media attachment. `isMine` selects\n * the sender's preview view (tap-to-preview own draft) vs. the recipient's\n * unlock/download view.\n */\nconst MediaCard: React.FC<MediaCardProps> = (props) =>\n props.isMine ? <OwnMediaCard {...props} /> : <OtherMediaCard {...props} />\n\nexport default MediaCard\n"],"names":["useReceivedSource","paymentStatus","onFetchSource","onUnlockClick","source","setSource","useState","cardRef","useRef","fetchingRef","onFetchSourceRef","fetchSource","useCallback","result","_a","handleUnlockClick","useEffect","observer","entry","buttonClass","ReceivedCardActions","isLocked","sourceUrl","redeemUrl","onUnlockClicked","onDownloadClicked","isUnlocking","jsx","jsxs","React","LockSimpleIcon","href","DownloadSimpleIcon","OwnMediaCard","title","mimeType","thumbnailUrl","detail","amountText","placeholderTitle","gallery","onPreviewClick","isGallery","isGalleryCard","isPreviewVisible","isLoadingPreview","togglePreview","usePreviewToggle","showLocked","MediaShell","PreviewToggle","CardThumbnail","CardBody","PurchaseStatusBadge","galleryBodyIcon","OtherMediaCard","onDownloadClick","effectiveSourceUrl","effectiveRedeemUrl","sourceType","getSourceType","actionSourceUrl","MediaCard","props"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Card-DX9nBx1S.js","sources":["../src/components/LockedAttachment/components/_shared/useReceivedSource.ts","../src/components/LockedAttachment/components/Media/CardActions.tsx","../src/components/LockedAttachment/components/Media/Card.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react'\n\nimport type {\n FetchSourceHandler,\n LockedAttachmentSource,\n PaymentStatus,\n} from '../../types'\n\nexport interface UseReceivedSourceOptions {\n paymentStatus?: PaymentStatus\n onFetchSource?: FetchSourceHandler\n /** Called on Unlock click while the card is still unpaid (opens checkout). */\n onUnlockClick?: () => void\n}\n\nexport interface UseReceivedSourceResult {\n source: LockedAttachmentSource | undefined\n /** Attach to the card root so the paid-source auto-fetch can observe it. */\n cardRef: React.RefObject<HTMLDivElement>\n /** Fetches the source when already paid, else defers to `onUnlockClick`. */\n handleUnlockClick: () => void\n}\n\n/**\n * Media !isMine's source-reveal logic: unlike Composer/Media isMine's\n * tap-to-toggle (`usePreviewToggle`), the recipient's card reveals its source\n * by fetching once — on click when already paid, or automatically the first\n * time a paid card scrolls fully into view. The fetch is guarded so it runs\n * at most once in flight.\n */\nexport function useReceivedSource({\n paymentStatus,\n onFetchSource,\n onUnlockClick,\n}: UseReceivedSourceOptions): UseReceivedSourceResult {\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 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 return { source, cardRef, handleUnlockClick }\n}\n","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 type React from 'react'\n\nimport { getSourceType } from '../../../AttachmentCard'\nimport type {\n FetchSourceHandler,\n LockedAttachmentGalleryItem,\n PaymentStatus,\n} from '../../types'\nimport CardBody from '../_shared/CardBody'\nimport CardThumbnail, {\n galleryBodyIcon,\n isGalleryCard,\n} from '../_shared/CardThumbnail'\nimport MediaShell from '../_shared/MediaShell'\nimport PreviewToggle from '../_shared/PreviewToggle'\nimport PurchaseStatusBadge from '../_shared/PurchaseStatusBadge'\nimport { usePreviewToggle } from '../_shared/usePreviewToggle'\nimport { useReceivedSource } from '../_shared/useReceivedSource'\n\nimport ReceivedCardActions from './CardActions'\n\ninterface MediaCardSharedProps {\n title?: string\n mimeType?: string\n thumbnailUrl?: string\n detail?: string\n amountText?: string\n paymentStatus?: PaymentStatus\n gallery?: LockedAttachmentGalleryItem[]\n onFetchSource?: FetchSourceHandler\n}\n\nexport type MediaCardProps =\n | (MediaCardSharedProps & {\n isMine: true\n /** Dimmed fallback shown in the title slot when `title` is unset. */\n placeholderTitle?: string\n /** Fired the first time the sender taps the thumbnail to preview their own attachment. */\n onPreviewClick?: () => void\n })\n | (MediaCardSharedProps & {\n isMine: false\n /**\n * When true, shows a loading spinner on the Unlock button. Driven by\n * the LockedAttachmentContext (e.g. checkout in progress).\n */\n isUnlocking?: boolean\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 when the recipient clicks Download on an unlocked card.\n * Omit to hide the Download button.\n */\n onDownloadClick?: () => void\n })\n\n/**\n * The sender's ('mine') view of a paid media attachment: the locked\n * thumbnail (single or gallery) they can tap to preview their own\n * attachment, plus the title/purchase-status body.\n */\nconst OwnMediaCard: React.FC<\n MediaCardSharedProps & {\n isMine: true\n placeholderTitle?: string\n onPreviewClick?: () => void\n }\n> = ({\n title,\n mimeType = 'application/octet-stream',\n thumbnailUrl,\n detail,\n amountText,\n placeholderTitle = 'Attachment title',\n paymentStatus = 'pending',\n gallery = [],\n onPreviewClick,\n onFetchSource,\n}) => {\n const isGallery = isGalleryCard(gallery)\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 { source, isPreviewVisible, isLoadingPreview, togglePreview } =\n usePreviewToggle({ isGallery, onFetchSource, onPreviewClick })\n\n const showLocked = !isPreviewVisible\n const isBusy = isLoadingPreview\n\n return (\n <MediaShell variant=\"dark\">\n <PreviewToggle\n onToggle={togglePreview}\n isBusy={isBusy}\n isPreviewVisible={!showLocked}\n >\n <CardThumbnail\n variant=\"dark\"\n gallery={gallery}\n title={title}\n showLocked={showLocked}\n paymentStatus={paymentStatus}\n mimeType={mimeType}\n thumbnailUrl={thumbnailUrl}\n source={source}\n />\n </PreviewToggle>\n\n <CardBody\n variant=\"dark\"\n title={title}\n placeholderTitle={placeholderTitle}\n mimeType={mimeType}\n detail={detail}\n statusBadge={\n <PurchaseStatusBadge\n isMine={true}\n paymentStatus={paymentStatus}\n amountText={amountText}\n />\n }\n icon={isGallery ? galleryBodyIcon('dark') : undefined}\n />\n </MediaShell>\n )\n}\n\n/**\n * The recipient's ('other') view of a paid media attachment: the locked\n * thumbnail (single or gallery) with an Unlock/Download CTA. The source is\n * revealed by fetching once — on click when already paid, or automatically\n * the first time a paid card scrolls into view.\n */\nconst OtherMediaCard: React.FC<\n MediaCardSharedProps & {\n isMine: false\n onUnlockClick?: () => void\n onDownloadClick?: () => void\n isUnlocking?: boolean\n }\n> = ({\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 = isGalleryCard(gallery)\n\n const { source, cardRef, handleUnlockClick } = useReceivedSource({\n paymentStatus,\n onFetchSource,\n onUnlockClick,\n })\n\n const effectiveSourceUrl = source?.sourceUrl\n const effectiveRedeemUrl = source?.redeemUrl\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 // 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 <MediaShell\n variant=\"light\"\n rootRef={cardRef}\n data-testid=\"locked-attachment\"\n >\n <CardThumbnail\n variant=\"light\"\n gallery={gallery}\n title={title}\n showLocked={isLocked}\n paymentStatus={paymentStatus}\n mimeType={mimeType}\n thumbnailUrl={thumbnailUrl}\n source={source}\n containedImage={\n !isLocked && (sourceType === 'image' || sourceType === 'document')\n }\n />\n\n <CardBody\n variant=\"light\"\n title={title}\n mimeType={mimeType}\n detail={detail}\n statusBadge={\n <PurchaseStatusBadge\n isMine={false}\n paymentStatus={paymentStatus}\n amountText={amountText}\n />\n }\n icon={isGallery ? galleryBodyIcon('light') : undefined}\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 </MediaShell>\n )\n}\n\n/**\n * The card either party sees for a paid media attachment. `isMine` selects\n * the sender's preview view (tap-to-preview own draft) vs. the recipient's\n * unlock/download view.\n */\nconst MediaCard: React.FC<MediaCardProps> = (props) =>\n props.isMine ? <OwnMediaCard {...props} /> : <OtherMediaCard {...props} />\n\nexport default MediaCard\n"],"names":["useReceivedSource","paymentStatus","onFetchSource","onUnlockClick","source","setSource","useState","cardRef","useRef","fetchingRef","onFetchSourceRef","fetchSource","useCallback","result","_a","handleUnlockClick","useEffect","observer","entry","buttonClass","ReceivedCardActions","isLocked","sourceUrl","redeemUrl","onUnlockClicked","onDownloadClicked","isUnlocking","jsx","jsxs","React","LockSimpleIcon","href","DownloadSimpleIcon","OwnMediaCard","title","mimeType","thumbnailUrl","detail","amountText","placeholderTitle","gallery","onPreviewClick","isGallery","isGalleryCard","isPreviewVisible","isLoadingPreview","togglePreview","usePreviewToggle","showLocked","MediaShell","PreviewToggle","CardThumbnail","CardBody","PurchaseStatusBadge","galleryBodyIcon","OtherMediaCard","onDownloadClick","effectiveSourceUrl","effectiveRedeemUrl","sourceType","getSourceType","actionSourceUrl","MediaCard","props"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as e, jsxs as r } from "react/jsx-runtime";
|
|
2
2
|
import { XIcon as m, PencilSimpleIcon as z } from "@phosphor-icons/react";
|
|
3
3
|
import B from "react";
|
|
4
|
-
import { i as j, u as T, M as I, P as L, C as M, a as R, g as S } from "./usePreviewToggle-
|
|
4
|
+
import { i as j, u as T, M as I, P as L, C as M, a as R, g as S } from "./usePreviewToggle-BG-pfsgP.js";
|
|
5
5
|
import { T as A, P as G } from "./TextShell-BiqF2UB0.js";
|
|
6
6
|
const V = ({
|
|
7
7
|
text: t,
|
|
@@ -105,4 +105,4 @@ const V = ({
|
|
|
105
105
|
export {
|
|
106
106
|
J as default
|
|
107
107
|
};
|
|
108
|
-
//# sourceMappingURL=Card-
|
|
108
|
+
//# sourceMappingURL=Card-qDLtjK6u.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Card-
|
|
1
|
+
{"version":3,"file":"Card-qDLtjK6u.js","sources":["../src/components/LockedAttachment/components/Composer/Card.tsx"],"sourcesContent":["import { PencilSimpleIcon, XIcon } from '@phosphor-icons/react'\nimport React from 'react'\n\nimport type { FetchSourceHandler, LockedAttachmentBaseProps } from '../../types'\nimport CardBody from '../_shared/CardBody'\nimport CardThumbnail, {\n galleryBodyIcon,\n isGalleryCard,\n} from '../_shared/CardThumbnail'\nimport MediaShell from '../_shared/MediaShell'\nimport PreviewToggle from '../_shared/PreviewToggle'\nimport PriceLockRow from '../_shared/PriceLockRow'\nimport TextShell from '../_shared/TextShell'\nimport { usePreviewToggle } from '../_shared/usePreviewToggle'\n\nexport interface ComposerCardProps extends LockedAttachmentBaseProps {\n /**\n * The message's own text, shown as-is (not redacted yet — the message\n * hasn't been sent). Only used when `contentType` is `\"text\"`.\n */\n text?: string\n /** Placeholder shown in the amount slot before one is configured. */\n placeholderAmountText?: string\n /**\n * Renders a persistent dismiss X on the thumbnail (media) or next to the\n * text (text mode); called to remove the draft attachment. Unrelated to\n * `TextCardProps.onDismiss`, which only appears for `isMine` after a\n * failed payment.\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 * Ignored when `contentType` is `\"text\"`.\n */\n onFetchSource?: FetchSourceHandler\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 * Composer card in text mode: a normal outgoing chat bubble showing the real\n * draft text (it hasn't been sent/redacted yet) plus a dismiss X and a price\n * row. Media-only props are ignored here.\n */\nconst ComposerTextCard: React.FC<ComposerCardProps> = ({\n text,\n amountText,\n placeholderAmountText,\n onDismiss,\n}) => (\n <TextShell>\n <div className=\"pr-8\">{text}</div>\n <PriceLockRow>\n <span className={amountText ? 'text-white/55' : 'text-white/30'}>\n {amountText || placeholderAmountText}\n </span>\n </PriceLockRow>\n {onDismiss && (\n <button\n type=\"button\"\n onClick={onDismiss}\n className=\"absolute right-3 top-3 flex size-6 shrink-0 items-center justify-center rounded-full bg-white/10 text-white hover:bg-white/15\"\n aria-label=\"Dismiss attachment\"\n >\n <XIcon className=\"size-3\" weight=\"bold\" />\n </button>\n )}\n </TextShell>\n)\n\n/**\n * Composer card in media mode: the locked thumbnail (single or gallery) the\n * composer taps to preview the attachment they're about to send, plus the\n * title/price body with optional dismiss X and edit pencil.\n */\nconst ComposerMediaCard: 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 isGallery = isGalleryCard(gallery)\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 { source, isPreviewVisible, isLoadingPreview, togglePreview } =\n usePreviewToggle({ isGallery, onFetchSource, onPreviewClick })\n\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 return (\n <MediaShell variant=\"dark\">\n <PreviewToggle\n onToggle={togglePreview}\n isBusy={isBusy}\n isPreviewVisible={!showLocked}\n >\n <CardThumbnail\n variant=\"dark\"\n gallery={gallery}\n title={title}\n showLocked={showLocked}\n mimeType={mimeType}\n thumbnailUrl={thumbnailUrl}\n source={source}\n topRight={dismissButton}\n />\n </PreviewToggle>\n\n <CardBody\n variant=\"dark\"\n title={title}\n placeholderTitle={placeholderTitle}\n mimeType={mimeType}\n detail={detail}\n statusBadge={statusBadge}\n icon={isGallery ? galleryBodyIcon('dark') : undefined}\n trailingAction={editButton}\n />\n </MediaShell>\n )\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 *\n * When `contentType === \"text\"`, renders as a normal outgoing chat bubble\n * showing the real draft text (it hasn't been sent/redacted yet) plus a\n * dismiss X and a price row, instead of a media thumbnail card.\n */\nconst ComposerCard: React.FC<ComposerCardProps> = (props) =>\n props.contentType === 'text' ? (\n <ComposerTextCard {...props} />\n ) : (\n <ComposerMediaCard {...props} />\n )\n\nexport default ComposerCard\n"],"names":["ComposerTextCard","text","amountText","placeholderAmountText","onDismiss","TextShell","jsx","PriceLockRow","XIcon","ComposerMediaCard","title","mimeType","thumbnailUrl","detail","placeholderTitle","gallery","onPreviewClick","onFetchSource","onEditClick","isGallery","isGalleryCard","source","isPreviewVisible","isLoadingPreview","togglePreview","usePreviewToggle","showLocked","isBusy","statusBadge","jsxs","React","dismissButton","e","editButton","PencilSimpleIcon","MediaShell","PreviewToggle","CardThumbnail","CardBody","galleryBodyIcon","ComposerCard","props"],"mappings":"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"}
|
|
@@ -818,7 +818,7 @@ function bs({
|
|
|
818
818
|
const n = e == null ? void 0 : e.text, a = ya(t);
|
|
819
819
|
return a ? ((r = e == null ? void 0 : e.i18n) == null ? void 0 : r[`${a}_text`]) ?? n : n;
|
|
820
820
|
}
|
|
821
|
-
const ka = V.lazy(() => import("./Card-
|
|
821
|
+
const ka = V.lazy(() => import("./Card-qDLtjK6u.js")), Ca = V.lazy(() => import("./Card-DSG-wR8t.js")), Sa = V.lazy(() => import("./Card-DX9nBx1S.js")), mt = () => /* @__PURE__ */ s(
|
|
822
822
|
"div",
|
|
823
823
|
{
|
|
824
824
|
className: "w-[280px] min-h-[200px] animate-pulse rounded-md bg-black/[0.06] shadow-[0_0_0_1px_rgba(0,0,0,0.04),0_1px_2px_rgba(0,0,0,0.04),0_8px_32px_rgba(0,0,0,0.1)]",
|
|
@@ -2682,10 +2682,10 @@ const Hr = ({ size: e = 15 }) => /* @__PURE__ */ s(
|
|
|
2682
2682
|
return ((t = e.metadata) == null ? void 0 : t.custom_type) === "MESSAGE_ATTACHMENT";
|
|
2683
2683
|
}, Wr = (e) => {
|
|
2684
2684
|
var t;
|
|
2685
|
-
return yt(e) && ((t = e.metadata) == null ? void 0 : t.
|
|
2685
|
+
return yt(e) && ((t = e.metadata) == null ? void 0 : t.attachment_content_type) === "text";
|
|
2686
2686
|
}, Xr = (e) => {
|
|
2687
2687
|
var t;
|
|
2688
|
-
return yt(e) && ((t = e.metadata) == null ? void 0 : t.
|
|
2688
|
+
return yt(e) && ((t = e.metadata) == null ? void 0 : t.attachment_content_type) !== "text";
|
|
2689
2689
|
}, Ps = (e) => Yr(e) || qr(e), Kr = (e) => {
|
|
2690
2690
|
var t;
|
|
2691
2691
|
return Ps(e) && !((t = e.text) != null && t.trim());
|
|
@@ -5240,4 +5240,4 @@ export {
|
|
|
5240
5240
|
pt as y,
|
|
5241
5241
|
ut as z
|
|
5242
5242
|
};
|
|
5243
|
-
//# sourceMappingURL=index-
|
|
5243
|
+
//# sourceMappingURL=index-CZTUyiPe.js.map
|