@dust-tt/sparkle 0.2.491 → 0.2.492

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/dist/sparkle.css CHANGED
@@ -969,8 +969,8 @@ select {
969
969
  bottom: 0.25rem;
970
970
  }
971
971
 
972
- .s-bottom-4 {
973
- bottom: 1rem;
972
+ .s-bottom-3 {
973
+ bottom: 0.75rem;
974
974
  }
975
975
 
976
976
  .s-bottom-6 {
@@ -1029,10 +1029,6 @@ select {
1029
1029
  right: 0.75rem;
1030
1030
  }
1031
1031
 
1032
- .s-right-4 {
1033
- right: 1rem;
1034
- }
1035
-
1036
1032
  .s-right-6 {
1037
1033
  right: 1.5rem;
1038
1034
  }
@@ -1061,10 +1057,6 @@ select {
1061
1057
  top: 0.75rem;
1062
1058
  }
1063
1059
 
1064
- .s-top-4 {
1065
- top: 1rem;
1066
- }
1067
-
1068
1060
  .s-top-6 {
1069
1061
  top: 1.5rem;
1070
1062
  }
@@ -1435,10 +1427,18 @@ select {
1435
1427
  height: 200px;
1436
1428
  }
1437
1429
 
1430
+ .s-h-\[240px\] {
1431
+ height: 240px;
1432
+ }
1433
+
1438
1434
  .s-h-\[30\%\] {
1439
1435
  height: 30%;
1440
1436
  }
1441
1437
 
1438
+ .s-h-\[32px\] {
1439
+ height: 32px;
1440
+ }
1441
+
1442
1442
  .s-h-\[340px\] {
1443
1443
  height: 340px;
1444
1444
  }
@@ -1668,6 +1668,10 @@ select {
1668
1668
  width: 250px;
1669
1669
  }
1670
1670
 
1671
+ .s-w-\[300px\] {
1672
+ width: 300px;
1673
+ }
1674
+
1671
1675
  .s-w-\[350px\] {
1672
1676
  width: 350px;
1673
1677
  }
@@ -1676,6 +1680,10 @@ select {
1676
1680
  width: 380px;
1677
1681
  }
1678
1682
 
1683
+ .s-w-\[3px\] {
1684
+ width: 3px;
1685
+ }
1686
+
1679
1687
  .s-w-\[420px\] {
1680
1688
  width: 420px;
1681
1689
  }
@@ -1738,10 +1746,6 @@ select {
1738
1746
  min-width: 0px;
1739
1747
  }
1740
1748
 
1741
- .s-min-w-\[1024px\] {
1742
- min-width: 1024px;
1743
- }
1744
-
1745
1749
  .s-min-w-\[20px\] {
1746
1750
  min-width: 20px;
1747
1751
  }
@@ -1916,6 +1920,28 @@ select {
1916
1920
  animation: s-breathing 3s infinite ease-in-out;
1917
1921
  }
1918
1922
 
1923
+ @keyframes s-cursor-blink {
1924
+ 0% {
1925
+ opacity: 1;
1926
+ }
1927
+
1928
+ 60% {
1929
+ opacity: 1;
1930
+ }
1931
+
1932
+ 70% {
1933
+ opacity: 0;
1934
+ }
1935
+
1936
+ 100% {
1937
+ opacity: 0;
1938
+ }
1939
+ }
1940
+
1941
+ .s-animate-cursor-blink {
1942
+ animation: s-cursor-blink 0.9s infinite;;
1943
+ }
1944
+
1919
1945
  @keyframes s-pulse {
1920
1946
  50% {
1921
1947
  opacity: .5;
@@ -2040,6 +2066,10 @@ select {
2040
2066
  grid-template-columns: repeat(4, minmax(0, 1fr));
2041
2067
  }
2042
2068
 
2069
+ .s-grid-cols-6 {
2070
+ grid-template-columns: repeat(6, minmax(0, 1fr));
2071
+ }
2072
+
2043
2073
  .s-grid-cols-8 {
2044
2074
  grid-template-columns: repeat(8, minmax(0, 1fr));
2045
2075
  }
@@ -2368,6 +2398,10 @@ select {
2368
2398
  border-radius: 0.375rem;
2369
2399
  }
2370
2400
 
2401
+ .s-rounded-none {
2402
+ border-radius: 0px;
2403
+ }
2404
+
2371
2405
  .s-rounded-sm {
2372
2406
  border-radius: 0.125rem;
2373
2407
  }
@@ -2390,6 +2424,10 @@ select {
2390
2424
  border-width: 1px;
2391
2425
  }
2392
2426
 
2427
+ .s-border-0 {
2428
+ border-width: 0px;
2429
+ }
2430
+
2393
2431
  .s-border-b {
2394
2432
  border-bottom-width: 1px;
2395
2433
  }
@@ -2822,6 +2860,11 @@ select {
2822
2860
  background-color: rgb(233 247 255 / var(--tw-bg-opacity));
2823
2861
  }
2824
2862
 
2863
+ .s-bg-brand-support-golden {
2864
+ --tw-bg-opacity: 1;
2865
+ background-color: rgb(255 250 224 / var(--tw-bg-opacity));
2866
+ }
2867
+
2825
2868
  .s-bg-brand-support-green {
2826
2869
  --tw-bg-opacity: 1;
2827
2870
  background-color: rgb(254 255 240 / var(--tw-bg-opacity));
@@ -2892,6 +2935,11 @@ select {
2892
2935
  background-color: rgb(4 20 10 / var(--tw-bg-opacity));
2893
2936
  }
2894
2937
 
2938
+ .s-bg-foreground {
2939
+ --tw-bg-opacity: 1;
2940
+ background-color: rgb(17 20 24 / var(--tw-bg-opacity));
2941
+ }
2942
+
2895
2943
  .s-bg-golden-100 {
2896
2944
  --tw-bg-opacity: 1;
2897
2945
  background-color: rgb(255 239 168 / var(--tw-bg-opacity));
@@ -4251,6 +4299,10 @@ select {
4251
4299
  padding-right: 0.75rem;
4252
4300
  }
4253
4301
 
4302
+ .s-pr-5 {
4303
+ padding-right: 1.25rem;
4304
+ }
4305
+
4254
4306
  .s-pr-8 {
4255
4307
  padding-right: 2rem;
4256
4308
  }
@@ -4990,6 +5042,12 @@ select {
4990
5042
  box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
4991
5043
  }
4992
5044
 
5045
+ .s-shadow-none {
5046
+ --tw-shadow: 0 0 #0000;
5047
+ --tw-shadow-colored: 0 0 #0000;
5048
+ box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
5049
+ }
5050
+
4993
5051
  .s-shadow-sm {
4994
5052
  --tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
4995
5053
  --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);
@@ -5007,6 +5065,12 @@ select {
5007
5065
  outline-offset: 2px;
5008
5066
  }
5009
5067
 
5068
+ .s-ring-0 {
5069
+ --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
5070
+ --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color);
5071
+ box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
5072
+ }
5073
+
5010
5074
  .s-ring-2 {
5011
5075
  --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
5012
5076
  --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);
@@ -5249,10 +5313,14 @@ select {
5249
5313
  opacity: 1;
5250
5314
  }
5251
5315
 
5252
- 90% {
5316
+ 60% {
5253
5317
  opacity: 1;
5254
5318
  }
5255
5319
 
5320
+ 70% {
5321
+ opacity: 0;
5322
+ }
5323
+
5256
5324
  100% {
5257
5325
  opacity: 0;
5258
5326
  }
@@ -8597,10 +8665,18 @@ select {
8597
8665
  }
8598
8666
 
8599
8667
  @media (min-width: 640px) {
8668
+ .sm\:s-h-full {
8669
+ height: 100%;
8670
+ }
8671
+
8600
8672
  .sm\:s-max-w-3xl {
8601
8673
  max-width: 48rem;
8602
8674
  }
8603
8675
 
8676
+ .sm\:s-max-w-full {
8677
+ max-width: 100%;
8678
+ }
8679
+
8604
8680
  .sm\:s-max-w-md {
8605
8681
  max-width: 28rem;
8606
8682
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dust-tt/sparkle",
3
- "version": "0.2.491",
3
+ "version": "0.2.492",
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",
@@ -4,7 +4,13 @@ import { FocusScope } from "@radix-ui/react-focus-scope";
4
4
  import { cva } from "class-variance-authority";
5
5
  import * as React from "react";
6
6
 
7
- import { Button, Checkbox, Label, ScrollArea } from "@sparkle/components";
7
+ import {
8
+ Button,
9
+ ButtonProps,
10
+ Checkbox,
11
+ Label,
12
+ ScrollArea,
13
+ } from "@sparkle/components";
8
14
  import { XMarkIcon } from "@sparkle/icons/app";
9
15
  import { cn } from "@sparkle/lib/utils";
10
16
 
@@ -29,13 +35,14 @@ const DialogOverlay = React.forwardRef<
29
35
  ));
30
36
  DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
31
37
 
32
- const DIALOG_SIZES = ["md", "lg", "xl"] as const;
38
+ const DIALOG_SIZES = ["md", "lg", "xl", "full"] as const;
33
39
  type DialogSizeType = (typeof DIALOG_SIZES)[number];
34
40
 
35
41
  const sizeClasses: Record<DialogSizeType, string> = {
36
42
  md: "sm:s-max-w-md",
37
43
  lg: "sm:s-max-w-xl",
38
44
  xl: "sm:s-max-w-3xl",
45
+ full: "sm:s-max-w-full sm:s-h-full",
39
46
  };
40
47
 
41
48
  const dialogVariants = cva(
@@ -90,12 +97,16 @@ const DialogContent = React.forwardRef<
90
97
  DialogContent.displayName = DialogPrimitive.Content.displayName;
91
98
 
92
99
  interface NewDialogHeaderProps extends React.HTMLAttributes<HTMLDivElement> {
100
+ buttonSize?: ButtonProps["size"];
101
+ buttonVariant?: ButtonProps["variant"];
93
102
  hideButton?: boolean;
94
103
  }
95
104
 
96
105
  const DialogHeader = ({
97
106
  className,
98
107
  children,
108
+ buttonSize = "mini",
109
+ buttonVariant = "ghost",
99
110
  hideButton = false,
100
111
  ...props
101
112
  }: NewDialogHeaderProps) => (
@@ -108,7 +119,9 @@ const DialogHeader = ({
108
119
  >
109
120
  {children}
110
121
  <DialogClose asChild className="s-absolute s-right-3 s-top-3">
111
- {!hideButton && <Button icon={XMarkIcon} variant="ghost" size="mini" />}
122
+ {!hideButton && (
123
+ <Button icon={XMarkIcon} variant={buttonVariant} size={buttonSize} />
124
+ )}
112
125
  </DialogClose>
113
126
  </div>
114
127
  );
@@ -1,11 +1,17 @@
1
1
  import React from "react";
2
2
 
3
- import { Button, Spinner } from "@sparkle/components/";
3
+ import {
4
+ Button,
5
+ Dialog,
6
+ DialogContent,
7
+ DialogHeader,
8
+ DialogTrigger,
9
+ Spinner,
10
+ } from "@sparkle/components/";
4
11
  import {
5
12
  ArrowDownOnSquareIcon,
6
13
  ChevronLeftIcon,
7
14
  ChevronRightIcon,
8
- XMarkIcon,
9
15
  } from "@sparkle/icons/app";
10
16
  import { cn } from "@sparkle/lib/utils";
11
17
 
@@ -53,7 +59,7 @@ const ImagePreview = React.forwardRef<HTMLDivElement, ImagePreviewProps>(
53
59
  ref={ref}
54
60
  onClick={onClick}
55
61
  className={cn(
56
- "s-group/preview s-relative",
62
+ "s-group/preview s-relative s-aspect-square",
57
63
  "s-cursor-pointer s-overflow-hidden s-rounded-2xl",
58
64
  "s-bg-muted-background dark:s-bg-muted-background-night"
59
65
  )}
@@ -113,14 +119,13 @@ interface InteractiveImageGridProps {
113
119
  }[];
114
120
  }
115
121
 
116
- const InteractiveImageGrid = React.forwardRef<
117
- HTMLDivElement,
118
- InteractiveImageGridProps
119
- >(({ className, images }, ref) => {
122
+ function InteractiveImageGrid({
123
+ className,
124
+ images,
125
+ }: InteractiveImageGridProps) {
120
126
  const [currentImageIndex, setCurrentImageIndex] = React.useState<
121
127
  number | null
122
128
  >(null);
123
- const [isZoomed, setIsZoomed] = React.useState(false);
124
129
  const [imageLoaded, setImageLoaded] = React.useState(false);
125
130
 
126
131
  const handleNext = React.useCallback(() => {
@@ -157,7 +162,7 @@ const InteractiveImageGrid = React.forwardRef<
157
162
  );
158
163
 
159
164
  React.useEffect(() => {
160
- if (!isZoomed) {
165
+ if (currentImageIndex === null) {
161
166
  return;
162
167
  }
163
168
 
@@ -167,72 +172,64 @@ const InteractiveImageGrid = React.forwardRef<
167
172
  handleNext();
168
173
  } else if (e.key === "ArrowLeft") {
169
174
  handlePrevious();
170
- } else if (e.key === "Escape") {
171
- setIsZoomed(false);
172
- setCurrentImageIndex(null);
173
175
  }
174
176
  };
175
177
 
176
178
  window.addEventListener("keydown", handleKeyDown);
177
179
  return () => window.removeEventListener("keydown", handleKeyDown);
178
- }, [isZoomed, handleNext, handlePrevious]);
180
+ }, [currentImageIndex, handleNext, handlePrevious]);
179
181
 
180
182
  return (
181
- <div ref={ref} className={cn("s-@container", className)}>
182
- {images.length === 1 ? (
183
- <div className="s-h-80 s-w-80">
184
- <ImagePreview
185
- image={images[0]}
186
- onClick={() => {
187
- setCurrentImageIndex(0);
188
- setIsZoomed(true);
189
- }}
190
- onDownload={async (e) => {
191
- e.stopPropagation();
192
- await handleDownload(images[0].downloadUrl, images[0].title);
193
- }}
194
- />
195
- </div>
196
- ) : (
197
- <div className="s-grid s-grid-cols-2 s-gap-2 @xxs:s-grid-cols-3 @xs:s-grid-cols-4">
198
- {images.map((image, idx) => (
199
- <ImagePreview
200
- key={idx}
201
- image={image}
202
- onClick={() => {
203
- setCurrentImageIndex(idx);
204
- setIsZoomed(true);
205
- }}
206
- onDownload={async (e) => {
207
- e.stopPropagation();
208
- await handleDownload(image.downloadUrl, image.title);
209
- }}
210
- />
211
- ))}
212
- </div>
213
- )}
214
-
215
- {isZoomed && currentImageIndex !== null && (
216
- <div
217
- className={cn(
218
- "s-fixed s-inset-0 s-z-50 s-flex s-items-center s-justify-center",
219
- "s-bg-white/95 dark:s-bg-gray-900/95"
220
- )}
221
- >
222
- <div className="s-relative s-flex s-h-full s-w-full s-flex-col">
223
- {/* Top bar */}
224
- <div className="s-absolute s-right-4 s-top-4 s-z-10 s-flex s-gap-2">
225
- <Button
226
- variant="outline"
227
- size="md"
228
- icon={XMarkIcon}
229
- tooltip="Close"
183
+ <Dialog
184
+ open={currentImageIndex !== null}
185
+ onOpenChange={(open) => !open && setCurrentImageIndex(null)}
186
+ >
187
+ <DialogTrigger asChild>
188
+ <div className={cn("s-@container", className)}>
189
+ {images.length === 1 ? (
190
+ <div className="s-h-80 s-w-80">
191
+ <ImagePreview
192
+ image={images[0]}
230
193
  onClick={() => {
231
- setIsZoomed(false);
232
- setCurrentImageIndex(null);
194
+ setCurrentImageIndex(0);
195
+ }}
196
+ onDownload={async (e) => {
197
+ e.stopPropagation();
198
+ await handleDownload(images[0].downloadUrl, images[0].title);
233
199
  }}
234
200
  />
235
201
  </div>
202
+ ) : (
203
+ <div className="s-grid s-grid-cols-2 s-gap-2 @xxs:s-grid-cols-3 @xs:s-grid-cols-4">
204
+ {images.map((image, idx) => (
205
+ <ImagePreview
206
+ key={idx}
207
+ image={image}
208
+ onClick={() => {
209
+ setCurrentImageIndex(idx);
210
+ }}
211
+ onDownload={async (e) => {
212
+ e.stopPropagation();
213
+ await handleDownload(image.downloadUrl, image.title);
214
+ }}
215
+ />
216
+ ))}
217
+ </div>
218
+ )}
219
+ </div>
220
+ </DialogTrigger>
221
+ <DialogContent
222
+ size="full"
223
+ className="s-rounded-none s-border-0 s-bg-white/95 s-p-0 s-shadow-none s-outline-none s-ring-0 dark:s-bg-gray-900/95"
224
+ >
225
+ {currentImageIndex !== null && (
226
+ <div className="s-relative s-flex s-h-full s-w-full s-flex-col">
227
+ {/* Top bar */}
228
+ <DialogHeader
229
+ buttonVariant="outline"
230
+ buttonSize="md"
231
+ className="s-h-6"
232
+ />
236
233
 
237
234
  {/* Main content */}
238
235
  <div className="s-flex s-flex-1 s-items-center s-justify-center">
@@ -255,7 +252,7 @@ const InteractiveImageGrid = React.forwardRef<
255
252
  src={images[currentImageIndex].imageUrl}
256
253
  alt={images[currentImageIndex].alt}
257
254
  className={cn(
258
- "s-max-h-[90vh] s-min-h-[50vh] s-w-auto s-min-w-[1024px]",
255
+ "s-max-h-[90vh] s-min-h-[50vh] s-w-auto s-min-w-[50vh]",
259
256
  "s-checkerboard s-object-contain"
260
257
  )}
261
258
  onLoad={() => setImageLoaded(true)}
@@ -279,7 +276,7 @@ const InteractiveImageGrid = React.forwardRef<
279
276
  {!images[currentImageIndex].isLoading && (
280
277
  <>
281
278
  {imageLoaded ? (
282
- <div className="s-absolute s-bottom-4 s-right-4 s-z-10">
279
+ <div className="s-absolute s-bottom-3 s-right-3 s-z-10">
283
280
  <Button
284
281
  variant="outline"
285
282
  size="md"
@@ -299,11 +296,11 @@ const InteractiveImageGrid = React.forwardRef<
299
296
  </>
300
297
  )}
301
298
  </div>
302
- </div>
303
- )}
304
- </div>
299
+ )}
300
+ </DialogContent>
301
+ </Dialog>
305
302
  );
306
- });
303
+ }
307
304
 
308
305
  InteractiveImageGrid.displayName = "InteractiveImageGrid";
309
306
 
@@ -62,9 +62,17 @@ export const InteractiveImageExample = () => (
62
62
  <h2>Interactive Image Grid</h2>
63
63
  <InteractiveImageGrid images={images} />
64
64
  </div>
65
+ <div className="s-w-[300px]">
66
+ <h2>Interactive Image Grid with small width</h2>
67
+ <InteractiveImageGrid images={images} />
68
+ </div>
65
69
  <div className="s-w-[700px]">
66
70
  <h2>Interactive Image Grid with 1 image</h2>
67
71
  <InteractiveImageGrid images={images.slice(1, 2)} />
68
72
  </div>
73
+ <div className="s-w-[700px]">
74
+ <h2>Interactive Image Grid with 1 image (loading)</h2>
75
+ <InteractiveImageGrid images={images.slice(0, 1)} />
76
+ </div>
69
77
  </div>
70
78
  );