@dust-tt/sparkle 0.2.481-rc1 → 0.2.481-rc2

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.
@@ -2,8 +2,6 @@ import React from "react";
2
2
  interface InteractiveImageProps {
3
3
  alt: string;
4
4
  isLoading?: boolean;
5
- onCopyError?: (error: unknown) => void;
6
- onDownloadError?: (error: unknown) => void;
7
5
  src?: string;
8
6
  title: string;
9
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"InteractiveImage.d.ts","sourceRoot":"","sources":["../../../src/components/InteractiveImage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAiB1B,UAAU,qBAAqB;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAC3C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,GAAG,EACH,SAAiB,EACjB,GAAG,EACH,GAAG,KAAK,EACT,EAAE,qBAAqB,qBAgCvB"}
1
+ {"version":3,"file":"InteractiveImage.d.ts","sourceRoot":"","sources":["../../../src/components/InteractiveImage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAY1B,UAAU,qBAAqB;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,GAAG,EACH,SAAiB,EACjB,GAAG,EACH,GAAG,KAAK,EACT,EAAE,qBAAqB,qBAsCvB"}
@@ -1,8 +1,7 @@
1
1
  import { __assign, __awaiter, __generator, __read, __rest } from "tslib";
2
2
  import React from "react";
3
3
  import { Dialog, DialogContent, DialogTrigger, IconButton, Spinner, } from "../components";
4
- import { useCopyToClipboard } from "../hooks";
5
- import { ArrowDownOnSquareIcon, ClipboardCheckIcon, ClipboardIcon, } from "../icons/app";
4
+ import { ArrowDownOnSquareIcon } from "../icons/app";
6
5
  import { cn } from "../lib/utils";
7
6
  export function InteractiveImage(_a) {
8
7
  var alt = _a.alt, _b = _a.isLoading, isLoading = _b === void 0 ? false : _b, src = _a.src, props = __rest(_a, ["alt", "isLoading", "src"]);
@@ -21,7 +20,7 @@ export function InteractiveImage(_a) {
21
20
  }
22
21
  handleZoomToggle();
23
22
  }, src: src }, props)))),
24
- React.createElement(DialogContent, { className: "s-w-auto s-max-w-none s-border-0 s-outline-none s-ring-0 focus:s-outline-none focus:s-ring-0" },
23
+ React.createElement(DialogContent, { className: cn("s-w-auto s-max-w-none s-border-0 s-outline-none s-ring-0", "focus:s-outline-none focus:s-ring-0"), size: "xl" },
25
24
  React.createElement("img", { src: src, alt: alt, className: "s-object-contain" }))));
26
25
  }
27
26
  function LoadingImage() {
@@ -30,91 +29,26 @@ function LoadingImage() {
30
29
  }
31
30
  function ImagePreview(_a) {
32
31
  var _this = this;
33
- var isLoading = _a.isLoading, onClick = _a.onClick, alt = _a.alt, src = _a.src, title = _a.title, onCopyError = _a.onCopyError, onDownloadError = _a.onDownloadError;
34
- var _b = __read(useCopyToClipboard(), 2), isCopied = _b[0], copyToClipboard = _b[1];
35
- var handleCopy = function () { return __awaiter(_this, void 0, void 0, function () {
36
- var response, blob, error_1;
37
- var _a;
38
- return __generator(this, function (_b) {
39
- switch (_b.label) {
40
- case 0:
41
- _b.trys.push([0, 4, , 5]);
42
- if (!src) {
43
- return [2 /*return*/];
44
- }
45
- return [4 /*yield*/, fetch(src)];
46
- case 1:
47
- response = _b.sent();
48
- return [4 /*yield*/, response.blob()];
49
- case 2:
50
- blob = _b.sent();
51
- // Copy to clipboard.
52
- return [4 /*yield*/, copyToClipboard(new ClipboardItem((_a = {},
53
- _a[blob.type] = blob,
54
- _a)))];
55
- case 3:
56
- // Copy to clipboard.
57
- _b.sent();
58
- return [3 /*break*/, 5];
59
- case 4:
60
- error_1 = _b.sent();
61
- onCopyError === null || onCopyError === void 0 ? void 0 : onCopyError(error_1);
62
- return [3 /*break*/, 5];
63
- case 5: return [2 /*return*/];
64
- }
65
- });
66
- }); };
67
- var handleDownload = function () { return __awaiter(_this, void 0, void 0, function () {
68
- var response, blob, url, link, error_2;
32
+ var isLoading = _a.isLoading, onClick = _a.onClick, alt = _a.alt, src = _a.src, title = _a.title;
33
+ var handleDownload = React.useCallback(function () { return __awaiter(_this, void 0, void 0, function () {
34
+ var link;
69
35
  return __generator(this, function (_a) {
70
- switch (_a.label) {
71
- case 0:
72
- _a.trys.push([0, 3, , 4]);
73
- if (!src) {
74
- return [2 /*return*/];
75
- }
76
- return [4 /*yield*/, fetch(src)];
77
- case 1:
78
- response = _a.sent();
79
- return [4 /*yield*/, response.blob()];
80
- case 2:
81
- blob = _a.sent();
82
- url = window.URL.createObjectURL(blob);
83
- link = document.createElement("a");
84
- link.href = url;
85
- // Extract filename from URL or use a default.
86
- link.download = title;
87
- // Trigger download.
88
- document.body.appendChild(link);
89
- link.click();
90
- // Cleanup.
91
- document.body.removeChild(link);
92
- window.URL.revokeObjectURL(url);
93
- return [3 /*break*/, 4];
94
- case 3:
95
- error_2 = _a.sent();
96
- onDownloadError === null || onDownloadError === void 0 ? void 0 : onDownloadError(error_2);
97
- return [3 /*break*/, 4];
98
- case 4: return [2 /*return*/];
36
+ if (!src) {
37
+ return [2 /*return*/];
99
38
  }
39
+ link = document.createElement("a");
40
+ link.href = src;
41
+ link.download = title;
42
+ document.body.appendChild(link);
43
+ link.click();
44
+ document.body.removeChild(link);
45
+ return [2 /*return*/];
100
46
  });
101
- }); };
47
+ }); }, [src, title]);
102
48
  return (React.createElement("div", { onClick: onClick, className: cn("s-group/preview s-relative s-h-full s-w-full s-overflow-hidden s-rounded-2xl s-bg-muted-background dark:s-bg-muted-background-night", !isLoading && "s-cursor-pointer") }, isLoading ? (React.createElement(LoadingImage, null)) : (React.createElement(React.Fragment, null,
103
49
  React.createElement("img", { src: src, alt: alt, className: "s-h-full s-w-full s-rounded-2xl s-object-cover" }),
104
50
  React.createElement("div", { className: "s-absolute s-inset-0 s-bg-black s-opacity-0 s-transition-opacity s-duration-200 group-hover/preview:s-opacity-40" }),
105
51
  React.createElement("div", { className: "s-absolute s-right-3 s-top-3 s-z-10 s-flex s-opacity-0 s-transition-opacity s-duration-200 group-hover/preview:s-opacity-100" },
106
- React.createElement(IconButton, { icon: isCopied ? ClipboardCheckIcon : ClipboardIcon, className: "s-text-white", tooltip: isCopied ? "Copied!" : "Copy to clipboard", size: "xs", onClick: function (e) { return __awaiter(_this, void 0, void 0, function () {
107
- return __generator(this, function (_a) {
108
- switch (_a.label) {
109
- case 0:
110
- e.stopPropagation(); // Prevent image zoom.
111
- return [4 /*yield*/, handleCopy()];
112
- case 1:
113
- _a.sent();
114
- return [2 /*return*/];
115
- }
116
- });
117
- }); } }),
118
52
  React.createElement(IconButton, { icon: ArrowDownOnSquareIcon, className: "s-text-white", tooltip: "Download", size: "xs", onClick: function (e) { return __awaiter(_this, void 0, void 0, function () {
119
53
  return __generator(this, function (_a) {
120
54
  switch (_a.label) {
@@ -1 +1 @@
1
- {"version":3,"file":"InteractiveImage.js","sourceRoot":"","sources":["../../../src/components/InteractiveImage.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"InteractiveImage.js","sourceRoot":"","sources":["../../../src/components/InteractiveImage.tsx"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dust-tt/sparkle",
3
- "version": "0.2.481-rc1",
3
+ "version": "0.2.481-rc2",
4
4
  "scripts": {
5
5
  "build": "rm -rf dist && npm run tailwind && npm run build:esm && npm run build:cjs",
6
6
  "tailwind": "tailwindcss -i ./src/styles/tailwind.css -o dist/sparkle.css",
@@ -7,19 +7,12 @@ import {
7
7
  IconButton,
8
8
  Spinner,
9
9
  } from "@sparkle/components/";
10
- import { useCopyToClipboard } from "@sparkle/hooks";
11
- import {
12
- ArrowDownOnSquareIcon,
13
- ClipboardCheckIcon,
14
- ClipboardIcon,
15
- } from "@sparkle/icons/app";
10
+ import { ArrowDownOnSquareIcon } from "@sparkle/icons/app";
16
11
  import { cn } from "@sparkle/lib/utils";
17
12
 
18
13
  interface InteractiveImageProps {
19
14
  alt: string;
20
15
  isLoading?: boolean;
21
- onCopyError?: (error: unknown) => void;
22
- onDownloadError?: (error: unknown) => void;
23
16
  src?: string;
24
17
  title: string;
25
18
  }
@@ -56,7 +49,13 @@ export function InteractiveImage({
56
49
  />
57
50
  </div>
58
51
  </DialogTrigger>
59
- <DialogContent className="s-w-auto s-max-w-none s-border-0 s-outline-none s-ring-0 focus:s-outline-none focus:s-ring-0">
52
+ <DialogContent
53
+ className={cn(
54
+ "s-w-auto s-max-w-none s-border-0 s-outline-none s-ring-0",
55
+ "focus:s-outline-none focus:s-ring-0"
56
+ )}
57
+ size="xl"
58
+ >
60
59
  <img src={src} alt={alt} className="s-object-contain" />
61
60
  </DialogContent>
62
61
  </Dialog>
@@ -81,61 +80,20 @@ function ImagePreview({
81
80
  alt,
82
81
  src,
83
82
  title,
84
- onCopyError,
85
- onDownloadError,
86
83
  }: ImagePreviewProps) {
87
- const [isCopied, copyToClipboard] = useCopyToClipboard();
88
-
89
- const handleCopy = async () => {
90
- try {
91
- if (!src) {
92
- return;
93
- }
94
-
95
- // Fetch the image as a blob.
96
- const response = await fetch(src);
97
- const blob = await response.blob();
98
-
99
- // Copy to clipboard.
100
- await copyToClipboard(
101
- new ClipboardItem({
102
- [blob.type]: blob,
103
- })
104
- );
105
- } catch (error) {
106
- onCopyError?.(error);
84
+ const handleDownload = React.useCallback(async () => {
85
+ if (!src) {
86
+ return;
107
87
  }
108
- };
109
-
110
- const handleDownload = async () => {
111
- try {
112
- if (!src) {
113
- return;
114
- }
115
88
 
116
- // Fetch the image.
117
- const response = await fetch(src);
118
- const blob = await response.blob();
119
-
120
- // Create a download link.
121
- const url = window.URL.createObjectURL(blob);
122
- const link = document.createElement("a");
123
- link.href = url;
124
-
125
- // Extract filename from URL or use a default.
126
- link.download = title;
127
-
128
- // Trigger download.
129
- document.body.appendChild(link);
130
- link.click();
131
-
132
- // Cleanup.
133
- document.body.removeChild(link);
134
- window.URL.revokeObjectURL(url);
135
- } catch (error) {
136
- onDownloadError?.(error);
137
- }
138
- };
89
+ // Create a hidden link and click it.
90
+ const link = document.createElement("a");
91
+ link.href = src;
92
+ link.download = title;
93
+ document.body.appendChild(link);
94
+ link.click();
95
+ document.body.removeChild(link);
96
+ }, [src, title]);
139
97
 
140
98
  return (
141
99
  <div
@@ -158,16 +116,6 @@ function ImagePreview({
158
116
  <div className="s-absolute s-inset-0 s-bg-black s-opacity-0 s-transition-opacity s-duration-200 group-hover/preview:s-opacity-40" />
159
117
  {/* Icon container - only visible on hover */}
160
118
  <div className="s-absolute s-right-3 s-top-3 s-z-10 s-flex s-opacity-0 s-transition-opacity s-duration-200 group-hover/preview:s-opacity-100">
161
- <IconButton
162
- icon={isCopied ? ClipboardCheckIcon : ClipboardIcon}
163
- className="s-text-white"
164
- tooltip={isCopied ? "Copied!" : "Copy to clipboard"}
165
- size="xs"
166
- onClick={async (e) => {
167
- e.stopPropagation(); // Prevent image zoom.
168
- await handleCopy();
169
- }}
170
- />
171
119
  <IconButton
172
120
  icon={ArrowDownOnSquareIcon}
173
121
  className="s-text-white"