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

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;AAqD1B,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,qBA8CvB"}
@@ -1,9 +1,39 @@
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";
6
+ function DownloadButton(_a) {
7
+ var _this = this;
8
+ var className = _a.className, _b = _a.size, size = _b === void 0 ? "xs" : _b, src = _a.src, title = _a.title;
9
+ var handleDownload = React.useCallback(function () { return __awaiter(_this, void 0, void 0, function () {
10
+ var link;
11
+ return __generator(this, function (_a) {
12
+ if (!src) {
13
+ return [2 /*return*/];
14
+ }
15
+ link = document.createElement("a");
16
+ link.href = src;
17
+ link.download = title;
18
+ document.body.appendChild(link);
19
+ link.click();
20
+ document.body.removeChild(link);
21
+ return [2 /*return*/];
22
+ });
23
+ }); }, [src, title]);
24
+ return (React.createElement(IconButton, { icon: ArrowDownOnSquareIcon, className: cn("s-text-white", className), tooltip: "Download", size: size, onClick: function (e) { return __awaiter(_this, void 0, void 0, function () {
25
+ return __generator(this, function (_a) {
26
+ switch (_a.label) {
27
+ case 0:
28
+ e.stopPropagation(); // Prevent image zoom.
29
+ return [4 /*yield*/, handleDownload()];
30
+ case 1:
31
+ _a.sent();
32
+ return [2 /*return*/];
33
+ }
34
+ });
35
+ }); } }));
36
+ }
7
37
  export function InteractiveImage(_a) {
8
38
  var alt = _a.alt, _b = _a.isLoading, isLoading = _b === void 0 ? false : _b, src = _a.src, props = __rest(_a, ["alt", "isLoading", "src"]);
9
39
  var _c = __read(React.useState(false), 2), isZoomed = _c[0], setIsZoomed = _c[1];
@@ -21,111 +51,23 @@ export function InteractiveImage(_a) {
21
51
  }
22
52
  handleZoomToggle();
23
53
  }, 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" },
25
- React.createElement("img", { src: src, alt: alt, className: "s-object-contain" }))));
54
+ 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", "s-rounded-none s-bg-transparent s-shadow-none"), size: "xl" },
55
+ React.createElement("div", { className: "s-flex s-flex-col" },
56
+ React.createElement("div", { className: "s-flex s-justify-end s-pb-2 s-pr-1 s-pt-1" },
57
+ React.createElement(DownloadButton, { src: src, title: props.title, size: "sm" })),
58
+ React.createElement("div", { className: "s-relative s-w-full" },
59
+ React.createElement("img", { src: src, alt: alt, className: "s-w-full s-object-contain" }))))));
26
60
  }
27
61
  function LoadingImage() {
28
62
  return (React.createElement("div", { className: "s-flex s-h-full s-w-full s-items-center s-justify-center" },
29
- React.createElement(Spinner, { variant: "dark", size: "sm" })));
63
+ React.createElement(Spinner, { variant: "dark", size: "md" })));
30
64
  }
31
65
  function ImagePreview(_a) {
32
- 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;
69
- 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*/];
99
- }
100
- });
101
- }); };
102
- 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,
66
+ var isLoading = _a.isLoading, onClick = _a.onClick, alt = _a.alt, src = _a.src, title = _a.title;
67
+ 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
68
  React.createElement("img", { src: src, alt: alt, className: "s-h-full s-w-full s-rounded-2xl s-object-cover" }),
104
- 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
- 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
- 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
- return __generator(this, function (_a) {
120
- switch (_a.label) {
121
- case 0:
122
- e.stopPropagation(); // Prevent image zoom.
123
- return [4 /*yield*/, handleDownload()];
124
- case 1:
125
- _a.sent();
126
- return [2 /*return*/];
127
- }
128
- });
129
- }); } }))))));
69
+ React.createElement("div", { className: cn("s-absolute s-inset-0 s-bg-gradient-to-b", "s-from-black/40 s-via-transparent s-to-black/40", "s-opacity-0 s-transition-opacity s-duration-200", "group-hover/preview:s-opacity-100") }),
70
+ React.createElement("div", { className: cn("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") },
71
+ React.createElement(DownloadButton, { src: src, title: title, size: "xs" }))))));
130
72
  }
131
73
  //# sourceMappingURL=InteractiveImage.js.map
@@ -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":";AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EACL,MAAM,EACN,aAAa,EACb,aAAa,EACb,UAAU,EACV,OAAO,GACR,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,EAAE,EAAE,MAAM,oBAAoB,CAAC;AASxC,SAAS,cAAc,CAAC,EAKF;IALtB,iBAgCC;QA/BC,SAAS,eAAA,EACT,YAAW,EAAX,IAAI,mBAAG,IAAI,KAAA,EACX,GAAG,SAAA,EACH,KAAK,WAAA;IAEL,IAAM,cAAc,GAAG,KAAK,CAAC,WAAW,CAAC;;;YACvC,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,sBAAO;YACT,CAAC;YAGK,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;YACzC,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC;YAChB,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;YACtB,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;YAChC,IAAI,CAAC,KAAK,EAAE,CAAC;YACb,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;;;SACjC,EAAE,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;IAEjB,OAAO,CACL,oBAAC,UAAU,IACT,IAAI,EAAE,qBAAqB,EAC3B,SAAS,EAAE,EAAE,CAAC,cAAc,EAAE,SAAS,CAAC,EACxC,OAAO,EAAC,UAAU,EAClB,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,UAAO,CAAC;;;;wBACf,CAAC,CAAC,eAAe,EAAE,CAAC,CAAC,sBAAsB;wBAC3C,qBAAM,cAAc,EAAE,EAAA;;wBAAtB,SAAsB,CAAC;;;;aACxB,GACD,CACH,CAAC;AACJ,CAAC;AASD,MAAM,UAAU,gBAAgB,CAAC,EAKT;IAJtB,IAAA,GAAG,SAAA,EACH,iBAAiB,EAAjB,SAAS,mBAAG,KAAK,KAAA,EACjB,GAAG,SAAA,EACA,KAAK,cAJuB,2BAKhC,CADS;IAEF,IAAA,KAAA,OAA0B,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAA,EAA9C,QAAQ,QAAA,EAAE,WAAW,QAAyB,CAAC;IAEtD,IAAM,gBAAgB,GAAG,KAAK,CAAC,WAAW,CAAC;QACzC,WAAW,CAAC,CAAC,QAAQ,CAAC,CAAC;IACzB,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;IAEf,OAAO,CACL,oBAAC,MAAM,IAAC,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE,gBAAgB;QACpD,oBAAC,aAAa,IAAC,OAAO;YACpB,6BAAK,SAAS,EAAC,+BAA+B;gBAC5C,oBAAC,YAAY,aACX,GAAG,EAAE,GAAG,EACR,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,UAAC,CAAC;wBACT,IAAI,SAAS,EAAE,CAAC;4BACd,CAAC,CAAC,cAAc,EAAE,CAAC;4BACnB,CAAC,CAAC,eAAe,EAAE,CAAC;4BACpB,OAAO;wBACT,CAAC;wBACD,gBAAgB,EAAE,CAAC;oBACrB,CAAC,EACD,GAAG,EAAE,GAAG,IACJ,KAAK,EACT,CACE,CACQ;QAChB,oBAAC,aAAa,IACZ,SAAS,EAAE,EAAE,CACX,0DAA0D,EAC1D,qCAAqC,EACrC,+CAA+C,CAChD,EACD,IAAI,EAAC,IAAI;YAET,6BAAK,SAAS,EAAC,mBAAmB;gBAChC,6BAAK,SAAS,EAAC,2CAA2C;oBACxD,oBAAC,cAAc,IAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,IAAI,EAAC,IAAI,GAAG,CACtD;gBACN,6BAAK,SAAS,EAAC,qBAAqB;oBAClC,6BAAK,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,SAAS,EAAC,2BAA2B,GAAG,CAC7D,CACF,CACQ,CACT,CACV,CAAC;AACJ,CAAC;AAED,SAAS,YAAY;IACnB,OAAO,CACL,6BAAK,SAAS,EAAC,0DAA0D;QACvE,oBAAC,OAAO,IAAC,OAAO,EAAC,MAAM,EAAC,IAAI,EAAC,IAAI,GAAG,CAChC,CACP,CAAC;AACJ,CAAC;AAMD,SAAS,YAAY,CAAC,EAMF;QALlB,SAAS,eAAA,EACT,OAAO,aAAA,EACP,GAAG,SAAA,EACH,GAAG,SAAA,EACH,KAAK,WAAA;IAEL,OAAO,CACL,6BACE,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,EAAE,CACX,8EAA8E,EAC9E,wDAAwD,EACxD,CAAC,SAAS,IAAI,kBAAkB,CACjC,IAEA,SAAS,CAAC,CAAC,CAAC,CACX,oBAAC,YAAY,OAAG,CACjB,CAAC,CAAC,CAAC,CACF;QACE,6BACE,GAAG,EAAE,GAAG,EACR,GAAG,EAAE,GAAG,EACR,SAAS,EAAC,gDAAgD,GAC1D;QAEF,6BACE,SAAS,EAAE,EAAE,CACX,yCAAyC,EACzC,iDAAiD,EACjD,iDAAiD,EACjD,mCAAmC,CACpC,GACD;QAEF,6BACE,SAAS,EAAE,EAAE,CACX,4CAA4C,EAC5C,iDAAiD,EACjD,mCAAmC,CACpC;YAED,oBAAC,cAAc,IAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAC,IAAI,GAAG,CAChD,CACL,CACJ,CACG,CACP,CAAC;AACJ,CAAC"}
package/dist/sparkle.css CHANGED
@@ -2311,6 +2311,10 @@ select {
2311
2311
  border-radius: 0.375rem;
2312
2312
  }
2313
2313
 
2314
+ .s-rounded-none {
2315
+ border-radius: 0px;
2316
+ }
2317
+
2314
2318
  .s-rounded-sm {
2315
2319
  border-radius: 0.125rem;
2316
2320
  }
@@ -2674,11 +2678,6 @@ select {
2674
2678
  background-color: rgb(255 255 255 / 0.8);
2675
2679
  }
2676
2680
 
2677
- .s-bg-black {
2678
- --tw-bg-opacity: 1;
2679
- background-color: rgb(0 0 0 / var(--tw-bg-opacity));
2680
- }
2681
-
2682
2681
  .s-bg-blue-100 {
2683
2682
  --tw-bg-opacity: 1;
2684
2683
  background-color: rgb(202 235 255 / var(--tw-bg-opacity));
@@ -3563,6 +3562,10 @@ select {
3563
3562
  background-color: rgb(169 184 169 / var(--tw-bg-opacity));
3564
3563
  }
3565
3564
 
3565
+ .s-bg-transparent {
3566
+ background-color: transparent;
3567
+ }
3568
+
3566
3569
  .s-bg-violet-100 {
3567
3570
  --tw-bg-opacity: 1;
3568
3571
  background-color: rgb(237 233 254 / var(--tw-bg-opacity));
@@ -3697,6 +3700,10 @@ select {
3697
3700
  background-color: rgb(254 240 138 / var(--tw-bg-opacity));
3698
3701
  }
3699
3702
 
3703
+ .s-bg-gradient-to-b {
3704
+ background-image: linear-gradient(to bottom, var(--tw-gradient-stops));
3705
+ }
3706
+
3700
3707
  .s-bg-gradient-to-r {
3701
3708
  background-image: linear-gradient(to right, var(--tw-gradient-stops));
3702
3709
  }
@@ -3709,6 +3716,12 @@ select {
3709
3716
  background-image: linear-gradient(90deg, #7AC6FF, #1C91FF, #a855f7, #4BABFF, #0A6CC6);
3710
3717
  }
3711
3718
 
3719
+ .s-from-black\/40 {
3720
+ --tw-gradient-from: rgb(0 0 0 / 0.4) var(--tw-gradient-from-position);
3721
+ --tw-gradient-to: rgb(0 0 0 / 0) var(--tw-gradient-to-position);
3722
+ --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
3723
+ }
3724
+
3712
3725
  .s-from-cyan-500 {
3713
3726
  --tw-gradient-from: #06b6d4 var(--tw-gradient-from-position);
3714
3727
  --tw-gradient-to: rgb(6 182 212 / 0) var(--tw-gradient-to-position);
@@ -3826,6 +3839,11 @@ select {
3826
3839
  --tw-gradient-stops: var(--tw-gradient-from), #04140A var(--tw-gradient-via-position), var(--tw-gradient-to);
3827
3840
  }
3828
3841
 
3842
+ .s-via-transparent {
3843
+ --tw-gradient-to: rgb(0 0 0 / 0) var(--tw-gradient-to-position);
3844
+ --tw-gradient-stops: var(--tw-gradient-from), transparent var(--tw-gradient-via-position), var(--tw-gradient-to);
3845
+ }
3846
+
3829
3847
  .s-via-warning-950 {
3830
3848
  --tw-gradient-to: rgb(34 10 4 / 0) var(--tw-gradient-to-position);
3831
3849
  --tw-gradient-stops: var(--tw-gradient-from), #220A04 var(--tw-gradient-via-position), var(--tw-gradient-to);
@@ -3835,6 +3853,10 @@ select {
3835
3853
  --tw-gradient-via-position: 50%;
3836
3854
  }
3837
3855
 
3856
+ .s-to-black\/40 {
3857
+ --tw-gradient-to: rgb(0 0 0 / 0.4) var(--tw-gradient-to-position);
3858
+ }
3859
+
3838
3860
  .s-to-blue-500 {
3839
3861
  --tw-gradient-to: #1C91FF var(--tw-gradient-to-position);
3840
3862
  }
@@ -4899,6 +4921,12 @@ select {
4899
4921
  box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
4900
4922
  }
4901
4923
 
4924
+ .s-shadow-none {
4925
+ --tw-shadow: 0 0 #0000;
4926
+ --tw-shadow-colored: 0 0 #0000;
4927
+ box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
4928
+ }
4929
+
4902
4930
  .s-shadow-sm {
4903
4931
  --tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
4904
4932
  --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);
@@ -5811,10 +5839,6 @@ select {
5811
5839
  opacity: 1;
5812
5840
  }
5813
5841
 
5814
- .s-group\/preview:hover .group-hover\/preview\:s-opacity-40 {
5815
- opacity: 0.4;
5816
- }
5817
-
5818
5842
  .s-group\/tree:hover .group-hover\/tree\:s-opacity-100 {
5819
5843
  opacity: 1;
5820
5844
  }
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-rc3",
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,53 @@ 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
 
13
+ interface DownloadButtonProps {
14
+ className?: string;
15
+ size?: "xs" | "sm";
16
+ src?: string;
17
+ title: string;
18
+ }
19
+
20
+ function DownloadButton({
21
+ className,
22
+ size = "xs",
23
+ src,
24
+ title,
25
+ }: DownloadButtonProps) {
26
+ const handleDownload = React.useCallback(async () => {
27
+ if (!src) {
28
+ return;
29
+ }
30
+
31
+ // Create a hidden link and click it.
32
+ const link = document.createElement("a");
33
+ link.href = src;
34
+ link.download = title;
35
+ document.body.appendChild(link);
36
+ link.click();
37
+ document.body.removeChild(link);
38
+ }, [src, title]);
39
+
40
+ return (
41
+ <IconButton
42
+ icon={ArrowDownOnSquareIcon}
43
+ className={cn("s-text-white", className)}
44
+ tooltip="Download"
45
+ size={size}
46
+ onClick={async (e) => {
47
+ e.stopPropagation(); // Prevent image zoom.
48
+ await handleDownload();
49
+ }}
50
+ />
51
+ );
52
+ }
53
+
18
54
  interface InteractiveImageProps {
19
55
  alt: string;
20
56
  isLoading?: boolean;
21
- onCopyError?: (error: unknown) => void;
22
- onDownloadError?: (error: unknown) => void;
23
57
  src?: string;
24
58
  title: string;
25
59
  }
@@ -56,8 +90,22 @@ export function InteractiveImage({
56
90
  />
57
91
  </div>
58
92
  </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">
60
- <img src={src} alt={alt} className="s-object-contain" />
93
+ <DialogContent
94
+ className={cn(
95
+ "s-w-auto s-max-w-none s-border-0 s-outline-none s-ring-0",
96
+ "focus:s-outline-none focus:s-ring-0",
97
+ "s-rounded-none s-bg-transparent s-shadow-none"
98
+ )}
99
+ size="xl"
100
+ >
101
+ <div className="s-flex s-flex-col">
102
+ <div className="s-flex s-justify-end s-pb-2 s-pr-1 s-pt-1">
103
+ <DownloadButton src={src} title={props.title} size="sm" />
104
+ </div>
105
+ <div className="s-relative s-w-full">
106
+ <img src={src} alt={alt} className="s-w-full s-object-contain" />
107
+ </div>
108
+ </div>
61
109
  </DialogContent>
62
110
  </Dialog>
63
111
  );
@@ -66,7 +114,7 @@ export function InteractiveImage({
66
114
  function LoadingImage() {
67
115
  return (
68
116
  <div className="s-flex s-h-full s-w-full s-items-center s-justify-center">
69
- <Spinner variant="dark" size="sm" />
117
+ <Spinner variant="dark" size="md" />
70
118
  </div>
71
119
  );
72
120
  }
@@ -81,67 +129,13 @@ function ImagePreview({
81
129
  alt,
82
130
  src,
83
131
  title,
84
- onCopyError,
85
- onDownloadError,
86
132
  }: 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);
107
- }
108
- };
109
-
110
- const handleDownload = async () => {
111
- try {
112
- if (!src) {
113
- return;
114
- }
115
-
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
- };
139
-
140
133
  return (
141
134
  <div
142
135
  onClick={onClick}
143
136
  className={cn(
144
- "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",
137
+ "s-group/preview s-relative s-h-full s-w-full s-overflow-hidden s-rounded-2xl",
138
+ "s-bg-muted-background dark:s-bg-muted-background-night",
145
139
  !isLoading && "s-cursor-pointer"
146
140
  )}
147
141
  >
@@ -155,29 +149,23 @@ function ImagePreview({
155
149
  className="s-h-full s-w-full s-rounded-2xl s-object-cover"
156
150
  />
157
151
  {/* Dark overlay on hover */}
158
- <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" />
152
+ <div
153
+ className={cn(
154
+ "s-absolute s-inset-0 s-bg-gradient-to-b",
155
+ "s-from-black/40 s-via-transparent s-to-black/40",
156
+ "s-opacity-0 s-transition-opacity s-duration-200",
157
+ "group-hover/preview:s-opacity-100"
158
+ )}
159
+ />
159
160
  {/* Icon container - only visible on hover */}
160
- <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
- <IconButton
172
- icon={ArrowDownOnSquareIcon}
173
- className="s-text-white"
174
- tooltip="Download"
175
- size="xs"
176
- onClick={async (e) => {
177
- e.stopPropagation(); // Prevent image zoom.
178
- await handleDownload();
179
- }}
180
- />
161
+ <div
162
+ className={cn(
163
+ "s-absolute s-right-3 s-top-3 s-z-10 s-flex",
164
+ "s-opacity-0 s-transition-opacity s-duration-200",
165
+ "group-hover/preview:s-opacity-100"
166
+ )}
167
+ >
168
+ <DownloadButton src={src} title={title} size="xs" />
181
169
  </div>
182
170
  </>
183
171
  )}