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.
Files changed (45) hide show
  1. package/README.md +84 -102
  2. package/dist/content.d.mts +3 -3
  3. package/dist/content.d.ts +3 -3
  4. package/dist/content.js +296 -271
  5. package/dist/content.js.map +1 -1
  6. package/dist/content.mjs +298 -273
  7. package/dist/content.mjs.map +1 -1
  8. package/dist/drawer.d.mts +3 -3
  9. package/dist/drawer.d.ts +3 -3
  10. package/dist/drawer.js +298 -275
  11. package/dist/drawer.js.map +1 -1
  12. package/dist/drawer.mjs +300 -277
  13. package/dist/drawer.mjs.map +1 -1
  14. package/dist/headless-B7I228Dt.d.mts +98 -0
  15. package/dist/headless-BiSYHizs.d.ts +98 -0
  16. package/dist/headless.d.mts +3 -50
  17. package/dist/headless.d.ts +3 -50
  18. package/dist/headless.js +165 -0
  19. package/dist/headless.js.map +1 -1
  20. package/dist/headless.mjs +163 -1
  21. package/dist/headless.mjs.map +1 -1
  22. package/dist/index.d.mts +2 -2
  23. package/dist/index.d.ts +2 -2
  24. package/dist/index.js +339 -277
  25. package/dist/index.js.map +1 -1
  26. package/dist/index.mjs +329 -278
  27. package/dist/index.mjs.map +1 -1
  28. package/dist/{platforms-DU1DVDFq.d.mts → platforms-omqzPfYX.d.mts} +17 -23
  29. package/dist/{platforms-DU1DVDFq.d.ts → platforms-omqzPfYX.d.ts} +17 -23
  30. package/package.json +24 -7
  31. package/src/ShareSheetContent.tsx +157 -311
  32. package/src/ShareSheetDrawer.tsx +2 -4
  33. package/src/__tests__/hooks.test.ts +203 -0
  34. package/src/__tests__/og-fetcher.test.ts +144 -0
  35. package/src/__tests__/platforms.test.ts +148 -0
  36. package/src/__tests__/setup.ts +22 -0
  37. package/src/__tests__/share-functions.test.ts +152 -0
  38. package/src/__tests__/utils.test.ts +64 -0
  39. package/src/headless.ts +4 -1
  40. package/src/hooks.ts +60 -2
  41. package/src/index.ts +20 -4
  42. package/src/og-fetcher.ts +64 -0
  43. package/src/share-functions.ts +25 -1
  44. package/src/types.ts +17 -24
  45. package/src/utils.ts +125 -0
package/dist/drawer.mjs CHANGED
@@ -14,13 +14,114 @@ function openUrl(url) {
14
14
  function getSafeUrl(shareUrl) {
15
15
  return shareUrl || (typeof window !== "undefined" ? window.location.href : "");
16
16
  }
17
+ function isMobileDevice() {
18
+ if (typeof navigator === "undefined") return false;
19
+ const userAgent = navigator.userAgent || navigator.vendor || "";
20
+ const mobileRegex = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Mobile|mobile|CriOS/i;
21
+ const hasTouch = typeof window !== "undefined" && ("ontouchstart" in window || navigator.maxTouchPoints > 0);
22
+ return mobileRegex.test(userAgent);
23
+ }
24
+ var MOBILE_ONLY_PLATFORMS = [
25
+ "instagram",
26
+ "tiktok",
27
+ "threads",
28
+ "sms"
29
+ ];
30
+ function checkPlatformAvailability(platform) {
31
+ const isMobile = isMobileDevice();
32
+ if (MOBILE_ONLY_PLATFORMS.includes(platform)) {
33
+ if (!isMobile) {
34
+ return {
35
+ available: false,
36
+ reason: `${platform} requires a mobile device with the app installed`
37
+ };
38
+ }
39
+ }
40
+ if (platform === "sms" && !isMobile) {
41
+ return {
42
+ available: false,
43
+ reason: "SMS sharing requires a mobile device"
44
+ };
45
+ }
46
+ if (platform === "native") {
47
+ const canShare = typeof navigator !== "undefined" && "share" in navigator;
48
+ if (!canShare) {
49
+ return {
50
+ available: false,
51
+ reason: "Native share is not supported by this browser"
52
+ };
53
+ }
54
+ }
55
+ return { available: true };
56
+ }
57
+ function getAllPlatformAvailability() {
58
+ const platforms = [
59
+ "native",
60
+ "copy",
61
+ "download",
62
+ "whatsapp",
63
+ "telegram",
64
+ "instagram",
65
+ "facebook",
66
+ "snapchat",
67
+ "sms",
68
+ "email",
69
+ "linkedin",
70
+ "reddit",
71
+ "x",
72
+ "tiktok",
73
+ "threads"
74
+ ];
75
+ const result = {};
76
+ for (const platform of platforms) {
77
+ result[platform] = checkPlatformAvailability(platform);
78
+ }
79
+ return result;
80
+ }
81
+ function warnUnavailablePlatform(platform, reason) {
82
+ console.warn(
83
+ `[react-sharesheet] ${platform} sharing is not available: ${reason}. This share option may not work correctly on this device.`
84
+ );
85
+ }
17
86
 
18
87
  // src/ShareSheetContent.tsx
19
88
  import { useMemo as useMemo2, useState as useState2, useCallback as useCallback2 } from "react";
20
- import { Image, FileText, Music, Film, Link2, Play } from "lucide-react";
89
+ import { Image, Link2 } from "lucide-react";
21
90
 
22
91
  // src/hooks.ts
23
- import { useMemo, useState, useCallback } from "react";
92
+ import { useMemo, useState, useCallback, useEffect } from "react";
93
+
94
+ // src/og-fetcher.ts
95
+ var ogCache = /* @__PURE__ */ new Map();
96
+ async function fetchOGData(url) {
97
+ if (ogCache.has(url)) {
98
+ return ogCache.get(url);
99
+ }
100
+ try {
101
+ const apiUrl = `https://api.microlink.io?url=${encodeURIComponent(url)}`;
102
+ const response = await fetch(apiUrl);
103
+ if (!response.ok) {
104
+ throw new Error(`Failed to fetch OG data: ${response.status}`);
105
+ }
106
+ const json = await response.json();
107
+ if (json.status !== "success" || !json.data) {
108
+ return null;
109
+ }
110
+ const { title, description, image, url: canonicalUrl, publisher } = json.data;
111
+ const ogData = {
112
+ title: title || void 0,
113
+ description: description || void 0,
114
+ image: image?.url || void 0,
115
+ url: canonicalUrl || url,
116
+ siteName: publisher || void 0
117
+ };
118
+ ogCache.set(url, ogData);
119
+ return ogData;
120
+ } catch (error) {
121
+ console.warn("[react-sharesheet] Failed to fetch OG data:", error);
122
+ return null;
123
+ }
124
+ }
24
125
 
25
126
  // src/share-functions.ts
26
127
  function shareToWhatsApp(url, text) {
@@ -43,12 +144,24 @@ function shareToFacebook(url) {
43
144
  openUrl(`https://www.facebook.com/sharer/sharer.php?u=${encodedUrl}`);
44
145
  }
45
146
  function openInstagram() {
147
+ const availability = checkPlatformAvailability("instagram");
148
+ if (!availability.available) {
149
+ warnUnavailablePlatform("instagram", availability.reason);
150
+ }
46
151
  window.location.href = "instagram://";
47
152
  }
48
153
  function openTikTok() {
154
+ const availability = checkPlatformAvailability("tiktok");
155
+ if (!availability.available) {
156
+ warnUnavailablePlatform("tiktok", availability.reason);
157
+ }
49
158
  window.location.href = "tiktok://";
50
159
  }
51
160
  function openThreads() {
161
+ const availability = checkPlatformAvailability("threads");
162
+ if (!availability.available) {
163
+ warnUnavailablePlatform("threads", availability.reason);
164
+ }
52
165
  window.location.href = "threads://";
53
166
  }
54
167
  function shareToSnapchat(url) {
@@ -56,6 +169,10 @@ function shareToSnapchat(url) {
56
169
  openUrl(`https://www.snapchat.com/scan?attachmentUrl=${encodedUrl}`);
57
170
  }
58
171
  function shareViaSMS(url, text) {
172
+ const availability = checkPlatformAvailability("sms");
173
+ if (!availability.available) {
174
+ warnUnavailablePlatform("sms", availability.reason);
175
+ }
59
176
  const body = encodeURIComponent(`${text}
60
177
  ${url}`);
61
178
  window.location.href = `sms:?body=${body}`;
@@ -93,6 +210,12 @@ function useShareSheet({
93
210
  const canNativeShare = useMemo(() => {
94
211
  return typeof navigator !== "undefined" && "share" in navigator;
95
212
  }, []);
213
+ const isMobile = useMemo(() => {
214
+ return isMobileDevice();
215
+ }, []);
216
+ const platformAvailability = useMemo(() => {
217
+ return getAllPlatformAvailability();
218
+ }, []);
96
219
  const safeUrl = getSafeUrl(shareUrl);
97
220
  const copyLink = useCallback(async () => {
98
221
  if (!safeUrl) return;
@@ -181,6 +304,8 @@ function useShareSheet({
181
304
  copied,
182
305
  downloading,
183
306
  safeUrl,
307
+ isMobile,
308
+ platformAvailability,
184
309
  copyLink,
185
310
  nativeShare,
186
311
  downloadFile,
@@ -198,6 +323,37 @@ function useShareSheet({
198
323
  shareReddit
199
324
  };
200
325
  }
326
+ function useOGData(url) {
327
+ const [ogData, setOgData] = useState(null);
328
+ const [loading, setLoading] = useState(false);
329
+ const [error, setError] = useState(null);
330
+ useEffect(() => {
331
+ if (!url) {
332
+ setOgData(null);
333
+ setLoading(false);
334
+ setError(null);
335
+ return;
336
+ }
337
+ let cancelled = false;
338
+ setLoading(true);
339
+ setError(null);
340
+ fetchOGData(url).then((data) => {
341
+ if (!cancelled) {
342
+ setOgData(data);
343
+ setLoading(false);
344
+ }
345
+ }).catch((err) => {
346
+ if (!cancelled) {
347
+ setError(err instanceof Error ? err.message : "Failed to fetch OG data");
348
+ setLoading(false);
349
+ }
350
+ });
351
+ return () => {
352
+ cancelled = true;
353
+ };
354
+ }, [url]);
355
+ return { ogData, loading, error };
356
+ }
201
357
 
202
358
  // src/platforms.tsx
203
359
  import {
@@ -349,32 +505,6 @@ var CSS_VAR_DEFAULTS = CSS_VAR_UI_DEFAULTS;
349
505
  import { jsx as jsx2, jsxs } from "react/jsx-runtime";
350
506
  var DEFAULT_BUTTON_SIZE = 45;
351
507
  var DEFAULT_ICON_SIZE = 22;
352
- var IMAGE_EXTENSIONS = ["jpg", "jpeg", "png", "gif", "webp", "svg", "bmp", "ico", "avif"];
353
- var VIDEO_EXTENSIONS = ["mp4", "webm", "mov", "avi", "mkv", "m4v", "ogv"];
354
- var AUDIO_EXTENSIONS = ["mp3", "wav", "ogg", "m4a", "aac", "flac", "wma"];
355
- function detectPreviewType(url) {
356
- try {
357
- const pathname = new URL(url, "http://localhost").pathname;
358
- const ext = pathname.split(".").pop()?.toLowerCase() || "";
359
- if (IMAGE_EXTENSIONS.includes(ext)) return "image";
360
- if (VIDEO_EXTENSIONS.includes(ext)) return "video";
361
- if (AUDIO_EXTENSIONS.includes(ext)) return "audio";
362
- if (url.includes("/api/og") || url.includes("og-image")) return "image";
363
- if (url.includes("youtube.com") || url.includes("vimeo.com")) return "video";
364
- return "link";
365
- } catch {
366
- return "link";
367
- }
368
- }
369
- function getFilenameFromUrl(url) {
370
- try {
371
- const pathname = new URL(url, "http://localhost").pathname;
372
- const filename = pathname.split("/").pop() || "";
373
- return decodeURIComponent(filename);
374
- } catch {
375
- return url;
376
- }
377
- }
378
508
  var defaultClasses = {
379
509
  root: "max-w-md mx-auto",
380
510
  header: "text-center mb-2",
@@ -383,12 +513,8 @@ var defaultClasses = {
383
513
  preview: "flex justify-center mb-4 px-4",
384
514
  previewSkeleton: "rounded-xl overflow-hidden",
385
515
  previewImage: "",
386
- previewVideo: "",
387
- previewFile: "",
388
- previewFileIcon: "",
389
- previewFilename: "truncate",
390
- previewLink: "",
391
- grid: "px-2 py-6 flex flex-row items-center gap-4 gap-y-6 flex-wrap justify-center",
516
+ previewMeta: "",
517
+ grid: "px-2 py-6 flex flex-row items-start gap-4 gap-y-6 flex-wrap justify-center",
392
518
  button: "flex flex-col items-center gap-0 text-xs w-[60px] outline-none cursor-pointer group",
393
519
  buttonIcon: "p-2 rounded-full transition-all flex items-center justify-center group-hover:scale-110 group-active:scale-95 mb-2",
394
520
  buttonLabel: ""
@@ -402,28 +528,10 @@ var shimmerKeyframes = `
402
528
  function cssVar(name, fallback) {
403
529
  return `var(${name}, ${fallback})`;
404
530
  }
405
- function normalizePreview(preview) {
406
- if (!preview) return null;
407
- if (typeof preview === "string") {
408
- const type2 = detectPreviewType(preview);
409
- return {
410
- url: preview,
411
- type: type2,
412
- filename: getFilenameFromUrl(preview)
413
- };
414
- }
415
- const type = preview.type === "auto" || !preview.type ? detectPreviewType(preview.url) : preview.type;
416
- return {
417
- ...preview,
418
- type,
419
- filename: preview.filename || getFilenameFromUrl(preview.url)
420
- };
421
- }
422
531
  function ShareSheetContent({
423
532
  title = "Share",
424
533
  shareUrl,
425
534
  shareText,
426
- preview,
427
535
  downloadUrl,
428
536
  downloadFilename,
429
537
  className,
@@ -438,15 +546,15 @@ function ShareSheetContent({
438
546
  labels = {},
439
547
  icons = {}
440
548
  }) {
441
- const [mediaLoaded, setMediaLoaded] = useState2(false);
442
- const [mediaError, setMediaError] = useState2(false);
443
- const handleMediaLoad = useCallback2(() => {
444
- setMediaLoaded(true);
549
+ const [imageLoaded, setImageLoaded] = useState2(false);
550
+ const [imageError, setImageError] = useState2(false);
551
+ const { ogData, loading: ogLoading } = useOGData(shareUrl);
552
+ const handleImageLoad = useCallback2(() => {
553
+ setImageLoaded(true);
445
554
  }, []);
446
- const handleMediaError = useCallback2(() => {
447
- setMediaError(true);
555
+ const handleImageError = useCallback2(() => {
556
+ setImageError(true);
448
557
  }, []);
449
- const previewConfig = useMemo2(() => normalizePreview(preview), [preview]);
450
558
  const shareSheet = useShareSheet({
451
559
  shareUrl,
452
560
  shareText,
@@ -482,6 +590,15 @@ function ShareSheetContent({
482
590
  return PLATFORM_IDS.map((id) => {
483
591
  const Icon = PLATFORM_ICONS[id];
484
592
  const defaultLabel = dynamicLabels[id] ?? PLATFORM_LABELS[id];
593
+ const availability = shareSheet.platformAvailability[id];
594
+ let condition = true;
595
+ if (id === "native") {
596
+ condition = shareSheet.canNativeShare;
597
+ } else if (id === "download") {
598
+ condition = !!downloadUrl;
599
+ } else if (!availability.available) {
600
+ condition = false;
601
+ }
485
602
  return {
486
603
  id,
487
604
  label: labels[id] ?? defaultLabel,
@@ -490,11 +607,10 @@ function ShareSheetContent({
490
607
  bgColor: cssVar(PLATFORM_CSS_VARS[id], PLATFORM_COLORS[id].bg),
491
608
  textColor: PLATFORM_COLORS[id].text,
492
609
  onClick: shareActions[id],
493
- // Conditions for showing certain buttons
494
- condition: id === "native" ? shareSheet.canNativeShare : id === "download" ? !!downloadUrl : true
610
+ condition
495
611
  };
496
612
  });
497
- }, [iconSize, labels, icons, dynamicLabels, shareActions, shareSheet.canNativeShare, downloadUrl]);
613
+ }, [iconSize, labels, icons, dynamicLabels, shareActions, shareSheet.canNativeShare, shareSheet.platformAvailability, downloadUrl]);
498
614
  const visibleButtons = useMemo2(() => {
499
615
  return buttons.filter((btn) => {
500
616
  if (btn.condition === false) return false;
@@ -503,49 +619,30 @@ function ShareSheetContent({
503
619
  return true;
504
620
  });
505
621
  }, [buttons, show, hide]);
506
- const showPreview = !!previewConfig;
622
+ const bgColor = cssVar(CSS_VARS_UI.previewBg, CSS_VAR_UI_DEFAULTS[CSS_VARS_UI.previewBg]);
623
+ const shimmerColor = cssVar(CSS_VARS_UI.previewShimmer, CSS_VAR_UI_DEFAULTS[CSS_VARS_UI.previewShimmer]);
624
+ const textColor = cssVar(CSS_VARS_UI.subtitleColor, CSS_VAR_UI_DEFAULTS[CSS_VARS_UI.subtitleColor]);
507
625
  const renderPreview = () => {
508
- if (!previewConfig) return null;
509
- const { type, url, filename, alt, poster } = previewConfig;
510
- const bgColor = cssVar(CSS_VARS_UI.previewBg, CSS_VAR_UI_DEFAULTS[CSS_VARS_UI.previewBg]);
511
- const shimmerColor = cssVar(CSS_VARS_UI.previewShimmer, CSS_VAR_UI_DEFAULTS[CSS_VARS_UI.previewShimmer]);
512
- const textColor = cssVar(CSS_VARS_UI.subtitleColor, CSS_VAR_UI_DEFAULTS[CSS_VARS_UI.subtitleColor]);
513
- const UrlLabel = ({ displayUrl = url }) => /* @__PURE__ */ jsx2(
514
- "div",
515
- {
516
- className: cn(defaultClasses.previewFilename, classNames.previewFilename),
517
- style: {
518
- color: textColor,
519
- fontSize: "10px",
520
- opacity: 0.5,
521
- textAlign: "center",
522
- marginTop: "6px"
523
- },
524
- children: displayUrl
525
- }
526
- );
527
- const PlaceholderCard = ({
528
- icon: IconComponent,
529
- isLoading = false,
530
- label,
531
- displayUrl
532
- }) => /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: "center" }, children: [
533
- /* @__PURE__ */ jsxs(
626
+ const ogImage = ogData?.image;
627
+ const hasImage = ogImage && !imageError;
628
+ if (ogLoading) {
629
+ return /* @__PURE__ */ jsx2("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", width: "100%" }, children: /* @__PURE__ */ jsxs(
534
630
  "div",
535
631
  {
536
632
  className: cn(defaultClasses.previewSkeleton, classNames.previewSkeleton),
537
633
  style: {
538
634
  position: "relative",
539
635
  backgroundColor: bgColor,
540
- width: "200px",
541
- height: "120px",
636
+ width: "100%",
637
+ maxWidth: "320px",
638
+ aspectRatio: "1.91 / 1",
542
639
  overflow: "hidden",
543
640
  display: "flex",
544
641
  alignItems: "center",
545
642
  justifyContent: "center"
546
643
  },
547
644
  children: [
548
- isLoading && /* @__PURE__ */ jsx2("div", { style: { position: "absolute", inset: 0, overflow: "hidden" }, children: /* @__PURE__ */ jsx2(
645
+ /* @__PURE__ */ jsx2("div", { style: { position: "absolute", inset: 0, overflow: "hidden" }, children: /* @__PURE__ */ jsx2(
549
646
  "div",
550
647
  {
551
648
  style: {
@@ -556,197 +653,125 @@ function ShareSheetContent({
556
653
  }
557
654
  }
558
655
  ) }),
559
- /* @__PURE__ */ jsxs(
560
- "div",
561
- {
562
- style: {
563
- display: "flex",
564
- flexDirection: "column",
565
- alignItems: "center",
566
- justifyContent: "center",
567
- gap: "8px"
568
- },
569
- children: [
570
- /* @__PURE__ */ jsx2(IconComponent, { size: 32, style: { color: textColor, opacity: 0.4 } }),
571
- label && /* @__PURE__ */ jsx2("span", { style: { color: textColor, fontSize: "11px", opacity: 0.4 }, children: label })
572
- ]
573
- }
574
- )
656
+ /* @__PURE__ */ jsx2(Link2, { size: 32, style: { color: textColor, opacity: 0.4 } })
575
657
  ]
576
658
  }
577
- ),
578
- /* @__PURE__ */ jsx2(UrlLabel, { displayUrl })
579
- ] });
580
- if (mediaError && (type === "image" || type === "video")) {
581
- return /* @__PURE__ */ jsx2(PlaceholderCard, { icon: Link2, displayUrl: url });
659
+ ) });
582
660
  }
583
- switch (type) {
584
- case "image":
585
- if (!mediaLoaded) {
586
- return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: "center" }, children: [
587
- /* @__PURE__ */ jsxs(
588
- "div",
589
- {
590
- className: cn(defaultClasses.previewSkeleton, classNames.previewSkeleton),
591
- style: {
592
- position: "relative",
593
- backgroundColor: bgColor,
594
- width: "200px",
595
- height: "120px",
596
- overflow: "hidden",
597
- display: "flex",
598
- alignItems: "center",
599
- justifyContent: "center"
600
- },
601
- children: [
602
- /* @__PURE__ */ jsx2("div", { style: { position: "absolute", inset: 0, overflow: "hidden" }, children: /* @__PURE__ */ jsx2(
603
- "div",
604
- {
605
- style: {
606
- position: "absolute",
607
- inset: 0,
608
- background: `linear-gradient(90deg, transparent, ${shimmerColor}, transparent)`,
609
- animation: "sharesheet-shimmer 1.5s infinite"
610
- }
611
- }
612
- ) }),
613
- /* @__PURE__ */ jsx2(Image, { size: 32, style: { color: textColor, opacity: 0.4 } })
614
- ]
615
- }
616
- ),
617
- /* @__PURE__ */ jsx2(UrlLabel, {}),
618
- /* @__PURE__ */ jsx2(
619
- "img",
620
- {
621
- src: url,
622
- alt: alt || "Preview",
623
- onLoad: handleMediaLoad,
624
- onError: handleMediaError,
625
- style: { display: "none" }
626
- }
627
- )
628
- ] });
629
- }
630
- return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: "center" }, children: [
631
- /* @__PURE__ */ jsx2(
632
- "img",
661
+ if (!ogData || !hasImage) {
662
+ return /* @__PURE__ */ jsx2("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", width: "100%" }, children: /* @__PURE__ */ jsx2(
663
+ "div",
664
+ {
665
+ className: cn(defaultClasses.previewSkeleton, classNames.previewSkeleton),
666
+ style: {
667
+ position: "relative",
668
+ backgroundColor: bgColor,
669
+ width: "100%",
670
+ maxWidth: "320px",
671
+ aspectRatio: "1.91 / 1",
672
+ overflow: "hidden",
673
+ display: "flex",
674
+ alignItems: "center",
675
+ justifyContent: "center"
676
+ },
677
+ children: /* @__PURE__ */ jsxs(
678
+ "div",
633
679
  {
634
- src: url,
635
- alt: alt || "Preview",
636
- className: cn(defaultClasses.previewImage, classNames.previewImage),
637
680
  style: {
638
- maxWidth: "100%",
639
- maxHeight: "180px",
640
- borderRadius: "12px",
641
- opacity: 1,
642
- transition: "opacity 0.3s ease-in-out"
643
- }
644
- }
645
- ),
646
- /* @__PURE__ */ jsx2(UrlLabel, {})
647
- ] });
648
- case "video":
649
- if (!mediaLoaded) {
650
- return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: "center" }, children: [
651
- /* @__PURE__ */ jsxs(
652
- "div",
653
- {
654
- className: cn(defaultClasses.previewSkeleton, classNames.previewSkeleton),
655
- style: {
656
- position: "relative",
657
- backgroundColor: bgColor,
658
- width: "200px",
659
- height: "120px",
660
- overflow: "hidden",
661
- display: "flex",
662
- alignItems: "center",
663
- justifyContent: "center"
664
- },
665
- children: [
666
- /* @__PURE__ */ jsx2("div", { style: { position: "absolute", inset: 0, overflow: "hidden" }, children: /* @__PURE__ */ jsx2(
667
- "div",
668
- {
669
- style: {
670
- position: "absolute",
671
- inset: 0,
672
- background: `linear-gradient(90deg, transparent, ${shimmerColor}, transparent)`,
673
- animation: "sharesheet-shimmer 1.5s infinite"
674
- }
675
- }
676
- ) }),
677
- /* @__PURE__ */ jsx2(Film, { size: 32, style: { color: textColor, opacity: 0.4 } })
678
- ]
679
- }
680
- ),
681
- /* @__PURE__ */ jsx2(UrlLabel, {}),
682
- /* @__PURE__ */ jsx2(
683
- "video",
684
- {
685
- src: url,
686
- poster,
687
- onLoadedData: handleMediaLoad,
688
- onError: handleMediaError,
689
- style: { display: "none" },
690
- muted: true,
691
- playsInline: true,
692
- preload: "metadata"
693
- }
694
- )
695
- ] });
696
- }
697
- return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: "center" }, children: [
698
- /* @__PURE__ */ jsxs("div", { style: { position: "relative", borderRadius: "12px", overflow: "hidden" }, children: [
699
- /* @__PURE__ */ jsx2(
700
- "video",
701
- {
702
- src: url,
703
- poster,
704
- className: cn(defaultClasses.previewVideo, classNames.previewVideo),
705
- style: {
706
- maxWidth: "100%",
707
- maxHeight: "180px",
708
- display: "block"
709
- },
710
- muted: true,
711
- playsInline: true,
712
- preload: "metadata"
713
- }
714
- ),
715
- /* @__PURE__ */ jsx2(
716
- "div",
717
- {
718
- style: {
719
- position: "absolute",
720
- inset: 0,
721
- display: "flex",
722
- alignItems: "center",
723
- justifyContent: "center",
724
- pointerEvents: "none"
725
- },
726
- children: /* @__PURE__ */ jsx2(
727
- "div",
681
+ display: "flex",
682
+ flexDirection: "column",
683
+ alignItems: "center",
684
+ justifyContent: "center",
685
+ gap: "8px",
686
+ padding: "16px"
687
+ },
688
+ children: [
689
+ /* @__PURE__ */ jsx2(Link2, { size: 32, style: { color: textColor, opacity: 0.4 } }),
690
+ ogData?.title && /* @__PURE__ */ jsx2(
691
+ "span",
728
692
  {
729
693
  style: {
730
- backgroundColor: "rgba(0, 0, 0, 0.5)",
731
- borderRadius: "50%",
732
- padding: "10px"
694
+ color: textColor,
695
+ fontSize: "12px",
696
+ opacity: 0.6,
697
+ textAlign: "center",
698
+ maxWidth: "280px",
699
+ overflow: "hidden",
700
+ textOverflow: "ellipsis",
701
+ display: "-webkit-box",
702
+ WebkitLineClamp: 2,
703
+ WebkitBoxOrient: "vertical"
733
704
  },
734
- children: /* @__PURE__ */ jsx2(Play, { size: 20, fill: "white", color: "white" })
705
+ children: ogData.title
735
706
  }
736
707
  )
737
- }
738
- )
739
- ] }),
740
- /* @__PURE__ */ jsx2(UrlLabel, {})
741
- ] });
742
- case "audio":
743
- return /* @__PURE__ */ jsx2(PlaceholderCard, { icon: Music, label: filename || "Audio", displayUrl: url });
744
- case "file":
745
- return /* @__PURE__ */ jsx2(PlaceholderCard, { icon: FileText, label: filename || "File", displayUrl: url });
746
- case "link":
747
- default:
748
- return /* @__PURE__ */ jsx2(PlaceholderCard, { icon: Link2, displayUrl: url });
708
+ ]
709
+ }
710
+ )
711
+ }
712
+ ) });
749
713
  }
714
+ if (!imageLoaded) {
715
+ return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", width: "100%" }, children: [
716
+ /* @__PURE__ */ jsxs(
717
+ "div",
718
+ {
719
+ className: cn(defaultClasses.previewSkeleton, classNames.previewSkeleton),
720
+ style: {
721
+ position: "relative",
722
+ backgroundColor: bgColor,
723
+ width: "100%",
724
+ maxWidth: "320px",
725
+ aspectRatio: "1.91 / 1",
726
+ overflow: "hidden",
727
+ display: "flex",
728
+ alignItems: "center",
729
+ justifyContent: "center"
730
+ },
731
+ children: [
732
+ /* @__PURE__ */ jsx2("div", { style: { position: "absolute", inset: 0, overflow: "hidden" }, children: /* @__PURE__ */ jsx2(
733
+ "div",
734
+ {
735
+ style: {
736
+ position: "absolute",
737
+ inset: 0,
738
+ background: `linear-gradient(90deg, transparent, ${shimmerColor}, transparent)`,
739
+ animation: "sharesheet-shimmer 1.5s infinite"
740
+ }
741
+ }
742
+ ) }),
743
+ /* @__PURE__ */ jsx2(Image, { size: 32, style: { color: textColor, opacity: 0.4 } })
744
+ ]
745
+ }
746
+ ),
747
+ /* @__PURE__ */ jsx2(
748
+ "img",
749
+ {
750
+ src: ogImage,
751
+ alt: ogData.title || "Preview",
752
+ onLoad: handleImageLoad,
753
+ onError: handleImageError,
754
+ style: { display: "none" }
755
+ }
756
+ )
757
+ ] });
758
+ }
759
+ return /* @__PURE__ */ jsx2("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", width: "100%" }, children: /* @__PURE__ */ jsx2(
760
+ "img",
761
+ {
762
+ src: ogImage,
763
+ alt: ogData.title || "Preview",
764
+ className: cn(defaultClasses.previewImage, classNames.previewImage),
765
+ style: {
766
+ width: "100%",
767
+ maxWidth: "320px",
768
+ height: "auto",
769
+ borderRadius: "12px",
770
+ opacity: 1,
771
+ transition: "opacity 0.3s ease-in-out"
772
+ }
773
+ }
774
+ ) });
750
775
  };
751
776
  return /* @__PURE__ */ jsxs("div", { className: cn(defaultClasses.root, classNames.root, className), children: [
752
777
  /* @__PURE__ */ jsx2("style", { dangerouslySetInnerHTML: { __html: shimmerKeyframes } }),
@@ -768,7 +793,7 @@ function ShareSheetContent({
768
793
  }
769
794
  )
770
795
  ] }),
771
- showPreview && /* @__PURE__ */ jsx2("div", { className: cn(defaultClasses.preview, classNames.preview), children: renderPreview() }),
796
+ /* @__PURE__ */ jsx2("div", { className: cn(defaultClasses.preview, classNames.preview), children: renderPreview() }),
772
797
  /* @__PURE__ */ jsx2("div", { className: cn(defaultClasses.grid, classNames.grid), children: visibleButtons.map((btn) => /* @__PURE__ */ jsxs(
773
798
  "button",
774
799
  {
@@ -808,8 +833,8 @@ function ShareSheetContent({
808
833
  import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
809
834
  var defaultDrawerClasses = {
810
835
  overlay: "fixed inset-0 z-[70]",
811
- drawer: "flex flex-col rounded-t-[14px] h-[70%] mt-24 fixed bottom-0 left-0 right-0 z-[80] border-t outline-none",
812
- drawerInner: "p-4 rounded-t-[14px] flex-1 overflow-auto",
836
+ drawer: "flex flex-col rounded-t-[14px] max-h-[90%] fixed bottom-0 left-0 right-0 z-[80] border-t outline-none",
837
+ drawerInner: "p-4 pb-8 rounded-t-[14px] overflow-auto",
813
838
  handle: "mx-auto w-12 h-1.5 shrink-0 rounded-full mb-6",
814
839
  trigger: ""
815
840
  };
@@ -820,7 +845,6 @@ function ShareSheetDrawer({
820
845
  title = "Share",
821
846
  shareUrl,
822
847
  shareText,
823
- preview,
824
848
  downloadUrl,
825
849
  downloadFilename,
826
850
  disabled,
@@ -898,7 +922,6 @@ function ShareSheetDrawer({
898
922
  title,
899
923
  shareUrl,
900
924
  shareText,
901
- preview,
902
925
  downloadUrl,
903
926
  downloadFilename,
904
927
  className,