@linktr.ee/messaging-react 1.31.0-rc-1776748331 → 1.31.0
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.
|
@@ -1,176 +1,176 @@
|
|
|
1
|
-
import { jsx as e, jsxs as
|
|
2
|
-
import { LockSimpleIcon as
|
|
3
|
-
import
|
|
4
|
-
import { r as
|
|
5
|
-
const
|
|
1
|
+
import { jsx as e, jsxs as c, Fragment as y } from "react/jsx-runtime";
|
|
2
|
+
import { LockSimpleIcon as I, DownloadSimpleIcon as D, CheckCircleIcon as M, LockOpenIcon as R } from "@phosphor-icons/react";
|
|
3
|
+
import O, { useState as z, useRef as g, useCallback as L, useEffect as T } from "react";
|
|
4
|
+
import { r as _, M as A, g as E } from "./MediaPlayer-BCsdmsON.js";
|
|
5
|
+
const V = (n) => {
|
|
6
6
|
const {
|
|
7
|
-
isLocked:
|
|
7
|
+
isLocked: r,
|
|
8
8
|
isUnlocking: s = !1,
|
|
9
|
-
sourceUrl:
|
|
10
|
-
redeemUrl:
|
|
9
|
+
sourceUrl: t,
|
|
10
|
+
redeemUrl: i,
|
|
11
11
|
onUnlockClicked: a,
|
|
12
12
|
onDownloadClicked: o
|
|
13
|
-
} =
|
|
14
|
-
return
|
|
13
|
+
} = n;
|
|
14
|
+
return r && a != null ? /* @__PURE__ */ e(
|
|
15
15
|
"button",
|
|
16
16
|
{
|
|
17
17
|
type: "button",
|
|
18
18
|
onClick: a,
|
|
19
19
|
disabled: s,
|
|
20
20
|
className: "mt-3 inline-flex h-10 w-full items-center justify-center gap-2 rounded-full bg-[#121110] px-4 text-sm font-medium leading-none text-white hover:bg-[#2a2928] disabled:opacity-70",
|
|
21
|
-
children: s ? /* @__PURE__ */ e(
|
|
22
|
-
/* @__PURE__ */ e(
|
|
21
|
+
children: s ? /* @__PURE__ */ e($, {}) : /* @__PURE__ */ c(O.Fragment, { children: [
|
|
22
|
+
/* @__PURE__ */ e(I, { className: "size-4", weight: "fill" }),
|
|
23
23
|
"Unlock"
|
|
24
24
|
] })
|
|
25
25
|
}
|
|
26
|
-
) : !
|
|
26
|
+
) : !r && o != null && t != null ? /* @__PURE__ */ c(
|
|
27
27
|
"a",
|
|
28
28
|
{
|
|
29
|
-
href:
|
|
29
|
+
href: i ?? t,
|
|
30
30
|
target: "_blank",
|
|
31
31
|
rel: "noopener noreferrer",
|
|
32
32
|
onClick: o,
|
|
33
33
|
className: "mt-3 inline-flex h-10 w-full items-center justify-center gap-2 rounded-full bg-[#121110] px-4 text-sm font-medium leading-none !text-white hover:bg-[#2a2928]",
|
|
34
34
|
children: [
|
|
35
|
-
/* @__PURE__ */ e(
|
|
35
|
+
/* @__PURE__ */ e(D, { className: "size-4", weight: "bold" }),
|
|
36
36
|
"Download"
|
|
37
37
|
]
|
|
38
38
|
}
|
|
39
39
|
) : null;
|
|
40
|
-
},
|
|
40
|
+
}, $ = () => /* @__PURE__ */ c("span", { className: "flex items-center gap-1", children: [
|
|
41
41
|
/* @__PURE__ */ e("span", { className: "size-1 rounded-full bg-white animate-bounce [animation-delay:-0.3s]" }),
|
|
42
42
|
/* @__PURE__ */ e("span", { className: "size-1 rounded-full bg-white animate-bounce [animation-delay:-0.15s]" }),
|
|
43
43
|
/* @__PURE__ */ e("span", { className: "size-1 rounded-full bg-white animate-bounce" })
|
|
44
|
-
] }),
|
|
45
|
-
const { thumbnailUrl:
|
|
46
|
-
return /* @__PURE__ */
|
|
47
|
-
|
|
44
|
+
] }), x = (n) => {
|
|
45
|
+
const { thumbnailUrl: r, mimeType: s, LockIcon: t } = n;
|
|
46
|
+
return /* @__PURE__ */ c("div", { className: "relative aspect-video overflow-hidden bg-black/5", children: [
|
|
47
|
+
r != null ? /* @__PURE__ */ e(
|
|
48
48
|
"img",
|
|
49
49
|
{
|
|
50
|
-
src:
|
|
50
|
+
src: r,
|
|
51
51
|
alt: "",
|
|
52
52
|
className: "absolute inset-0 h-full w-full object-cover"
|
|
53
53
|
}
|
|
54
|
-
) : /* @__PURE__ */ e("div", { className: "absolute inset-0 flex items-center justify-center", children:
|
|
54
|
+
) : /* @__PURE__ */ e("div", { className: "absolute inset-0 flex items-center justify-center", children: _(s, {
|
|
55
55
|
className: "size-12 text-black/20",
|
|
56
56
|
weight: "regular"
|
|
57
57
|
}) }),
|
|
58
|
-
|
|
58
|
+
t != null ? /* @__PURE__ */ e(q, { icon: t }) : null
|
|
59
59
|
] });
|
|
60
|
-
},
|
|
61
|
-
const { sourceUrl:
|
|
60
|
+
}, q = ({ icon: n }) => /* @__PURE__ */ e("div", { className: "absolute inset-0 bg-black/30", children: /* @__PURE__ */ e("div", { className: "absolute left-3 top-3 flex size-8 items-center justify-center rounded-full bg-black/60", children: /* @__PURE__ */ e(n, { className: "size-4 text-white", weight: "fill" }) }) }), B = (n) => {
|
|
61
|
+
const { sourceUrl: r, thumbnailUrl: s, mimeType: t, title: i, LockIcon: a } = n, [o, h] = z(!1);
|
|
62
62
|
return a != null ? /* @__PURE__ */ e(
|
|
63
|
-
|
|
63
|
+
x,
|
|
64
64
|
{
|
|
65
65
|
thumbnailUrl: s,
|
|
66
|
-
mimeType:
|
|
66
|
+
mimeType: t,
|
|
67
67
|
LockIcon: a
|
|
68
68
|
}
|
|
69
69
|
) : /* @__PURE__ */ e("div", { className: "relative overflow-hidden bg-black/5", children: /* @__PURE__ */ e(
|
|
70
70
|
"img",
|
|
71
71
|
{
|
|
72
|
-
src:
|
|
73
|
-
alt:
|
|
72
|
+
src: r,
|
|
73
|
+
alt: i,
|
|
74
74
|
className: `block w-full transition-opacity duration-300 ${o ? "opacity-100" : "opacity-0"}`,
|
|
75
75
|
onLoad: () => h(!0)
|
|
76
76
|
}
|
|
77
77
|
) });
|
|
78
|
-
},
|
|
79
|
-
const { sourceUrl:
|
|
80
|
-
return
|
|
81
|
-
|
|
78
|
+
}, F = (n) => {
|
|
79
|
+
const { sourceUrl: r, thumbnailUrl: s, mimeType: t, LockIcon: i } = n;
|
|
80
|
+
return i != null ? /* @__PURE__ */ e(
|
|
81
|
+
x,
|
|
82
82
|
{
|
|
83
83
|
thumbnailUrl: s,
|
|
84
|
-
mimeType:
|
|
85
|
-
LockIcon:
|
|
84
|
+
mimeType: t,
|
|
85
|
+
LockIcon: i
|
|
86
86
|
}
|
|
87
87
|
) : /* @__PURE__ */ e(
|
|
88
|
-
|
|
88
|
+
A,
|
|
89
89
|
{
|
|
90
|
-
source:
|
|
91
|
-
mimeType:
|
|
90
|
+
source: r ?? "",
|
|
91
|
+
mimeType: t,
|
|
92
92
|
poster: s
|
|
93
93
|
}
|
|
94
94
|
);
|
|
95
95
|
};
|
|
96
|
-
function
|
|
97
|
-
return
|
|
96
|
+
function G(n) {
|
|
97
|
+
return n === "paid" ? R : I;
|
|
98
98
|
}
|
|
99
|
-
const
|
|
100
|
-
title:
|
|
101
|
-
amountText:
|
|
99
|
+
const S = ({
|
|
100
|
+
title: n,
|
|
101
|
+
amountText: r,
|
|
102
102
|
thumbnailUrl: s,
|
|
103
|
-
mimeType:
|
|
104
|
-
detail:
|
|
103
|
+
mimeType: t = "application/octet-stream",
|
|
104
|
+
detail: i,
|
|
105
105
|
onUnlockClick: a,
|
|
106
106
|
onFetchSource: o,
|
|
107
107
|
onDownloadClick: h,
|
|
108
108
|
paymentStatus: d,
|
|
109
|
-
isUnlocking:
|
|
109
|
+
isUnlocking: j = !1
|
|
110
110
|
}) => {
|
|
111
|
-
const [l,
|
|
111
|
+
const [l, C] = z(), w = g(!1), b = g(!1), u = g(o);
|
|
112
112
|
u.current = o;
|
|
113
|
-
const
|
|
114
|
-
var
|
|
115
|
-
if (!
|
|
116
|
-
|
|
113
|
+
const k = l === void 0, N = E(t), p = k ? G(d) : void 0, m = L(async () => {
|
|
114
|
+
var v;
|
|
115
|
+
if (!b.current) {
|
|
116
|
+
b.current = !0;
|
|
117
117
|
try {
|
|
118
|
-
const
|
|
119
|
-
|
|
118
|
+
const U = await ((v = u.current) == null ? void 0 : v.call(u));
|
|
119
|
+
U && C(U);
|
|
120
120
|
} finally {
|
|
121
|
-
|
|
121
|
+
b.current = !1;
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
124
|
}, []);
|
|
125
|
-
|
|
126
|
-
if (!
|
|
127
|
-
|
|
125
|
+
T(() => {
|
|
126
|
+
if (!w.current) {
|
|
127
|
+
w.current = !0;
|
|
128
128
|
return;
|
|
129
129
|
}
|
|
130
|
-
|
|
130
|
+
d === "paid" && m();
|
|
131
131
|
}, [d, m]);
|
|
132
|
-
const
|
|
133
|
-
d === "paid" ?
|
|
132
|
+
const P = L(() => {
|
|
133
|
+
d === "paid" ? m() : a == null || a();
|
|
134
134
|
}, [d, a, m]);
|
|
135
135
|
let f;
|
|
136
|
-
return
|
|
136
|
+
return N === "image" ? f = /* @__PURE__ */ e(
|
|
137
137
|
B,
|
|
138
138
|
{
|
|
139
139
|
sourceUrl: l == null ? void 0 : l.sourceUrl,
|
|
140
140
|
thumbnailUrl: s,
|
|
141
|
-
mimeType:
|
|
142
|
-
title:
|
|
141
|
+
mimeType: t,
|
|
142
|
+
title: n,
|
|
143
143
|
LockIcon: p
|
|
144
144
|
},
|
|
145
145
|
l == null ? void 0 : l.sourceUrl
|
|
146
|
-
) :
|
|
147
|
-
|
|
146
|
+
) : N === "document" ? f = /* @__PURE__ */ e(
|
|
147
|
+
x,
|
|
148
148
|
{
|
|
149
149
|
thumbnailUrl: s,
|
|
150
|
-
mimeType:
|
|
150
|
+
mimeType: t,
|
|
151
151
|
LockIcon: p
|
|
152
152
|
},
|
|
153
153
|
l == null ? void 0 : l.sourceUrl
|
|
154
154
|
) : f = /* @__PURE__ */ e(
|
|
155
|
-
|
|
155
|
+
F,
|
|
156
156
|
{
|
|
157
157
|
sourceUrl: l == null ? void 0 : l.sourceUrl,
|
|
158
158
|
thumbnailUrl: s,
|
|
159
|
-
mimeType:
|
|
159
|
+
mimeType: t,
|
|
160
160
|
LockIcon: p
|
|
161
161
|
},
|
|
162
162
|
l == null ? void 0 : l.sourceUrl
|
|
163
|
-
), /* @__PURE__ */
|
|
163
|
+
), /* @__PURE__ */ c("div", { className: "w-[280px] select-none overflow-hidden rounded-[24px] bg-white shadow-[0_0_0_1px_rgba(0,0,0,0.04),0_4px_8px_rgba(0,0,0,0.06)]", children: [
|
|
164
164
|
f,
|
|
165
|
-
/* @__PURE__ */
|
|
166
|
-
/* @__PURE__ */ e("p", { className: "mb-1.5 truncate text-base font-medium text-black", children:
|
|
167
|
-
/* @__PURE__ */
|
|
168
|
-
|
|
165
|
+
/* @__PURE__ */ c("div", { className: "px-4 pb-3 pt-3", children: [
|
|
166
|
+
/* @__PURE__ */ e("p", { className: "mb-1.5 truncate text-base font-medium text-black", children: n }),
|
|
167
|
+
/* @__PURE__ */ c("div", { className: "flex items-center gap-1", children: [
|
|
168
|
+
_(t, {
|
|
169
169
|
className: "size-5 shrink-0 text-black/55",
|
|
170
170
|
weight: "regular"
|
|
171
171
|
}),
|
|
172
|
-
|
|
173
|
-
d === "paid" ? /* @__PURE__ */
|
|
172
|
+
i != null ? /* @__PURE__ */ e("span", { className: "text-xs font-medium text-black/55", children: i }) : null,
|
|
173
|
+
d === "paid" ? /* @__PURE__ */ c(y, { children: [
|
|
174
174
|
/* @__PURE__ */ e("span", { className: "text-xs font-medium text-black/55", children: "•" }),
|
|
175
175
|
/* @__PURE__ */ e("span", { className: "text-xs font-medium text-[#008236]", children: "Purchased" }),
|
|
176
176
|
/* @__PURE__ */ e(
|
|
@@ -180,19 +180,19 @@ const Q = ({
|
|
|
180
180
|
weight: "bold"
|
|
181
181
|
}
|
|
182
182
|
)
|
|
183
|
-
] }) :
|
|
183
|
+
] }) : r != null ? /* @__PURE__ */ c(y, { children: [
|
|
184
184
|
/* @__PURE__ */ e("span", { className: "text-xs font-medium text-black/55", children: "•" }),
|
|
185
|
-
/* @__PURE__ */ e("span", { className: "text-xs font-medium text-black/55", children:
|
|
185
|
+
/* @__PURE__ */ e("span", { className: "text-xs font-medium text-black/55", children: r })
|
|
186
186
|
] }) : null
|
|
187
187
|
] }),
|
|
188
188
|
/* @__PURE__ */ e(
|
|
189
|
-
|
|
189
|
+
V,
|
|
190
190
|
{
|
|
191
|
-
isLocked:
|
|
192
|
-
isUnlocking:
|
|
191
|
+
isLocked: k,
|
|
192
|
+
isUnlocking: j,
|
|
193
193
|
sourceUrl: l == null ? void 0 : l.sourceUrl,
|
|
194
194
|
redeemUrl: l == null ? void 0 : l.redeemUrl,
|
|
195
|
-
onUnlockClicked:
|
|
195
|
+
onUnlockClicked: P,
|
|
196
196
|
onDownloadClicked: h
|
|
197
197
|
}
|
|
198
198
|
)
|
|
@@ -200,6 +200,6 @@ const Q = ({
|
|
|
200
200
|
] });
|
|
201
201
|
};
|
|
202
202
|
export {
|
|
203
|
-
|
|
203
|
+
S as default
|
|
204
204
|
};
|
|
205
|
-
//# sourceMappingURL=Card-
|
|
205
|
+
//# sourceMappingURL=Card-Cn2va-Qr.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Card-Cn2va-Qr.js","sources":["../src/components/LockedAttachment/components/Visitor/CardActions.tsx","../src/components/LockedAttachment/components/Visitor/CardThumbnailPreview.tsx","../src/components/LockedAttachment/components/Visitor/CardImagePreview.tsx","../src/components/LockedAttachment/components/Visitor/CardMediaPreview.tsx","../src/components/LockedAttachment/components/Visitor/Card.tsx"],"sourcesContent":["import { DownloadSimpleIcon, LockSimpleIcon } from '@phosphor-icons/react'\nimport React from 'react'\n\ninterface CardActionsProps {\n isLocked: boolean\n isUnlocking?: boolean\n sourceUrl?: string\n redeemUrl?: string\n onUnlockClicked?: () => void\n onDownloadClicked?: () => void\n}\n\nconst CardActions: React.FC<CardActionsProps> = (props) => {\n const {\n isLocked,\n isUnlocking = false,\n sourceUrl,\n redeemUrl,\n onUnlockClicked,\n onDownloadClicked,\n } = props\n\n if (isLocked && onUnlockClicked != null) {\n return (\n <button\n type=\"button\"\n onClick={onUnlockClicked}\n disabled={isUnlocking}\n className=\"mt-3 inline-flex h-10 w-full items-center justify-center gap-2 rounded-full bg-[#121110] px-4 text-sm font-medium leading-none text-white hover:bg-[#2a2928] disabled:opacity-70\"\n >\n {isUnlocking ? (\n <LoadingDots />\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 && sourceUrl != null) {\n return (\n <a\n href={redeemUrl ?? sourceUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n onClick={onDownloadClicked}\n className=\"mt-3 inline-flex h-10 w-full items-center justify-center gap-2 rounded-full bg-[#121110] px-4 text-sm font-medium leading-none !text-white hover:bg-[#2a2928]\"\n >\n <DownloadSimpleIcon className=\"size-4\" weight=\"bold\" />\n Download\n </a>\n )\n }\n\n return null\n}\n\nconst LoadingDots: React.FC = () => {\n return (\n <span className=\"flex items-center gap-1\">\n <span className=\"size-1 rounded-full bg-white animate-bounce [animation-delay:-0.3s]\" />\n <span className=\"size-1 rounded-full bg-white animate-bounce [animation-delay:-0.15s]\" />\n <span className=\"size-1 rounded-full bg-white animate-bounce\" />\n </span>\n )\n}\n\nexport default CardActions\n","import React from 'react'\n\nimport { renderTypeIcon } from '../../utils/icons'\n\ninterface ThumbnailPreviewProps {\n thumbnailUrl?: string\n mimeType: string\n LockIcon?: React.ElementType\n}\n\nconst ThumbnailPreview: React.FC<ThumbnailPreviewProps> = (props) => {\n const { thumbnailUrl, mimeType, LockIcon } = props\n\n return (\n <div className=\"relative aspect-video overflow-hidden bg-black/5\">\n {thumbnailUrl != null ? (\n <img\n src={thumbnailUrl}\n alt=\"\"\n className=\"absolute inset-0 h-full w-full object-cover\"\n />\n ) : (\n <div className=\"absolute inset-0 flex items-center justify-center\">\n {renderTypeIcon(mimeType, {\n className: 'size-12 text-black/20',\n weight: 'regular',\n })}\n </div>\n )}\n {LockIcon != null ? <LockOverlay icon={LockIcon} /> : null}\n </div>\n )\n}\n\nconst LockOverlay: React.FC<{ icon: React.ElementType }> = ({ icon: Icon }) => {\n return (\n <div className=\"absolute inset-0 bg-black/30\">\n <div className=\"absolute left-3 top-3 flex size-8 items-center justify-center rounded-full bg-black/60\">\n <Icon className=\"size-4 text-white\" weight=\"fill\" />\n </div>\n </div>\n )\n}\n\nexport default ThumbnailPreview\n","import React, { useState } from 'react'\n\nimport ThumbnailPreview from './CardThumbnailPreview'\n\ninterface ImagePreviewProps {\n sourceUrl?: string\n thumbnailUrl?: string\n mimeType: string\n title?: string\n LockIcon?: React.ElementType\n}\n\nconst ImagePreview: React.FC<ImagePreviewProps> = (props) => {\n const { sourceUrl, thumbnailUrl, mimeType, title, LockIcon } = props\n const [sourceReady, setSourceReady] = useState(false)\n\n if (LockIcon != null) {\n return (\n <ThumbnailPreview\n thumbnailUrl={thumbnailUrl}\n mimeType={mimeType}\n LockIcon={LockIcon}\n />\n )\n }\n\n return (\n <div className=\"relative overflow-hidden bg-black/5\">\n <img\n src={sourceUrl}\n alt={title}\n className={`block w-full transition-opacity duration-300 ${sourceReady ? 'opacity-100' : 'opacity-0'}`}\n onLoad={() => setSourceReady(true)}\n />\n </div>\n )\n}\n\nexport default ImagePreview\n","import React from 'react'\n\nimport MediaPlayer from '../MediaPlayer'\n\nimport ThumbnailPreview from './CardThumbnailPreview'\n\ninterface MediaPreviewProps {\n sourceUrl?: string\n thumbnailUrl?: string\n mimeType: string\n LockIcon?: React.ElementType\n}\n\nconst MediaPreview: React.FC<MediaPreviewProps> = (props) => {\n const { sourceUrl, thumbnailUrl, mimeType, LockIcon } = props\n\n if (LockIcon != null) {\n return (\n <ThumbnailPreview\n thumbnailUrl={thumbnailUrl}\n mimeType={mimeType}\n LockIcon={LockIcon}\n />\n )\n }\n\n return (\n <MediaPlayer\n source={sourceUrl ?? ''}\n mimeType={mimeType}\n poster={thumbnailUrl}\n />\n )\n}\n\nexport default MediaPreview\n","import {\n CheckCircleIcon,\n LockOpenIcon,\n LockSimpleIcon,\n} from '@phosphor-icons/react'\nimport React, { useCallback, useEffect, useRef, useState } from 'react'\n\nimport type {\n LockedAttachmentBaseProps,\n LockedAttachmentSource,\n PaymentStatus,\n} from '../../types'\nimport { renderTypeIcon } from '../../utils/icons'\nimport { getSourceType } from '../../utils/mimeType'\n\nimport CardActions from './CardActions'\nimport ImagePreview from './CardImagePreview'\nimport MediaPreview from './CardMediaPreview'\nimport ThumbnailPreview from './CardThumbnailPreview'\n\nexport interface VisitorCardProps extends LockedAttachmentBaseProps {\n /**\n * Called when the visitor 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 to\n * unlock the card.\n */\n onFetchSource?: () => Promise<LockedAttachmentSource | void>\n /**\n * Called when the visitor clicks Download on an unlocked card.\n * Omit to hide the Download button.\n */\n onDownloadClick?: () => void\n /**\n * When true, shows loading dots on the Unlock button.\n * Driven by the LockedAttachmentContext (e.g. checkout in progress, payment processing).\n */\n isUnlocking?: boolean\n}\n\nfunction getLockIcon(paymentStatus?: PaymentStatus): React.ElementType {\n return paymentStatus === 'paid' ? LockOpenIcon : LockSimpleIcon\n}\n\nconst VisitorCard: React.FC<VisitorCardProps> = ({\n title,\n amountText,\n thumbnailUrl,\n mimeType = 'application/octet-stream',\n detail,\n onUnlockClick,\n onFetchSource,\n onDownloadClick,\n paymentStatus,\n isUnlocking = false,\n}) => {\n const [source, setSource] = useState<LockedAttachmentSource | undefined>()\n const hasMounted = useRef(false)\n const fetchingRef = useRef(false)\n // Stable ref so fetchSource doesn't change identity when onFetchSource prop changes\n const onFetchSourceRef = useRef(onFetchSource)\n onFetchSourceRef.current = onFetchSource\n\n const isLocked = source === undefined\n const sourceType = getSourceType(mimeType)\n const LockIcon = isLocked ? getLockIcon(paymentStatus) : undefined\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 }, []) // stable — reads onFetchSource via ref\n\n // When paymentStatus transitions to 'paid' (e.g. after checkout completes),\n // automatically fetch the source. Skipped on mount.\n useEffect(() => {\n if (!hasMounted.current) {\n hasMounted.current = true\n return\n }\n\n if (paymentStatus === 'paid') {\n void fetchSource()\n }\n }, [paymentStatus, fetchSource])\n\n const handleUnlockClick = useCallback(() => {\n if (paymentStatus === 'paid') {\n void fetchSource()\n } else {\n onUnlockClick?.()\n }\n }, [paymentStatus, onUnlockClick, fetchSource])\n\n let mediaPreview: React.ReactNode\n if (sourceType === 'image') {\n mediaPreview = (\n <ImagePreview\n key={source?.sourceUrl}\n sourceUrl={source?.sourceUrl}\n thumbnailUrl={thumbnailUrl}\n mimeType={mimeType}\n title={title}\n LockIcon={LockIcon}\n />\n )\n } else if (sourceType === 'document') {\n mediaPreview = (\n <ThumbnailPreview\n key={source?.sourceUrl}\n thumbnailUrl={thumbnailUrl}\n mimeType={mimeType}\n LockIcon={LockIcon}\n />\n )\n } else {\n mediaPreview = (\n <MediaPreview\n key={source?.sourceUrl}\n sourceUrl={source?.sourceUrl}\n thumbnailUrl={thumbnailUrl}\n mimeType={mimeType}\n LockIcon={LockIcon}\n />\n )\n }\n\n return (\n <div className=\"w-[280px] select-none overflow-hidden rounded-[24px] bg-white shadow-[0_0_0_1px_rgba(0,0,0,0.04),0_4px_8px_rgba(0,0,0,0.06)]\">\n {mediaPreview}\n <div className=\"px-4 pb-3 pt-3\">\n <p className=\"mb-1.5 truncate text-base font-medium text-black\">\n {title}\n </p>\n <div className=\"flex items-center gap-1\">\n {renderTypeIcon(mimeType, {\n className: 'size-5 shrink-0 text-black/55',\n weight: 'regular',\n })}\n {detail != null ? (\n <span className=\"text-xs font-medium text-black/55\">{detail}</span>\n ) : null}\n {paymentStatus === 'paid' ? (\n <>\n <span className=\"text-xs font-medium text-black/55\">•</span>\n <span className=\"text-xs font-medium text-[#008236]\">\n Purchased\n </span>\n <CheckCircleIcon\n className=\"size-4 text-[#008236]\"\n weight=\"bold\"\n />\n </>\n ) : amountText != null ? (\n <>\n <span className=\"text-xs font-medium text-black/55\">•</span>\n <span className=\"text-xs font-medium text-black/55\">\n {amountText}\n </span>\n </>\n ) : null}\n </div>\n <CardActions\n isLocked={isLocked}\n isUnlocking={isUnlocking}\n sourceUrl={source?.sourceUrl}\n redeemUrl={source?.redeemUrl}\n onUnlockClicked={handleUnlockClick}\n onDownloadClicked={onDownloadClick}\n />\n </div>\n </div>\n )\n}\n\nexport default VisitorCard\n"],"names":["CardActions","props","isLocked","isUnlocking","sourceUrl","redeemUrl","onUnlockClicked","onDownloadClicked","jsx","LoadingDots","jsxs","React","LockSimpleIcon","DownloadSimpleIcon","ThumbnailPreview","thumbnailUrl","mimeType","LockIcon","LockOverlay","Icon","ImagePreview","title","sourceReady","setSourceReady","useState","MediaPreview","MediaPlayer","getLockIcon","paymentStatus","LockOpenIcon","VisitorCard","amountText","detail","onUnlockClick","onFetchSource","onDownloadClick","source","setSource","hasMounted","useRef","fetchingRef","onFetchSourceRef","sourceType","getSourceType","fetchSource","useCallback","result","_a","useEffect","handleUnlockClick","mediaPreview","renderTypeIcon","Fragment","CheckCircleIcon"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -835,7 +835,7 @@ function ws(t) {
|
|
|
835
835
|
}, [s, n == null ? void 0 : n.userID, t.id, o]);
|
|
836
836
|
return { selected: o, voteUp: l, voteDown: m };
|
|
837
837
|
}
|
|
838
|
-
const _s = U.lazy(() => import("./Card-C5t3dZ5q.js")), Es = U.lazy(() => import("./Card-
|
|
838
|
+
const _s = U.lazy(() => import("./Card-C5t3dZ5q.js")), Es = U.lazy(() => import("./Card-Cn2va-Qr.js")), mt = () => /* @__PURE__ */ e(
|
|
839
839
|
"div",
|
|
840
840
|
{
|
|
841
841
|
className: "w-[280px] min-h-[200px] animate-pulse rounded-[24px] bg-black/[0.06] shadow-[0_0_0_1px_rgba(0,0,0,0.04),0_4px_8px_rgba(0,0,0,0.06)]",
|
package/package.json
CHANGED
|
@@ -72,11 +72,9 @@ const VisitorCard: React.FC<VisitorCardProps> = ({
|
|
|
72
72
|
|
|
73
73
|
const fetchSource = useCallback(async (): Promise<void> => {
|
|
74
74
|
if (fetchingRef.current) return
|
|
75
|
-
console.log('[LOCKED ATTACHMENT] fetchSource: starting fetch')
|
|
76
75
|
fetchingRef.current = true
|
|
77
76
|
try {
|
|
78
77
|
const result = await onFetchSourceRef.current?.()
|
|
79
|
-
console.log('[LOCKED ATTACHMENT] fetchSource: result received', { hasResult: Boolean(result) })
|
|
80
78
|
if (result) setSource(result)
|
|
81
79
|
} finally {
|
|
82
80
|
fetchingRef.current = false
|
|
@@ -91,19 +89,15 @@ const VisitorCard: React.FC<VisitorCardProps> = ({
|
|
|
91
89
|
return
|
|
92
90
|
}
|
|
93
91
|
|
|
94
|
-
console.log('[LOCKED ATTACHMENT] paymentStatus changed', { paymentStatus })
|
|
95
92
|
if (paymentStatus === 'paid') {
|
|
96
|
-
console.log('[LOCKED ATTACHMENT] paymentStatus=paid: auto-fetching source')
|
|
97
93
|
void fetchSource()
|
|
98
94
|
}
|
|
99
95
|
}, [paymentStatus, fetchSource])
|
|
100
96
|
|
|
101
97
|
const handleUnlockClick = useCallback(() => {
|
|
102
98
|
if (paymentStatus === 'paid') {
|
|
103
|
-
console.log('[LOCKED ATTACHMENT] handleUnlockClick: already paid, fetching source')
|
|
104
99
|
void fetchSource()
|
|
105
100
|
} else {
|
|
106
|
-
console.log('[LOCKED ATTACHMENT] handleUnlockClick: not paid, opening checkout')
|
|
107
101
|
onUnlockClick?.()
|
|
108
102
|
}
|
|
109
103
|
}, [paymentStatus, onUnlockClick, fetchSource])
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Card-B1gJkHn-.js","sources":["../src/components/LockedAttachment/components/Visitor/CardActions.tsx","../src/components/LockedAttachment/components/Visitor/CardThumbnailPreview.tsx","../src/components/LockedAttachment/components/Visitor/CardImagePreview.tsx","../src/components/LockedAttachment/components/Visitor/CardMediaPreview.tsx","../src/components/LockedAttachment/components/Visitor/Card.tsx"],"sourcesContent":["import { DownloadSimpleIcon, LockSimpleIcon } from '@phosphor-icons/react'\nimport React from 'react'\n\ninterface CardActionsProps {\n isLocked: boolean\n isUnlocking?: boolean\n sourceUrl?: string\n redeemUrl?: string\n onUnlockClicked?: () => void\n onDownloadClicked?: () => void\n}\n\nconst CardActions: React.FC<CardActionsProps> = (props) => {\n const {\n isLocked,\n isUnlocking = false,\n sourceUrl,\n redeemUrl,\n onUnlockClicked,\n onDownloadClicked,\n } = props\n\n if (isLocked && onUnlockClicked != null) {\n return (\n <button\n type=\"button\"\n onClick={onUnlockClicked}\n disabled={isUnlocking}\n className=\"mt-3 inline-flex h-10 w-full items-center justify-center gap-2 rounded-full bg-[#121110] px-4 text-sm font-medium leading-none text-white hover:bg-[#2a2928] disabled:opacity-70\"\n >\n {isUnlocking ? (\n <LoadingDots />\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 && sourceUrl != null) {\n return (\n <a\n href={redeemUrl ?? sourceUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n onClick={onDownloadClicked}\n className=\"mt-3 inline-flex h-10 w-full items-center justify-center gap-2 rounded-full bg-[#121110] px-4 text-sm font-medium leading-none !text-white hover:bg-[#2a2928]\"\n >\n <DownloadSimpleIcon className=\"size-4\" weight=\"bold\" />\n Download\n </a>\n )\n }\n\n return null\n}\n\nconst LoadingDots: React.FC = () => {\n return (\n <span className=\"flex items-center gap-1\">\n <span className=\"size-1 rounded-full bg-white animate-bounce [animation-delay:-0.3s]\" />\n <span className=\"size-1 rounded-full bg-white animate-bounce [animation-delay:-0.15s]\" />\n <span className=\"size-1 rounded-full bg-white animate-bounce\" />\n </span>\n )\n}\n\nexport default CardActions\n","import React from 'react'\n\nimport { renderTypeIcon } from '../../utils/icons'\n\ninterface ThumbnailPreviewProps {\n thumbnailUrl?: string\n mimeType: string\n LockIcon?: React.ElementType\n}\n\nconst ThumbnailPreview: React.FC<ThumbnailPreviewProps> = (props) => {\n const { thumbnailUrl, mimeType, LockIcon } = props\n\n return (\n <div className=\"relative aspect-video overflow-hidden bg-black/5\">\n {thumbnailUrl != null ? (\n <img\n src={thumbnailUrl}\n alt=\"\"\n className=\"absolute inset-0 h-full w-full object-cover\"\n />\n ) : (\n <div className=\"absolute inset-0 flex items-center justify-center\">\n {renderTypeIcon(mimeType, {\n className: 'size-12 text-black/20',\n weight: 'regular',\n })}\n </div>\n )}\n {LockIcon != null ? <LockOverlay icon={LockIcon} /> : null}\n </div>\n )\n}\n\nconst LockOverlay: React.FC<{ icon: React.ElementType }> = ({ icon: Icon }) => {\n return (\n <div className=\"absolute inset-0 bg-black/30\">\n <div className=\"absolute left-3 top-3 flex size-8 items-center justify-center rounded-full bg-black/60\">\n <Icon className=\"size-4 text-white\" weight=\"fill\" />\n </div>\n </div>\n )\n}\n\nexport default ThumbnailPreview\n","import React, { useState } from 'react'\n\nimport ThumbnailPreview from './CardThumbnailPreview'\n\ninterface ImagePreviewProps {\n sourceUrl?: string\n thumbnailUrl?: string\n mimeType: string\n title?: string\n LockIcon?: React.ElementType\n}\n\nconst ImagePreview: React.FC<ImagePreviewProps> = (props) => {\n const { sourceUrl, thumbnailUrl, mimeType, title, LockIcon } = props\n const [sourceReady, setSourceReady] = useState(false)\n\n if (LockIcon != null) {\n return (\n <ThumbnailPreview\n thumbnailUrl={thumbnailUrl}\n mimeType={mimeType}\n LockIcon={LockIcon}\n />\n )\n }\n\n return (\n <div className=\"relative overflow-hidden bg-black/5\">\n <img\n src={sourceUrl}\n alt={title}\n className={`block w-full transition-opacity duration-300 ${sourceReady ? 'opacity-100' : 'opacity-0'}`}\n onLoad={() => setSourceReady(true)}\n />\n </div>\n )\n}\n\nexport default ImagePreview\n","import React from 'react'\n\nimport MediaPlayer from '../MediaPlayer'\n\nimport ThumbnailPreview from './CardThumbnailPreview'\n\ninterface MediaPreviewProps {\n sourceUrl?: string\n thumbnailUrl?: string\n mimeType: string\n LockIcon?: React.ElementType\n}\n\nconst MediaPreview: React.FC<MediaPreviewProps> = (props) => {\n const { sourceUrl, thumbnailUrl, mimeType, LockIcon } = props\n\n if (LockIcon != null) {\n return (\n <ThumbnailPreview\n thumbnailUrl={thumbnailUrl}\n mimeType={mimeType}\n LockIcon={LockIcon}\n />\n )\n }\n\n return (\n <MediaPlayer\n source={sourceUrl ?? ''}\n mimeType={mimeType}\n poster={thumbnailUrl}\n />\n )\n}\n\nexport default MediaPreview\n","import {\n CheckCircleIcon,\n LockOpenIcon,\n LockSimpleIcon,\n} from '@phosphor-icons/react'\nimport React, { useCallback, useEffect, useRef, useState } from 'react'\n\nimport type {\n LockedAttachmentBaseProps,\n LockedAttachmentSource,\n PaymentStatus,\n} from '../../types'\nimport { renderTypeIcon } from '../../utils/icons'\nimport { getSourceType } from '../../utils/mimeType'\n\nimport CardActions from './CardActions'\nimport ImagePreview from './CardImagePreview'\nimport MediaPreview from './CardMediaPreview'\nimport ThumbnailPreview from './CardThumbnailPreview'\n\nexport interface VisitorCardProps extends LockedAttachmentBaseProps {\n /**\n * Called when the visitor 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 to\n * unlock the card.\n */\n onFetchSource?: () => Promise<LockedAttachmentSource | void>\n /**\n * Called when the visitor clicks Download on an unlocked card.\n * Omit to hide the Download button.\n */\n onDownloadClick?: () => void\n /**\n * When true, shows loading dots on the Unlock button.\n * Driven by the LockedAttachmentContext (e.g. checkout in progress, payment processing).\n */\n isUnlocking?: boolean\n}\n\nfunction getLockIcon(paymentStatus?: PaymentStatus): React.ElementType {\n return paymentStatus === 'paid' ? LockOpenIcon : LockSimpleIcon\n}\n\nconst VisitorCard: React.FC<VisitorCardProps> = ({\n title,\n amountText,\n thumbnailUrl,\n mimeType = 'application/octet-stream',\n detail,\n onUnlockClick,\n onFetchSource,\n onDownloadClick,\n paymentStatus,\n isUnlocking = false,\n}) => {\n const [source, setSource] = useState<LockedAttachmentSource | undefined>()\n const hasMounted = useRef(false)\n const fetchingRef = useRef(false)\n // Stable ref so fetchSource doesn't change identity when onFetchSource prop changes\n const onFetchSourceRef = useRef(onFetchSource)\n onFetchSourceRef.current = onFetchSource\n\n const isLocked = source === undefined\n const sourceType = getSourceType(mimeType)\n const LockIcon = isLocked ? getLockIcon(paymentStatus) : undefined\n\n const fetchSource = useCallback(async (): Promise<void> => {\n if (fetchingRef.current) return\n console.log('[LOCKED ATTACHMENT] fetchSource: starting fetch')\n fetchingRef.current = true\n try {\n const result = await onFetchSourceRef.current?.()\n console.log('[LOCKED ATTACHMENT] fetchSource: result received', { hasResult: Boolean(result) })\n if (result) setSource(result)\n } finally {\n fetchingRef.current = false\n }\n }, []) // stable — reads onFetchSource via ref\n\n // When paymentStatus transitions to 'paid' (e.g. after checkout completes),\n // automatically fetch the source. Skipped on mount.\n useEffect(() => {\n if (!hasMounted.current) {\n hasMounted.current = true\n return\n }\n\n console.log('[LOCKED ATTACHMENT] paymentStatus changed', { paymentStatus })\n if (paymentStatus === 'paid') {\n console.log('[LOCKED ATTACHMENT] paymentStatus=paid: auto-fetching source')\n void fetchSource()\n }\n }, [paymentStatus, fetchSource])\n\n const handleUnlockClick = useCallback(() => {\n if (paymentStatus === 'paid') {\n console.log('[LOCKED ATTACHMENT] handleUnlockClick: already paid, fetching source')\n void fetchSource()\n } else {\n console.log('[LOCKED ATTACHMENT] handleUnlockClick: not paid, opening checkout')\n onUnlockClick?.()\n }\n }, [paymentStatus, onUnlockClick, fetchSource])\n\n let mediaPreview: React.ReactNode\n if (sourceType === 'image') {\n mediaPreview = (\n <ImagePreview\n key={source?.sourceUrl}\n sourceUrl={source?.sourceUrl}\n thumbnailUrl={thumbnailUrl}\n mimeType={mimeType}\n title={title}\n LockIcon={LockIcon}\n />\n )\n } else if (sourceType === 'document') {\n mediaPreview = (\n <ThumbnailPreview\n key={source?.sourceUrl}\n thumbnailUrl={thumbnailUrl}\n mimeType={mimeType}\n LockIcon={LockIcon}\n />\n )\n } else {\n mediaPreview = (\n <MediaPreview\n key={source?.sourceUrl}\n sourceUrl={source?.sourceUrl}\n thumbnailUrl={thumbnailUrl}\n mimeType={mimeType}\n LockIcon={LockIcon}\n />\n )\n }\n\n return (\n <div className=\"w-[280px] select-none overflow-hidden rounded-[24px] bg-white shadow-[0_0_0_1px_rgba(0,0,0,0.04),0_4px_8px_rgba(0,0,0,0.06)]\">\n {mediaPreview}\n <div className=\"px-4 pb-3 pt-3\">\n <p className=\"mb-1.5 truncate text-base font-medium text-black\">\n {title}\n </p>\n <div className=\"flex items-center gap-1\">\n {renderTypeIcon(mimeType, {\n className: 'size-5 shrink-0 text-black/55',\n weight: 'regular',\n })}\n {detail != null ? (\n <span className=\"text-xs font-medium text-black/55\">{detail}</span>\n ) : null}\n {paymentStatus === 'paid' ? (\n <>\n <span className=\"text-xs font-medium text-black/55\">•</span>\n <span className=\"text-xs font-medium text-[#008236]\">\n Purchased\n </span>\n <CheckCircleIcon\n className=\"size-4 text-[#008236]\"\n weight=\"bold\"\n />\n </>\n ) : amountText != null ? (\n <>\n <span className=\"text-xs font-medium text-black/55\">•</span>\n <span className=\"text-xs font-medium text-black/55\">\n {amountText}\n </span>\n </>\n ) : null}\n </div>\n <CardActions\n isLocked={isLocked}\n isUnlocking={isUnlocking}\n sourceUrl={source?.sourceUrl}\n redeemUrl={source?.redeemUrl}\n onUnlockClicked={handleUnlockClick}\n onDownloadClicked={onDownloadClick}\n />\n </div>\n </div>\n )\n}\n\nexport default VisitorCard\n"],"names":["CardActions","props","isLocked","isUnlocking","sourceUrl","redeemUrl","onUnlockClicked","onDownloadClicked","jsx","LoadingDots","jsxs","React","LockSimpleIcon","DownloadSimpleIcon","ThumbnailPreview","thumbnailUrl","mimeType","LockIcon","LockOverlay","Icon","ImagePreview","title","sourceReady","setSourceReady","useState","MediaPreview","MediaPlayer","getLockIcon","paymentStatus","LockOpenIcon","VisitorCard","amountText","detail","onUnlockClick","onFetchSource","onDownloadClick","source","setSource","hasMounted","useRef","fetchingRef","onFetchSourceRef","sourceType","getSourceType","fetchSource","useCallback","result","_a","useEffect","handleUnlockClick","mediaPreview","renderTypeIcon","Fragment","CheckCircleIcon"],"mappings":";;;;AAYA,MAAMA,IAA0C,CAACC,MAAU;AACzD,QAAM;AAAA,IACJ,UAAAC;AAAA,IACA,aAAAC,IAAc;AAAA,IACd,WAAAC;AAAA,IACA,WAAAC;AAAA,IACA,iBAAAC;AAAA,IACA,mBAAAC;AAAA,EAAA,IACEN;AAEJ,SAAIC,KAAYI,KAAmB,OAE/B,gBAAAE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAK;AAAA,MACL,SAASF;AAAA,MACT,UAAUH;AAAA,MACV,WAAU;AAAA,MAET,cACC,gBAAAK,EAACC,GAAA,CAAA,CAAY,IAEb,gBAAAC,EAACC,EAAM,UAAN,EACC,UAAA;AAAA,QAAA,gBAAAH,EAACI,GAAA,EAAe,WAAU,UAAS,QAAO,QAAO;AAAA,QAAE;AAAA,MAAA,EAAA,CAErD;AAAA,IAAA;AAAA,EAAA,IAMJ,CAACV,KAAYK,KAAqB,QAAQH,KAAa,OAEvD,gBAAAM;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAML,KAAaD;AAAA,MACnB,QAAO;AAAA,MACP,KAAI;AAAA,MACJ,SAASG;AAAA,MACT,WAAU;AAAA,MAEV,UAAA;AAAA,QAAA,gBAAAC,EAACK,GAAA,EAAmB,WAAU,UAAS,QAAO,QAAO;AAAA,QAAE;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA,IAMtD;AACT,GAEMJ,IAAwB,MAE1B,gBAAAC,EAAC,QAAA,EAAK,WAAU,2BACd,UAAA;AAAA,EAAA,gBAAAF,EAAC,QAAA,EAAK,WAAU,sEAAA,CAAsE;AAAA,EACtF,gBAAAA,EAAC,QAAA,EAAK,WAAU,uEAAA,CAAuE;AAAA,EACvF,gBAAAA,EAAC,QAAA,EAAK,WAAU,8CAAA,CAA8C;AAAA,GAChE,GCxDEM,IAAoD,CAACb,MAAU;AACnE,QAAM,EAAE,cAAAc,GAAc,UAAAC,GAAU,UAAAC,EAAA,IAAahB;AAE7C,SACE,gBAAAS,EAAC,OAAA,EAAI,WAAU,oDACZ,UAAA;AAAA,IAAAK,KAAgB,OACf,gBAAAP;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,KAAKO;AAAA,QACL,KAAI;AAAA,QACJ,WAAU;AAAA,MAAA;AAAA,IAAA,IAGZ,gBAAAP,EAAC,OAAA,EAAI,WAAU,qDACZ,YAAeQ,GAAU;AAAA,MACxB,WAAW;AAAA,MACX,QAAQ;AAAA,IAAA,CACT,GACH;AAAA,IAEDC,KAAY,OAAO,gBAAAT,EAACU,GAAA,EAAY,MAAMD,GAAU,IAAK;AAAA,EAAA,GACxD;AAEJ,GAEMC,IAAqD,CAAC,EAAE,MAAMC,QAEhE,gBAAAX,EAAC,OAAA,EAAI,WAAU,gCACb,4BAAC,OAAA,EAAI,WAAU,0FACb,UAAA,gBAAAA,EAACW,KAAK,WAAU,qBAAoB,QAAO,OAAA,CAAO,GACpD,GACF,GC5BEC,IAA4C,CAACnB,MAAU;AAC3D,QAAM,EAAE,WAAAG,GAAW,cAAAW,GAAc,UAAAC,GAAU,OAAAK,GAAO,UAAAJ,MAAahB,GACzD,CAACqB,GAAaC,CAAc,IAAIC,EAAS,EAAK;AAEpD,SAAIP,KAAY,OAEZ,gBAAAT;AAAA,IAACM;AAAA,IAAA;AAAA,MACC,cAAAC;AAAA,MACA,UAAAC;AAAA,MACA,UAAAC;AAAA,IAAA;AAAA,EAAA,IAMJ,gBAAAT,EAAC,OAAA,EAAI,WAAU,uCACb,UAAA,gBAAAA;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAKJ;AAAA,MACL,KAAKiB;AAAA,MACL,WAAW,gDAAgDC,IAAc,gBAAgB,WAAW;AAAA,MACpG,QAAQ,MAAMC,EAAe,EAAI;AAAA,IAAA;AAAA,EAAA,GAErC;AAEJ,GCvBME,IAA4C,CAACxB,MAAU;AAC3D,QAAM,EAAE,WAAAG,GAAW,cAAAW,GAAc,UAAAC,GAAU,UAAAC,MAAahB;AAExD,SAAIgB,KAAY,OAEZ,gBAAAT;AAAA,IAACM;AAAA,IAAA;AAAA,MACC,cAAAC;AAAA,MACA,UAAAC;AAAA,MACA,UAAAC;AAAA,IAAA;AAAA,EAAA,IAMJ,gBAAAT;AAAA,IAACkB;AAAA,IAAA;AAAA,MACC,QAAQtB,KAAa;AAAA,MACrB,UAAAY;AAAA,MACA,QAAQD;AAAA,IAAA;AAAA,EAAA;AAGd;ACYA,SAASY,EAAYC,GAAkD;AACrE,SAAOA,MAAkB,SAASC,IAAejB;AACnD;AAEA,MAAMkB,IAA0C,CAAC;AAAA,EAC/C,OAAAT;AAAA,EACA,YAAAU;AAAA,EACA,cAAAhB;AAAA,EACA,UAAAC,IAAW;AAAA,EACX,QAAAgB;AAAA,EACA,eAAAC;AAAA,EACA,eAAAC;AAAA,EACA,iBAAAC;AAAA,EACA,eAAAP;AAAA,EACA,aAAAzB,IAAc;AAChB,MAAM;AACJ,QAAM,CAACiC,GAAQC,CAAS,IAAIb,EAAA,GACtBc,IAAaC,EAAO,EAAK,GACzBC,IAAcD,EAAO,EAAK,GAE1BE,IAAmBF,EAAOL,CAAa;AAC7C,EAAAO,EAAiB,UAAUP;AAE3B,QAAMhC,IAAWkC,MAAW,QACtBM,IAAaC,EAAc3B,CAAQ,GACnCC,IAAWf,IAAWyB,EAAYC,CAAa,IAAI,QAEnDgB,IAAcC,EAAY,YAA2B;;AACzD,QAAI,CAAAL,EAAY,SAChB;AAAA,cAAQ,IAAI,iDAAiD,GAC7DA,EAAY,UAAU;AACtB,UAAI;AACF,cAAMM,IAAS,QAAMC,IAAAN,EAAiB,YAAjB,gBAAAM,EAAA,KAAAN;AACrB,gBAAQ,IAAI,oDAAoD,EAAE,WAAW,EAAQK,GAAS,GAC1FA,OAAkBA,CAAM;AAAA,MAC9B,UAAA;AACE,QAAAN,EAAY,UAAU;AAAA,MACxB;AAAA;AAAA,EACF,GAAG,CAAA,CAAE;AAIL,EAAAQ,EAAU,MAAM;AACd,QAAI,CAACV,EAAW,SAAS;AACvB,MAAAA,EAAW,UAAU;AACrB;AAAA,IACF;AAEA,YAAQ,IAAI,6CAA6C,EAAE,eAAAV,EAAA,CAAe,GACtEA,MAAkB,WACpB,QAAQ,IAAI,8DAA8D,GACrEgB,EAAA;AAAA,EAET,GAAG,CAAChB,GAAegB,CAAW,CAAC;AAE/B,QAAMK,IAAoBJ,EAAY,MAAM;AAC1C,IAAIjB,MAAkB,UACpB,QAAQ,IAAI,sEAAsE,GAC7EgB,EAAA,MAEL,QAAQ,IAAI,mEAAmE,GAC/EX,KAAA,QAAAA;AAAA,EAEJ,GAAG,CAACL,GAAeK,GAAeW,CAAW,CAAC;AAE9C,MAAIM;AACJ,SAAIR,MAAe,UACjBQ,IACE,gBAAA1C;AAAA,IAACY;AAAA,IAAA;AAAA,MAEC,WAAWgB,KAAA,gBAAAA,EAAQ;AAAA,MACnB,cAAArB;AAAA,MACA,UAAAC;AAAA,MACA,OAAAK;AAAA,MACA,UAAAJ;AAAA,IAAA;AAAA,IALKmB,KAAA,gBAAAA,EAAQ;AAAA,EAAA,IAQRM,MAAe,aACxBQ,IACE,gBAAA1C;AAAA,IAACM;AAAA,IAAA;AAAA,MAEC,cAAAC;AAAA,MACA,UAAAC;AAAA,MACA,UAAAC;AAAA,IAAA;AAAA,IAHKmB,KAAA,gBAAAA,EAAQ;AAAA,EAAA,IAOjBc,IACE,gBAAA1C;AAAA,IAACiB;AAAA,IAAA;AAAA,MAEC,WAAWW,KAAA,gBAAAA,EAAQ;AAAA,MACnB,cAAArB;AAAA,MACA,UAAAC;AAAA,MACA,UAAAC;AAAA,IAAA;AAAA,IAJKmB,KAAA,gBAAAA,EAAQ;AAAA,EAAA,GAUjB,gBAAA1B,EAAC,OAAA,EAAI,WAAU,gIACZ,UAAA;AAAA,IAAAwC;AAAA,IACD,gBAAAxC,EAAC,OAAA,EAAI,WAAU,kBACb,UAAA;AAAA,MAAA,gBAAAF,EAAC,KAAA,EAAE,WAAU,oDACV,UAAAa,GACH;AAAA,MACA,gBAAAX,EAAC,OAAA,EAAI,WAAU,2BACZ,UAAA;AAAA,QAAAyC,EAAenC,GAAU;AAAA,UACxB,WAAW;AAAA,UACX,QAAQ;AAAA,QAAA,CACT;AAAA,QACAgB,KAAU,OACT,gBAAAxB,EAAC,UAAK,WAAU,qCAAqC,aAAO,IAC1D;AAAA,QACHoB,MAAkB,SACjB,gBAAAlB,EAAA0C,GAAA,EACE,UAAA;AAAA,UAAA,gBAAA5C,EAAC,QAAA,EAAK,WAAU,qCAAoC,UAAA,KAAC;AAAA,UACrD,gBAAAA,EAAC,QAAA,EAAK,WAAU,sCAAqC,UAAA,aAErD;AAAA,UACA,gBAAAA;AAAA,YAAC6C;AAAA,YAAA;AAAA,cACC,WAAU;AAAA,cACV,QAAO;AAAA,YAAA;AAAA,UAAA;AAAA,QACT,EAAA,CACF,IACEtB,KAAc,OAChB,gBAAArB,EAAA0C,GAAA,EACE,UAAA;AAAA,UAAA,gBAAA5C,EAAC,QAAA,EAAK,WAAU,qCAAoC,UAAA,KAAC;AAAA,UACrD,gBAAAA,EAAC,QAAA,EAAK,WAAU,qCACb,UAAAuB,EAAA,CACH;AAAA,QAAA,EAAA,CACF,IACE;AAAA,MAAA,GACN;AAAA,MACA,gBAAAvB;AAAA,QAACR;AAAA,QAAA;AAAA,UACC,UAAAE;AAAA,UACA,aAAAC;AAAA,UACA,WAAWiC,KAAA,gBAAAA,EAAQ;AAAA,UACnB,WAAWA,KAAA,gBAAAA,EAAQ;AAAA,UACnB,iBAAiBa;AAAA,UACjB,mBAAmBd;AAAA,QAAA;AAAA,MAAA;AAAA,IACrB,EAAA,CACF;AAAA,EAAA,GACF;AAEJ;"}
|