react-sharesheet 1.8.0 → 1.9.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 +9 -0
- package/dist/content.d.mts +3 -3
- package/dist/content.d.ts +3 -3
- package/dist/content.js +79 -15
- package/dist/content.js.map +1 -1
- package/dist/content.mjs +79 -15
- 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 +85 -15
- package/dist/drawer.js.map +1 -1
- package/dist/drawer.mjs +85 -15
- package/dist/drawer.mjs.map +1 -1
- package/dist/{headless-BTnsV8ZO.d.ts → headless-lxSw27f0.d.ts} +6 -2
- package/dist/{headless-DzKMJ3eW.d.mts → headless-x5iUF86E.d.mts} +6 -2
- package/dist/headless.d.mts +2 -2
- package/dist/headless.d.ts +2 -2
- package/dist/headless.js +41 -2
- package/dist/headless.js.map +1 -1
- package/dist/headless.mjs +41 -2
- 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 +85 -15
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +85 -15
- package/dist/index.mjs.map +1 -1
- package/dist/{platforms-BgGzSDRk.d.mts → platforms-BtmTZmgl.d.mts} +10 -2
- package/dist/{platforms-BgGzSDRk.d.ts → platforms-BtmTZmgl.d.ts} +10 -2
- package/package.json +18 -16
- package/src/ShareSheetContent.tsx +45 -15
- package/src/ShareSheetDrawer.tsx +6 -0
- package/src/hooks.ts +60 -2
- package/src/types.ts +9 -1
|
@@ -17,7 +17,7 @@ declare const CSS_VAR_UI_DEFAULTS: {
|
|
|
17
17
|
readonly "--sharesheet-overlay-bg": "rgba(0, 0, 0, 0.7)";
|
|
18
18
|
readonly "--sharesheet-drawer-bg": "#09090b";
|
|
19
19
|
readonly "--sharesheet-drawer-border": "#27272a";
|
|
20
|
-
readonly "--sharesheet-handle-bg": "
|
|
20
|
+
readonly "--sharesheet-handle-bg": "rgba(255, 255, 255, 0.2)";
|
|
21
21
|
readonly "--sharesheet-title-color": "#ffffff";
|
|
22
22
|
readonly "--sharesheet-subtitle-color": "#a1a1aa";
|
|
23
23
|
readonly "--sharesheet-button-label-color": "#ffffff";
|
|
@@ -85,6 +85,12 @@ interface ShareSheetContentProps {
|
|
|
85
85
|
downloadUrl?: string | null;
|
|
86
86
|
/** Filename for downloaded file */
|
|
87
87
|
downloadFilename?: string;
|
|
88
|
+
/** Custom preview image URL (skips OG fetching if provided) */
|
|
89
|
+
previewImage?: string | null;
|
|
90
|
+
/** File to share via native share (data URL or Blob) - takes priority over URL sharing */
|
|
91
|
+
shareFile?: string | Blob | null;
|
|
92
|
+
/** Filename for the shared file */
|
|
93
|
+
shareFilename?: string;
|
|
88
94
|
/** Custom class name for the container (shorthand for classNames.root) */
|
|
89
95
|
className?: string;
|
|
90
96
|
/** Override class names for sub-components */
|
|
@@ -99,6 +105,8 @@ interface ShareSheetContentProps {
|
|
|
99
105
|
onCopy?: () => void;
|
|
100
106
|
/** Called when download starts */
|
|
101
107
|
onDownload?: () => void;
|
|
108
|
+
/** Called on every share option click, with the option id (analytics-friendly) */
|
|
109
|
+
onShare?: (option: ShareOption) => void;
|
|
102
110
|
/** Hide specific share options */
|
|
103
111
|
hide?: ShareOption[];
|
|
104
112
|
/** Show only these platforms, in this exact order */
|
|
@@ -199,7 +207,7 @@ declare const CSS_VAR_DEFAULTS: {
|
|
|
199
207
|
readonly "--sharesheet-overlay-bg": "rgba(0, 0, 0, 0.7)";
|
|
200
208
|
readonly "--sharesheet-drawer-bg": "#09090b";
|
|
201
209
|
readonly "--sharesheet-drawer-border": "#27272a";
|
|
202
|
-
readonly "--sharesheet-handle-bg": "
|
|
210
|
+
readonly "--sharesheet-handle-bg": "rgba(255, 255, 255, 0.2)";
|
|
203
211
|
readonly "--sharesheet-title-color": "#ffffff";
|
|
204
212
|
readonly "--sharesheet-subtitle-color": "#a1a1aa";
|
|
205
213
|
readonly "--sharesheet-button-label-color": "#ffffff";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-sharesheet",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.0",
|
|
4
4
|
"description": "A mobile-first share sheet for React with native share support, Open Graph previews, 15+ social platforms, and headless APIs. Tailwind-styled by default, fully customizable.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
@@ -35,6 +35,21 @@
|
|
|
35
35
|
"require": "./dist/headless.js"
|
|
36
36
|
}
|
|
37
37
|
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build": "tsup",
|
|
40
|
+
"dev": "tsup --watch",
|
|
41
|
+
"test": "vitest run",
|
|
42
|
+
"test:watch": "vitest",
|
|
43
|
+
"test:coverage": "vitest run --coverage",
|
|
44
|
+
"prepack": "npm run clean && npm run build",
|
|
45
|
+
"prepublishOnly": "pnpm run type-check && pnpm run test && pnpm run build",
|
|
46
|
+
"publish-patch": "npm version patch && npm publish",
|
|
47
|
+
"publish-minor": "npm version minor && npm publish",
|
|
48
|
+
"publish-major": "npm version major && npm publish",
|
|
49
|
+
"release": "npm publish",
|
|
50
|
+
"type-check": "tsc --noEmit",
|
|
51
|
+
"clean": "rm -rf dist"
|
|
52
|
+
},
|
|
38
53
|
"repository": {
|
|
39
54
|
"type": "git",
|
|
40
55
|
"url": "https://github.com/gwendall/react-sharesheet.git"
|
|
@@ -85,18 +100,5 @@
|
|
|
85
100
|
"dist",
|
|
86
101
|
"src",
|
|
87
102
|
"README.md"
|
|
88
|
-
]
|
|
89
|
-
|
|
90
|
-
"build": "tsup",
|
|
91
|
-
"dev": "tsup --watch",
|
|
92
|
-
"test": "vitest run",
|
|
93
|
-
"test:watch": "vitest",
|
|
94
|
-
"test:coverage": "vitest run --coverage",
|
|
95
|
-
"publish-patch": "npm version patch && npm publish",
|
|
96
|
-
"publish-minor": "npm version minor && npm publish",
|
|
97
|
-
"publish-major": "npm version major && npm publish",
|
|
98
|
-
"release": "npm publish",
|
|
99
|
-
"type-check": "tsc --noEmit",
|
|
100
|
-
"clean": "rm -rf dist"
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
+
]
|
|
104
|
+
}
|
|
@@ -28,9 +28,9 @@ const defaultClasses = {
|
|
|
28
28
|
header: "text-center mb-2",
|
|
29
29
|
title: "text-2xl font-black",
|
|
30
30
|
subtitle: "mt-1 text-sm",
|
|
31
|
-
preview: "flex justify-center
|
|
31
|
+
preview: "flex justify-center my-4 px-4",
|
|
32
32
|
previewSkeleton: "rounded-xl overflow-hidden",
|
|
33
|
-
previewImage: "border border-white/10",
|
|
33
|
+
previewImage: "border border-white/10 rounded-xl",
|
|
34
34
|
previewMeta: "",
|
|
35
35
|
grid: "px-2 py-6 flex flex-row items-start gap-4 gap-y-6 flex-wrap justify-center",
|
|
36
36
|
button: "flex flex-col items-center gap-0 text-xs w-[60px] outline-none cursor-pointer group",
|
|
@@ -64,12 +64,16 @@ export function ShareSheetContent({
|
|
|
64
64
|
shareText,
|
|
65
65
|
downloadUrl,
|
|
66
66
|
downloadFilename,
|
|
67
|
+
previewImage,
|
|
68
|
+
shareFile,
|
|
69
|
+
shareFilename,
|
|
67
70
|
className,
|
|
68
71
|
classNames = {},
|
|
69
72
|
buttonSize = DEFAULT_BUTTON_SIZE,
|
|
70
73
|
iconSize = DEFAULT_ICON_SIZE,
|
|
71
74
|
onNativeShare,
|
|
72
75
|
onCopy,
|
|
76
|
+
onShare,
|
|
73
77
|
onDownload,
|
|
74
78
|
hide = [],
|
|
75
79
|
show,
|
|
@@ -79,8 +83,8 @@ export function ShareSheetContent({
|
|
|
79
83
|
const [imageLoaded, setImageLoaded] = useState(false);
|
|
80
84
|
const [imageError, setImageError] = useState(false);
|
|
81
85
|
|
|
82
|
-
//
|
|
83
|
-
const { ogData, loading: ogLoading } = useOGData(shareUrl);
|
|
86
|
+
// Only fetch OG data if previewImage is not provided
|
|
87
|
+
const { ogData, loading: ogLoading } = useOGData(previewImage ? undefined : shareUrl);
|
|
84
88
|
|
|
85
89
|
const handleImageLoad = useCallback(() => {
|
|
86
90
|
setImageLoaded(true);
|
|
@@ -96,6 +100,8 @@ export function ShareSheetContent({
|
|
|
96
100
|
downloadUrl,
|
|
97
101
|
downloadFilename,
|
|
98
102
|
emailSubject: shareText,
|
|
103
|
+
shareFile,
|
|
104
|
+
shareFilename,
|
|
99
105
|
onNativeShare,
|
|
100
106
|
onCopy,
|
|
101
107
|
onDownload,
|
|
@@ -151,11 +157,14 @@ export function ShareSheetContent({
|
|
|
151
157
|
// Use CSS var with fallback to platform color
|
|
152
158
|
bgColor: cssVar(PLATFORM_CSS_VARS[id], PLATFORM_COLORS[id].bg),
|
|
153
159
|
textColor: PLATFORM_COLORS[id].text,
|
|
154
|
-
onClick:
|
|
160
|
+
onClick: () => {
|
|
161
|
+
onShare?.(id);
|
|
162
|
+
shareActions[id]();
|
|
163
|
+
},
|
|
155
164
|
condition,
|
|
156
165
|
};
|
|
157
166
|
});
|
|
158
|
-
}, [iconSize, labels, icons, dynamicLabels, shareActions, shareSheet.canNativeShare, shareSheet.platformAvailability, downloadUrl]);
|
|
167
|
+
}, [iconSize, labels, icons, dynamicLabels, shareActions, onShare, shareSheet.canNativeShare, shareSheet.platformAvailability, downloadUrl]);
|
|
159
168
|
|
|
160
169
|
const visibleButtons = useMemo(() => {
|
|
161
170
|
// If show is provided, use its order
|
|
@@ -184,11 +193,13 @@ export function ShareSheetContent({
|
|
|
184
193
|
|
|
185
194
|
// Render OG preview
|
|
186
195
|
const renderPreview = () => {
|
|
187
|
-
|
|
196
|
+
// Use previewImage if provided, otherwise use OG data
|
|
197
|
+
const ogImage = previewImage || ogData?.image;
|
|
188
198
|
const hasImage = ogImage && !imageError;
|
|
199
|
+
const isLoading = !previewImage && ogLoading;
|
|
189
200
|
|
|
190
|
-
// Loading state
|
|
191
|
-
if (
|
|
201
|
+
// Loading state (only when fetching OG data, not when previewImage is provided)
|
|
202
|
+
if (isLoading) {
|
|
192
203
|
return (
|
|
193
204
|
<div style={{ display: "flex", flexDirection: "column", alignItems: "center", width: "100%" }}>
|
|
194
205
|
<div
|
|
@@ -221,8 +232,8 @@ export function ShareSheetContent({
|
|
|
221
232
|
);
|
|
222
233
|
}
|
|
223
234
|
|
|
224
|
-
// No
|
|
225
|
-
if (!
|
|
235
|
+
// No image available - show link placeholder (skip if previewImage was provided)
|
|
236
|
+
if (!hasImage) {
|
|
226
237
|
return (
|
|
227
238
|
<div style={{ display: "flex", flexDirection: "column", alignItems: "center", width: "100%" }}>
|
|
228
239
|
<div
|
|
@@ -274,7 +285,27 @@ export function ShareSheetContent({
|
|
|
274
285
|
);
|
|
275
286
|
}
|
|
276
287
|
|
|
277
|
-
//
|
|
288
|
+
// If previewImage is a data URL, show it directly (no preloading needed)
|
|
289
|
+
const isDataUrl = typeof ogImage === "string" && ogImage.startsWith("data:");
|
|
290
|
+
if (isDataUrl) {
|
|
291
|
+
return (
|
|
292
|
+
<div style={{ display: "flex", flexDirection: "column", alignItems: "center", width: "100%" }}>
|
|
293
|
+
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
294
|
+
<img
|
|
295
|
+
src={ogImage}
|
|
296
|
+
alt="Preview"
|
|
297
|
+
className={cn(defaultClasses.previewImage, classNames.previewImage)}
|
|
298
|
+
style={{
|
|
299
|
+
width: "100%",
|
|
300
|
+
maxWidth: "320px",
|
|
301
|
+
height: "auto",
|
|
302
|
+
}}
|
|
303
|
+
/>
|
|
304
|
+
</div>
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Image loading state (for remote URLs)
|
|
278
309
|
if (!imageLoaded) {
|
|
279
310
|
return (
|
|
280
311
|
<div style={{ display: "flex", flexDirection: "column", alignItems: "center", width: "100%" }}>
|
|
@@ -308,7 +339,7 @@ export function ShareSheetContent({
|
|
|
308
339
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
309
340
|
<img
|
|
310
341
|
src={ogImage}
|
|
311
|
-
alt={ogData
|
|
342
|
+
alt={ogData?.title || "Preview"}
|
|
312
343
|
onLoad={handleImageLoad}
|
|
313
344
|
onError={handleImageError}
|
|
314
345
|
style={{ display: "none" }}
|
|
@@ -323,13 +354,12 @@ export function ShareSheetContent({
|
|
|
323
354
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
324
355
|
<img
|
|
325
356
|
src={ogImage}
|
|
326
|
-
alt={ogData
|
|
357
|
+
alt={ogData?.title || "Preview"}
|
|
327
358
|
className={cn(defaultClasses.previewImage, classNames.previewImage, "sharesheet-fadein")}
|
|
328
359
|
style={{
|
|
329
360
|
width: "100%",
|
|
330
361
|
maxWidth: "320px",
|
|
331
362
|
height: "auto",
|
|
332
|
-
borderRadius: "12px",
|
|
333
363
|
}}
|
|
334
364
|
/>
|
|
335
365
|
</div>
|
package/src/ShareSheetDrawer.tsx
CHANGED
|
@@ -40,6 +40,9 @@ export function ShareSheetDrawer({
|
|
|
40
40
|
shareText,
|
|
41
41
|
downloadUrl,
|
|
42
42
|
downloadFilename,
|
|
43
|
+
previewImage,
|
|
44
|
+
shareFile,
|
|
45
|
+
shareFilename,
|
|
43
46
|
disabled,
|
|
44
47
|
children,
|
|
45
48
|
open: controlledOpen,
|
|
@@ -111,6 +114,9 @@ export function ShareSheetDrawer({
|
|
|
111
114
|
shareText={shareText}
|
|
112
115
|
downloadUrl={downloadUrl}
|
|
113
116
|
downloadFilename={downloadFilename}
|
|
117
|
+
previewImage={previewImage}
|
|
118
|
+
shareFile={shareFile}
|
|
119
|
+
shareFilename={shareFilename}
|
|
114
120
|
className={className}
|
|
115
121
|
classNames={classNames}
|
|
116
122
|
buttonSize={buttonSize}
|
package/src/hooks.ts
CHANGED
|
@@ -50,6 +50,10 @@ export interface UseShareSheetOptions {
|
|
|
50
50
|
downloadFilename?: string;
|
|
51
51
|
/** Email subject (optional) */
|
|
52
52
|
emailSubject?: string;
|
|
53
|
+
/** File to share via native share (data URL or Blob) - takes priority over URL sharing */
|
|
54
|
+
shareFile?: string | Blob | null;
|
|
55
|
+
/** Filename for the shared file */
|
|
56
|
+
shareFilename?: string;
|
|
53
57
|
/** Callback after native share */
|
|
54
58
|
onNativeShare?: () => void;
|
|
55
59
|
/** Callback after copy */
|
|
@@ -68,6 +72,8 @@ export function useShareSheet({
|
|
|
68
72
|
downloadUrl,
|
|
69
73
|
downloadFilename,
|
|
70
74
|
emailSubject = "Share",
|
|
75
|
+
shareFile,
|
|
76
|
+
shareFilename = "share.png",
|
|
71
77
|
onNativeShare,
|
|
72
78
|
onCopy,
|
|
73
79
|
onDownload,
|
|
@@ -105,12 +111,64 @@ export function useShareSheet({
|
|
|
105
111
|
}, [safeUrl, onCopy]);
|
|
106
112
|
|
|
107
113
|
const nativeShare = useCallback(async () => {
|
|
108
|
-
if (!safeUrl) return;
|
|
109
114
|
const nav = navigator as Navigator & {
|
|
110
115
|
share?: (data: ShareData) => Promise<void>;
|
|
116
|
+
canShare?: (data: ShareData) => boolean;
|
|
111
117
|
};
|
|
112
118
|
if (!("share" in nav) || typeof nav.share !== "function") return;
|
|
119
|
+
|
|
113
120
|
try {
|
|
121
|
+
// If shareFile is provided, try to share as a file
|
|
122
|
+
if (shareFile) {
|
|
123
|
+
let blob: Blob;
|
|
124
|
+
|
|
125
|
+
// Convert data URL to Blob if needed
|
|
126
|
+
if (typeof shareFile === "string" && shareFile.startsWith("data:")) {
|
|
127
|
+
const response = await fetch(shareFile);
|
|
128
|
+
blob = await response.blob();
|
|
129
|
+
} else if (shareFile instanceof Blob) {
|
|
130
|
+
blob = shareFile;
|
|
131
|
+
} else {
|
|
132
|
+
// Invalid shareFile, fall back to URL sharing
|
|
133
|
+
if (!safeUrl) return;
|
|
134
|
+
await nav.share({
|
|
135
|
+
title: shareText,
|
|
136
|
+
text: shareText,
|
|
137
|
+
url: safeUrl,
|
|
138
|
+
});
|
|
139
|
+
onNativeShare?.();
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Create a File from the Blob
|
|
144
|
+
const file = new File([blob], shareFilename, { type: blob.type || "image/png" });
|
|
145
|
+
|
|
146
|
+
// Check if file sharing is supported
|
|
147
|
+
const shareData: ShareData = {
|
|
148
|
+
files: [file],
|
|
149
|
+
title: shareText,
|
|
150
|
+
text: shareText,
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
if (nav.canShare && !nav.canShare(shareData)) {
|
|
154
|
+
// File sharing not supported, fall back to URL sharing
|
|
155
|
+
if (!safeUrl) return;
|
|
156
|
+
await nav.share({
|
|
157
|
+
title: shareText,
|
|
158
|
+
text: shareText,
|
|
159
|
+
url: safeUrl,
|
|
160
|
+
});
|
|
161
|
+
onNativeShare?.();
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
await nav.share(shareData);
|
|
166
|
+
onNativeShare?.();
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Fall back to URL sharing
|
|
171
|
+
if (!safeUrl) return;
|
|
114
172
|
await nav.share({
|
|
115
173
|
title: shareText,
|
|
116
174
|
text: shareText,
|
|
@@ -120,7 +178,7 @@ export function useShareSheet({
|
|
|
120
178
|
} catch {
|
|
121
179
|
// user canceled or share failed -> ignore
|
|
122
180
|
}
|
|
123
|
-
}, [safeUrl, shareText, onNativeShare]);
|
|
181
|
+
}, [safeUrl, shareText, shareFile, shareFilename, onNativeShare]);
|
|
124
182
|
|
|
125
183
|
const downloadFile = useCallback(async () => {
|
|
126
184
|
const url = (downloadUrl ?? "").trim();
|
package/src/types.ts
CHANGED
|
@@ -21,7 +21,7 @@ export const CSS_VAR_UI_DEFAULTS = {
|
|
|
21
21
|
[CSS_VARS_UI.overlayBg]: "rgba(0, 0, 0, 0.7)",
|
|
22
22
|
[CSS_VARS_UI.drawerBg]: "#09090b",
|
|
23
23
|
[CSS_VARS_UI.drawerBorder]: "#27272a",
|
|
24
|
-
[CSS_VARS_UI.handleBg]: "
|
|
24
|
+
[CSS_VARS_UI.handleBg]: "rgba(255, 255, 255, 0.2)",
|
|
25
25
|
[CSS_VARS_UI.titleColor]: "#ffffff",
|
|
26
26
|
[CSS_VARS_UI.subtitleColor]: "#a1a1aa",
|
|
27
27
|
[CSS_VARS_UI.buttonLabelColor]: "#ffffff",
|
|
@@ -108,6 +108,12 @@ export interface ShareSheetContentProps {
|
|
|
108
108
|
downloadUrl?: string | null;
|
|
109
109
|
/** Filename for downloaded file */
|
|
110
110
|
downloadFilename?: string;
|
|
111
|
+
/** Custom preview image URL (skips OG fetching if provided) */
|
|
112
|
+
previewImage?: string | null;
|
|
113
|
+
/** File to share via native share (data URL or Blob) - takes priority over URL sharing */
|
|
114
|
+
shareFile?: string | Blob | null;
|
|
115
|
+
/** Filename for the shared file */
|
|
116
|
+
shareFilename?: string;
|
|
111
117
|
/** Custom class name for the container (shorthand for classNames.root) */
|
|
112
118
|
className?: string;
|
|
113
119
|
/** Override class names for sub-components */
|
|
@@ -122,6 +128,8 @@ export interface ShareSheetContentProps {
|
|
|
122
128
|
onCopy?: () => void;
|
|
123
129
|
/** Called when download starts */
|
|
124
130
|
onDownload?: () => void;
|
|
131
|
+
/** Called on every share option click, with the option id (analytics-friendly) */
|
|
132
|
+
onShare?: (option: ShareOption) => void;
|
|
125
133
|
/** Hide specific share options */
|
|
126
134
|
hide?: ShareOption[];
|
|
127
135
|
/** Show only these platforms, in this exact order */
|