react-sharesheet 1.0.0 → 1.2.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.
- package/README.md +84 -102
- package/dist/content.d.mts +3 -3
- package/dist/content.d.ts +3 -3
- package/dist/content.js +296 -271
- package/dist/content.js.map +1 -1
- package/dist/content.mjs +298 -273
- package/dist/content.mjs.map +1 -1
- package/dist/drawer.d.mts +3 -3
- package/dist/drawer.d.ts +3 -3
- package/dist/drawer.js +298 -275
- package/dist/drawer.js.map +1 -1
- package/dist/drawer.mjs +300 -277
- package/dist/drawer.mjs.map +1 -1
- package/dist/headless-B7I228Dt.d.mts +98 -0
- package/dist/headless-BiSYHizs.d.ts +98 -0
- package/dist/headless.d.mts +3 -50
- package/dist/headless.d.ts +3 -50
- package/dist/headless.js +165 -0
- package/dist/headless.js.map +1 -1
- package/dist/headless.mjs +163 -1
- package/dist/headless.mjs.map +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +339 -277
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +329 -278
- package/dist/index.mjs.map +1 -1
- package/dist/{platforms-DU1DVDFq.d.mts → platforms-omqzPfYX.d.mts} +17 -23
- package/dist/{platforms-DU1DVDFq.d.ts → platforms-omqzPfYX.d.ts} +17 -23
- package/package.json +24 -7
- package/src/ShareSheetContent.tsx +157 -311
- package/src/ShareSheetDrawer.tsx +2 -4
- package/src/__tests__/hooks.test.ts +203 -0
- package/src/__tests__/og-fetcher.test.ts +144 -0
- package/src/__tests__/platforms.test.ts +148 -0
- package/src/__tests__/setup.ts +22 -0
- package/src/__tests__/share-functions.test.ts +152 -0
- package/src/__tests__/utils.test.ts +64 -0
- package/src/headless.ts +4 -1
- package/src/hooks.ts +60 -2
- package/src/index.ts +20 -4
- package/src/og-fetcher.ts +64 -0
- package/src/share-functions.ts +25 -1
- package/src/types.ts +17 -24
- package/src/utils.ts +125 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { useMemo, useState, useCallback } from "react";
|
|
4
|
-
import { Image,
|
|
4
|
+
import { Image, Link2 } from "lucide-react";
|
|
5
5
|
import { cn } from "./utils";
|
|
6
|
-
import { useShareSheet } from "./hooks";
|
|
6
|
+
import { useShareSheet, useOGData } from "./hooks";
|
|
7
7
|
import {
|
|
8
8
|
PLATFORM_IDS,
|
|
9
9
|
PLATFORM_COLORS,
|
|
@@ -17,49 +17,11 @@ import {
|
|
|
17
17
|
type ShareSheetContentProps,
|
|
18
18
|
type ShareOption,
|
|
19
19
|
type ShareButtonConfig,
|
|
20
|
-
type PreviewConfig,
|
|
21
|
-
type PreviewType,
|
|
22
20
|
} from "./types";
|
|
23
21
|
|
|
24
22
|
const DEFAULT_BUTTON_SIZE = 45;
|
|
25
23
|
const DEFAULT_ICON_SIZE = 22;
|
|
26
24
|
|
|
27
|
-
// File extension mappings
|
|
28
|
-
const IMAGE_EXTENSIONS = ["jpg", "jpeg", "png", "gif", "webp", "svg", "bmp", "ico", "avif"];
|
|
29
|
-
const VIDEO_EXTENSIONS = ["mp4", "webm", "mov", "avi", "mkv", "m4v", "ogv"];
|
|
30
|
-
const AUDIO_EXTENSIONS = ["mp3", "wav", "ogg", "m4a", "aac", "flac", "wma"];
|
|
31
|
-
|
|
32
|
-
// Detect content type from URL
|
|
33
|
-
function detectPreviewType(url: string): PreviewType {
|
|
34
|
-
try {
|
|
35
|
-
const pathname = new URL(url, "http://localhost").pathname;
|
|
36
|
-
const ext = pathname.split(".").pop()?.toLowerCase() || "";
|
|
37
|
-
|
|
38
|
-
if (IMAGE_EXTENSIONS.includes(ext)) return "image";
|
|
39
|
-
if (VIDEO_EXTENSIONS.includes(ext)) return "video";
|
|
40
|
-
if (AUDIO_EXTENSIONS.includes(ext)) return "audio";
|
|
41
|
-
|
|
42
|
-
// Check for common patterns
|
|
43
|
-
if (url.includes("/api/og") || url.includes("og-image")) return "image";
|
|
44
|
-
if (url.includes("youtube.com") || url.includes("vimeo.com")) return "video";
|
|
45
|
-
|
|
46
|
-
return "link";
|
|
47
|
-
} catch {
|
|
48
|
-
return "link";
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Get filename from URL
|
|
53
|
-
function getFilenameFromUrl(url: string): string {
|
|
54
|
-
try {
|
|
55
|
-
const pathname = new URL(url, "http://localhost").pathname;
|
|
56
|
-
const filename = pathname.split("/").pop() || "";
|
|
57
|
-
return decodeURIComponent(filename);
|
|
58
|
-
} catch {
|
|
59
|
-
return url;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
25
|
// Default class names
|
|
64
26
|
const defaultClasses = {
|
|
65
27
|
root: "max-w-md mx-auto",
|
|
@@ -69,12 +31,8 @@ const defaultClasses = {
|
|
|
69
31
|
preview: "flex justify-center mb-4 px-4",
|
|
70
32
|
previewSkeleton: "rounded-xl overflow-hidden",
|
|
71
33
|
previewImage: "",
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
previewFileIcon: "",
|
|
75
|
-
previewFilename: "truncate",
|
|
76
|
-
previewLink: "",
|
|
77
|
-
grid: "px-2 py-6 flex flex-row items-center gap-4 gap-y-6 flex-wrap justify-center",
|
|
34
|
+
previewMeta: "",
|
|
35
|
+
grid: "px-2 py-6 flex flex-row items-start gap-4 gap-y-6 flex-wrap justify-center",
|
|
78
36
|
button: "flex flex-col items-center gap-0 text-xs w-[60px] outline-none cursor-pointer group",
|
|
79
37
|
buttonIcon: "p-2 rounded-full transition-all flex items-center justify-center group-hover:scale-110 group-active:scale-95 mb-2",
|
|
80
38
|
buttonLabel: "",
|
|
@@ -93,34 +51,10 @@ function cssVar(name: string, fallback: string): string {
|
|
|
93
51
|
return `var(${name}, ${fallback})`;
|
|
94
52
|
}
|
|
95
53
|
|
|
96
|
-
// Normalize preview prop to PreviewConfig
|
|
97
|
-
function normalizePreview(preview: string | PreviewConfig | null | undefined): PreviewConfig | null {
|
|
98
|
-
if (!preview) return null;
|
|
99
|
-
|
|
100
|
-
if (typeof preview === "string") {
|
|
101
|
-
const type = detectPreviewType(preview);
|
|
102
|
-
return {
|
|
103
|
-
url: preview,
|
|
104
|
-
type,
|
|
105
|
-
filename: getFilenameFromUrl(preview),
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// It's already a config object
|
|
110
|
-
const type = preview.type === "auto" || !preview.type ? detectPreviewType(preview.url) : preview.type;
|
|
111
|
-
|
|
112
|
-
return {
|
|
113
|
-
...preview,
|
|
114
|
-
type,
|
|
115
|
-
filename: preview.filename || getFilenameFromUrl(preview.url),
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
|
|
119
54
|
export function ShareSheetContent({
|
|
120
55
|
title = "Share",
|
|
121
56
|
shareUrl,
|
|
122
57
|
shareText,
|
|
123
|
-
preview,
|
|
124
58
|
downloadUrl,
|
|
125
59
|
downloadFilename,
|
|
126
60
|
className,
|
|
@@ -135,19 +69,19 @@ export function ShareSheetContent({
|
|
|
135
69
|
labels = {},
|
|
136
70
|
icons = {},
|
|
137
71
|
}: ShareSheetContentProps) {
|
|
138
|
-
const [
|
|
139
|
-
const [
|
|
72
|
+
const [imageLoaded, setImageLoaded] = useState(false);
|
|
73
|
+
const [imageError, setImageError] = useState(false);
|
|
140
74
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
}, []);
|
|
75
|
+
// Fetch OG data automatically from shareUrl
|
|
76
|
+
const { ogData, loading: ogLoading } = useOGData(shareUrl);
|
|
144
77
|
|
|
145
|
-
const
|
|
146
|
-
|
|
78
|
+
const handleImageLoad = useCallback(() => {
|
|
79
|
+
setImageLoaded(true);
|
|
147
80
|
}, []);
|
|
148
81
|
|
|
149
|
-
|
|
150
|
-
|
|
82
|
+
const handleImageError = useCallback(() => {
|
|
83
|
+
setImageError(true);
|
|
84
|
+
}, []);
|
|
151
85
|
|
|
152
86
|
const shareSheet = useShareSheet({
|
|
153
87
|
shareUrl,
|
|
@@ -190,6 +124,18 @@ export function ShareSheetContent({
|
|
|
190
124
|
return PLATFORM_IDS.map((id) => {
|
|
191
125
|
const Icon = PLATFORM_ICONS[id];
|
|
192
126
|
const defaultLabel = dynamicLabels[id] ?? PLATFORM_LABELS[id];
|
|
127
|
+
const availability = shareSheet.platformAvailability[id];
|
|
128
|
+
|
|
129
|
+
// Determine if button should be shown based on various conditions
|
|
130
|
+
let condition = true;
|
|
131
|
+
if (id === "native") {
|
|
132
|
+
condition = shareSheet.canNativeShare;
|
|
133
|
+
} else if (id === "download") {
|
|
134
|
+
condition = !!downloadUrl;
|
|
135
|
+
} else if (!availability.available) {
|
|
136
|
+
// Hide unavailable platforms (mobile-only on desktop)
|
|
137
|
+
condition = false;
|
|
138
|
+
}
|
|
193
139
|
|
|
194
140
|
return {
|
|
195
141
|
id,
|
|
@@ -199,13 +145,10 @@ export function ShareSheetContent({
|
|
|
199
145
|
bgColor: cssVar(PLATFORM_CSS_VARS[id], PLATFORM_COLORS[id].bg),
|
|
200
146
|
textColor: PLATFORM_COLORS[id].text,
|
|
201
147
|
onClick: shareActions[id],
|
|
202
|
-
|
|
203
|
-
condition: id === "native" ? shareSheet.canNativeShare
|
|
204
|
-
: id === "download" ? !!downloadUrl
|
|
205
|
-
: true,
|
|
148
|
+
condition,
|
|
206
149
|
};
|
|
207
150
|
});
|
|
208
|
-
}, [iconSize, labels, icons, dynamicLabels, shareActions, shareSheet.canNativeShare, downloadUrl]);
|
|
151
|
+
}, [iconSize, labels, icons, dynamicLabels, shareActions, shareSheet.canNativeShare, shareSheet.platformAvailability, downloadUrl]);
|
|
209
152
|
|
|
210
153
|
const visibleButtons = useMemo(() => {
|
|
211
154
|
return buttons.filter((btn) => {
|
|
@@ -219,60 +162,33 @@ export function ShareSheetContent({
|
|
|
219
162
|
});
|
|
220
163
|
}, [buttons, show, hide]);
|
|
221
164
|
|
|
222
|
-
const
|
|
165
|
+
const bgColor = cssVar(CSS_VARS_UI.previewBg, CSS_VAR_UI_DEFAULTS[CSS_VARS_UI.previewBg]);
|
|
166
|
+
const shimmerColor = cssVar(CSS_VARS_UI.previewShimmer, CSS_VAR_UI_DEFAULTS[CSS_VARS_UI.previewShimmer]);
|
|
167
|
+
const textColor = cssVar(CSS_VARS_UI.subtitleColor, CSS_VAR_UI_DEFAULTS[CSS_VARS_UI.subtitleColor]);
|
|
223
168
|
|
|
224
|
-
// Render preview
|
|
169
|
+
// Render OG preview
|
|
225
170
|
const renderPreview = () => {
|
|
226
|
-
|
|
171
|
+
const ogImage = ogData?.image;
|
|
172
|
+
const hasImage = ogImage && !imageError;
|
|
227
173
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
</div>
|
|
247
|
-
);
|
|
248
|
-
|
|
249
|
-
// Placeholder card for non-media types or loading/error states
|
|
250
|
-
const PlaceholderCard = ({
|
|
251
|
-
icon: IconComponent,
|
|
252
|
-
isLoading = false,
|
|
253
|
-
label,
|
|
254
|
-
displayUrl,
|
|
255
|
-
}: {
|
|
256
|
-
icon: typeof Link2;
|
|
257
|
-
isLoading?: boolean;
|
|
258
|
-
label?: string;
|
|
259
|
-
displayUrl?: string;
|
|
260
|
-
}) => (
|
|
261
|
-
<div style={{ display: "flex", flexDirection: "column", alignItems: "center" }}>
|
|
262
|
-
<div
|
|
263
|
-
className={cn(defaultClasses.previewSkeleton, classNames.previewSkeleton)}
|
|
264
|
-
style={{
|
|
265
|
-
position: "relative",
|
|
266
|
-
backgroundColor: bgColor,
|
|
267
|
-
width: "200px",
|
|
268
|
-
height: "120px",
|
|
269
|
-
overflow: "hidden",
|
|
270
|
-
display: "flex",
|
|
271
|
-
alignItems: "center",
|
|
272
|
-
justifyContent: "center",
|
|
273
|
-
}}
|
|
274
|
-
>
|
|
275
|
-
{isLoading && (
|
|
174
|
+
// Loading state
|
|
175
|
+
if (ogLoading) {
|
|
176
|
+
return (
|
|
177
|
+
<div style={{ display: "flex", flexDirection: "column", alignItems: "center", width: "100%" }}>
|
|
178
|
+
<div
|
|
179
|
+
className={cn(defaultClasses.previewSkeleton, classNames.previewSkeleton)}
|
|
180
|
+
style={{
|
|
181
|
+
position: "relative",
|
|
182
|
+
backgroundColor: bgColor,
|
|
183
|
+
width: "100%",
|
|
184
|
+
maxWidth: "320px",
|
|
185
|
+
aspectRatio: "1.91 / 1",
|
|
186
|
+
overflow: "hidden",
|
|
187
|
+
display: "flex",
|
|
188
|
+
alignItems: "center",
|
|
189
|
+
justifyContent: "center",
|
|
190
|
+
}}
|
|
191
|
+
>
|
|
276
192
|
<div style={{ position: "absolute", inset: 0, overflow: "hidden" }}>
|
|
277
193
|
<div
|
|
278
194
|
style={{
|
|
@@ -283,194 +199,127 @@ export function ShareSheetContent({
|
|
|
283
199
|
}}
|
|
284
200
|
/>
|
|
285
201
|
</div>
|
|
286
|
-
|
|
202
|
+
<Link2 size={32} style={{ color: textColor, opacity: 0.4 }} />
|
|
203
|
+
</div>
|
|
204
|
+
</div>
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// No OG data or no image - show link placeholder
|
|
209
|
+
if (!ogData || !hasImage) {
|
|
210
|
+
return (
|
|
211
|
+
<div style={{ display: "flex", flexDirection: "column", alignItems: "center", width: "100%" }}>
|
|
287
212
|
<div
|
|
213
|
+
className={cn(defaultClasses.previewSkeleton, classNames.previewSkeleton)}
|
|
288
214
|
style={{
|
|
215
|
+
position: "relative",
|
|
216
|
+
backgroundColor: bgColor,
|
|
217
|
+
width: "100%",
|
|
218
|
+
maxWidth: "320px",
|
|
219
|
+
aspectRatio: "1.91 / 1",
|
|
220
|
+
overflow: "hidden",
|
|
289
221
|
display: "flex",
|
|
290
|
-
flexDirection: "column",
|
|
291
222
|
alignItems: "center",
|
|
292
223
|
justifyContent: "center",
|
|
293
|
-
gap: "8px",
|
|
294
224
|
}}
|
|
295
225
|
>
|
|
296
|
-
<
|
|
297
|
-
{label && (
|
|
298
|
-
<span style={{ color: textColor, fontSize: "11px", opacity: 0.4 }}>
|
|
299
|
-
{label}
|
|
300
|
-
</span>
|
|
301
|
-
)}
|
|
302
|
-
</div>
|
|
303
|
-
</div>
|
|
304
|
-
<UrlLabel displayUrl={displayUrl} />
|
|
305
|
-
</div>
|
|
306
|
-
);
|
|
307
|
-
|
|
308
|
-
// If there was an error loading media, show fallback
|
|
309
|
-
if (mediaError && (type === "image" || type === "video")) {
|
|
310
|
-
return <PlaceholderCard icon={Link2} displayUrl={url} />;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
switch (type) {
|
|
314
|
-
case "image":
|
|
315
|
-
// Show placeholder while loading, then show image with correct aspect ratio
|
|
316
|
-
if (!mediaLoaded) {
|
|
317
|
-
return (
|
|
318
|
-
<div style={{ display: "flex", flexDirection: "column", alignItems: "center" }}>
|
|
319
|
-
<div
|
|
320
|
-
className={cn(defaultClasses.previewSkeleton, classNames.previewSkeleton)}
|
|
321
|
-
style={{
|
|
322
|
-
position: "relative",
|
|
323
|
-
backgroundColor: bgColor,
|
|
324
|
-
width: "200px",
|
|
325
|
-
height: "120px",
|
|
326
|
-
overflow: "hidden",
|
|
327
|
-
display: "flex",
|
|
328
|
-
alignItems: "center",
|
|
329
|
-
justifyContent: "center",
|
|
330
|
-
}}
|
|
331
|
-
>
|
|
332
|
-
<div style={{ position: "absolute", inset: 0, overflow: "hidden" }}>
|
|
333
|
-
<div
|
|
334
|
-
style={{
|
|
335
|
-
position: "absolute",
|
|
336
|
-
inset: 0,
|
|
337
|
-
background: `linear-gradient(90deg, transparent, ${shimmerColor}, transparent)`,
|
|
338
|
-
animation: "sharesheet-shimmer 1.5s infinite",
|
|
339
|
-
}}
|
|
340
|
-
/>
|
|
341
|
-
</div>
|
|
342
|
-
<Image size={32} style={{ color: textColor, opacity: 0.4 }} />
|
|
343
|
-
</div>
|
|
344
|
-
<UrlLabel />
|
|
345
|
-
{/* Hidden image for preloading */}
|
|
346
|
-
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
347
|
-
<img
|
|
348
|
-
src={url}
|
|
349
|
-
alt={alt || "Preview"}
|
|
350
|
-
onLoad={handleMediaLoad}
|
|
351
|
-
onError={handleMediaError}
|
|
352
|
-
style={{ display: "none" }}
|
|
353
|
-
/>
|
|
354
|
-
</div>
|
|
355
|
-
);
|
|
356
|
-
}
|
|
357
|
-
// Image loaded - show with correct aspect ratio
|
|
358
|
-
return (
|
|
359
|
-
<div style={{ display: "flex", flexDirection: "column", alignItems: "center" }}>
|
|
360
|
-
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
361
|
-
<img
|
|
362
|
-
src={url}
|
|
363
|
-
alt={alt || "Preview"}
|
|
364
|
-
className={cn(defaultClasses.previewImage, classNames.previewImage)}
|
|
226
|
+
<div
|
|
365
227
|
style={{
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
228
|
+
display: "flex",
|
|
229
|
+
flexDirection: "column",
|
|
230
|
+
alignItems: "center",
|
|
231
|
+
justifyContent: "center",
|
|
232
|
+
gap: "8px",
|
|
233
|
+
padding: "16px",
|
|
371
234
|
}}
|
|
372
|
-
|
|
373
|
-
|
|
235
|
+
>
|
|
236
|
+
<Link2 size={32} style={{ color: textColor, opacity: 0.4 }} />
|
|
237
|
+
{ogData?.title && (
|
|
238
|
+
<span
|
|
239
|
+
style={{
|
|
240
|
+
color: textColor,
|
|
241
|
+
fontSize: "12px",
|
|
242
|
+
opacity: 0.6,
|
|
243
|
+
textAlign: "center",
|
|
244
|
+
maxWidth: "280px",
|
|
245
|
+
overflow: "hidden",
|
|
246
|
+
textOverflow: "ellipsis",
|
|
247
|
+
display: "-webkit-box",
|
|
248
|
+
WebkitLineClamp: 2,
|
|
249
|
+
WebkitBoxOrient: "vertical",
|
|
250
|
+
}}
|
|
251
|
+
>
|
|
252
|
+
{ogData.title}
|
|
253
|
+
</span>
|
|
254
|
+
)}
|
|
255
|
+
</div>
|
|
374
256
|
</div>
|
|
375
|
-
|
|
257
|
+
</div>
|
|
258
|
+
);
|
|
259
|
+
}
|
|
376
260
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
style={{
|
|
397
|
-
position: "absolute",
|
|
398
|
-
inset: 0,
|
|
399
|
-
background: `linear-gradient(90deg, transparent, ${shimmerColor}, transparent)`,
|
|
400
|
-
animation: "sharesheet-shimmer 1.5s infinite",
|
|
401
|
-
}}
|
|
402
|
-
/>
|
|
403
|
-
</div>
|
|
404
|
-
<Film size={32} style={{ color: textColor, opacity: 0.4 }} />
|
|
405
|
-
</div>
|
|
406
|
-
<UrlLabel />
|
|
407
|
-
{/* Hidden video for preloading */}
|
|
408
|
-
<video
|
|
409
|
-
src={url}
|
|
410
|
-
poster={poster}
|
|
411
|
-
onLoadedData={handleMediaLoad}
|
|
412
|
-
onError={handleMediaError}
|
|
413
|
-
style={{ display: "none" }}
|
|
414
|
-
muted
|
|
415
|
-
playsInline
|
|
416
|
-
preload="metadata"
|
|
417
|
-
/>
|
|
418
|
-
</div>
|
|
419
|
-
);
|
|
420
|
-
}
|
|
421
|
-
// Video loaded
|
|
422
|
-
return (
|
|
423
|
-
<div style={{ display: "flex", flexDirection: "column", alignItems: "center" }}>
|
|
424
|
-
<div style={{ position: "relative", borderRadius: "12px", overflow: "hidden" }}>
|
|
425
|
-
<video
|
|
426
|
-
src={url}
|
|
427
|
-
poster={poster}
|
|
428
|
-
className={cn(defaultClasses.previewVideo, classNames.previewVideo)}
|
|
429
|
-
style={{
|
|
430
|
-
maxWidth: "100%",
|
|
431
|
-
maxHeight: "180px",
|
|
432
|
-
display: "block",
|
|
433
|
-
}}
|
|
434
|
-
muted
|
|
435
|
-
playsInline
|
|
436
|
-
preload="metadata"
|
|
437
|
-
/>
|
|
438
|
-
{/* Play icon overlay */}
|
|
261
|
+
// Image loading state
|
|
262
|
+
if (!imageLoaded) {
|
|
263
|
+
return (
|
|
264
|
+
<div style={{ display: "flex", flexDirection: "column", alignItems: "center", width: "100%" }}>
|
|
265
|
+
<div
|
|
266
|
+
className={cn(defaultClasses.previewSkeleton, classNames.previewSkeleton)}
|
|
267
|
+
style={{
|
|
268
|
+
position: "relative",
|
|
269
|
+
backgroundColor: bgColor,
|
|
270
|
+
width: "100%",
|
|
271
|
+
maxWidth: "320px",
|
|
272
|
+
aspectRatio: "1.91 / 1",
|
|
273
|
+
overflow: "hidden",
|
|
274
|
+
display: "flex",
|
|
275
|
+
alignItems: "center",
|
|
276
|
+
justifyContent: "center",
|
|
277
|
+
}}
|
|
278
|
+
>
|
|
279
|
+
<div style={{ position: "absolute", inset: 0, overflow: "hidden" }}>
|
|
439
280
|
<div
|
|
440
281
|
style={{
|
|
441
282
|
position: "absolute",
|
|
442
283
|
inset: 0,
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
justifyContent: "center",
|
|
446
|
-
pointerEvents: "none",
|
|
284
|
+
background: `linear-gradient(90deg, transparent, ${shimmerColor}, transparent)`,
|
|
285
|
+
animation: "sharesheet-shimmer 1.5s infinite",
|
|
447
286
|
}}
|
|
448
|
-
|
|
449
|
-
<div
|
|
450
|
-
style={{
|
|
451
|
-
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
|
452
|
-
borderRadius: "50%",
|
|
453
|
-
padding: "10px",
|
|
454
|
-
}}
|
|
455
|
-
>
|
|
456
|
-
<Play size={20} fill="white" color="white" />
|
|
457
|
-
</div>
|
|
458
|
-
</div>
|
|
287
|
+
/>
|
|
459
288
|
</div>
|
|
460
|
-
<
|
|
289
|
+
<Image size={32} style={{ color: textColor, opacity: 0.4 }} />
|
|
461
290
|
</div>
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
291
|
+
{/* Hidden image for preloading */}
|
|
292
|
+
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
293
|
+
<img
|
|
294
|
+
src={ogImage}
|
|
295
|
+
alt={ogData.title || "Preview"}
|
|
296
|
+
onLoad={handleImageLoad}
|
|
297
|
+
onError={handleImageError}
|
|
298
|
+
style={{ display: "none" }}
|
|
299
|
+
/>
|
|
300
|
+
</div>
|
|
301
|
+
);
|
|
473
302
|
}
|
|
303
|
+
|
|
304
|
+
// Image loaded - show it
|
|
305
|
+
return (
|
|
306
|
+
<div style={{ display: "flex", flexDirection: "column", alignItems: "center", width: "100%" }}>
|
|
307
|
+
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
308
|
+
<img
|
|
309
|
+
src={ogImage}
|
|
310
|
+
alt={ogData.title || "Preview"}
|
|
311
|
+
className={cn(defaultClasses.previewImage, classNames.previewImage)}
|
|
312
|
+
style={{
|
|
313
|
+
width: "100%",
|
|
314
|
+
maxWidth: "320px",
|
|
315
|
+
height: "auto",
|
|
316
|
+
borderRadius: "12px",
|
|
317
|
+
opacity: 1,
|
|
318
|
+
transition: "opacity 0.3s ease-in-out",
|
|
319
|
+
}}
|
|
320
|
+
/>
|
|
321
|
+
</div>
|
|
322
|
+
);
|
|
474
323
|
};
|
|
475
324
|
|
|
476
325
|
return (
|
|
@@ -493,12 +342,10 @@ export function ShareSheetContent({
|
|
|
493
342
|
</div>
|
|
494
343
|
</div>
|
|
495
344
|
|
|
496
|
-
{/*
|
|
497
|
-
{
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
</div>
|
|
501
|
-
)}
|
|
345
|
+
{/* OG Preview - always shown */}
|
|
346
|
+
<div className={cn(defaultClasses.preview, classNames.preview)}>
|
|
347
|
+
{renderPreview()}
|
|
348
|
+
</div>
|
|
502
349
|
|
|
503
350
|
<div className={cn(defaultClasses.grid, classNames.grid)}>
|
|
504
351
|
{visibleButtons.map((btn) => (
|
|
@@ -535,4 +382,3 @@ export function ShareSheetContent({
|
|
|
535
382
|
// Legacy export for backwards compatibility
|
|
536
383
|
/** @deprecated Use ShareSheetContent instead */
|
|
537
384
|
export const ShareMenuContent = ShareSheetContent;
|
|
538
|
-
|
package/src/ShareSheetDrawer.tsx
CHANGED
|
@@ -10,8 +10,8 @@ import { CSS_VARS_UI, CSS_VAR_UI_DEFAULTS, type ShareSheetDrawerProps } from "./
|
|
|
10
10
|
// Default class names for drawer
|
|
11
11
|
const defaultDrawerClasses = {
|
|
12
12
|
overlay: "fixed inset-0 z-[70]",
|
|
13
|
-
drawer: "flex flex-col rounded-t-[14px] h-[
|
|
14
|
-
drawerInner: "p-4 rounded-t-[14px]
|
|
13
|
+
drawer: "flex flex-col rounded-t-[14px] max-h-[90%] fixed bottom-0 left-0 right-0 z-[80] border-t outline-none",
|
|
14
|
+
drawerInner: "p-4 pb-8 rounded-t-[14px] overflow-auto",
|
|
15
15
|
handle: "mx-auto w-12 h-1.5 shrink-0 rounded-full mb-6",
|
|
16
16
|
trigger: "",
|
|
17
17
|
};
|
|
@@ -25,7 +25,6 @@ export function ShareSheetDrawer({
|
|
|
25
25
|
title = "Share",
|
|
26
26
|
shareUrl,
|
|
27
27
|
shareText,
|
|
28
|
-
preview,
|
|
29
28
|
downloadUrl,
|
|
30
29
|
downloadFilename,
|
|
31
30
|
disabled,
|
|
@@ -97,7 +96,6 @@ export function ShareSheetDrawer({
|
|
|
97
96
|
title={title}
|
|
98
97
|
shareUrl={shareUrl}
|
|
99
98
|
shareText={shareText}
|
|
100
|
-
preview={preview}
|
|
101
99
|
downloadUrl={downloadUrl}
|
|
102
100
|
downloadFilename={downloadFilename}
|
|
103
101
|
className={className}
|