@dust-tt/sparkle 0.2.552 → 0.2.553-rc-1

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
@@ -1315,6 +1315,14 @@ select {
1315
1315
  height: 3rem;
1316
1316
  }
1317
1317
 
1318
+ .s-h-125 {
1319
+ height: 500px;
1320
+ }
1321
+
1322
+ .s-h-150 {
1323
+ height: 600px;
1324
+ }
1325
+
1318
1326
  .s-h-16 {
1319
1327
  height: 4rem;
1320
1328
  }
@@ -1468,6 +1476,14 @@ select {
1468
1476
  max-height: calc(var(--radix-dropdown-menu-content-available-height) - var(--header-height,20px));
1469
1477
  }
1470
1478
 
1479
+ .s-max-h-screen {
1480
+ max-height: 100vh;
1481
+ }
1482
+
1483
+ .s-min-h-0 {
1484
+ min-height: 0px;
1485
+ }
1486
+
1471
1487
  .s-min-h-64 {
1472
1488
  min-height: 16rem;
1473
1489
  }
@@ -1826,16 +1842,41 @@ select {
1826
1842
  border-collapse: collapse;
1827
1843
  }
1828
1844
 
1845
+ .s--translate-x-1 {
1846
+ --tw-translate-x: -0.25rem;
1847
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
1848
+ }
1849
+
1829
1850
  .s--translate-x-1\/2 {
1830
1851
  --tw-translate-x: -50%;
1831
1852
  transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
1832
1853
  }
1833
1854
 
1855
+ .s--translate-x-2 {
1856
+ --tw-translate-x: -0.5rem;
1857
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
1858
+ }
1859
+
1834
1860
  .s--translate-y-1\/2 {
1835
1861
  --tw-translate-y: -50%;
1836
1862
  transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
1837
1863
  }
1838
1864
 
1865
+ .s-translate-x-0 {
1866
+ --tw-translate-x: 0px;
1867
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
1868
+ }
1869
+
1870
+ .s-translate-x-1 {
1871
+ --tw-translate-x: 0.25rem;
1872
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
1873
+ }
1874
+
1875
+ .s-translate-x-2 {
1876
+ --tw-translate-x: 0.5rem;
1877
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
1878
+ }
1879
+
1839
1880
  .s-translate-x-\[-50\%\] {
1840
1881
  --tw-translate-x: -50%;
1841
1882
  transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
@@ -2248,6 +2289,12 @@ select {
2248
2289
  margin-bottom: calc(1rem * var(--tw-space-y-reverse));
2249
2290
  }
2250
2291
 
2292
+ .s-space-y-6 > :not([hidden]) ~ :not([hidden]) {
2293
+ --tw-space-y-reverse: 0;
2294
+ margin-top: calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));
2295
+ margin-bottom: calc(1.5rem * var(--tw-space-y-reverse));
2296
+ }
2297
+
2251
2298
  .s-space-y-8 > :not([hidden]) ~ :not([hidden]) {
2252
2299
  --tw-space-y-reverse: 0;
2253
2300
  margin-top: calc(2rem * calc(1 - var(--tw-space-y-reverse)));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dust-tt/sparkle",
3
- "version": "0.2.552",
3
+ "version": "0.2.553-rc-1",
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",
@@ -0,0 +1,295 @@
1
+ import { cva } from "class-variance-authority";
2
+ import * as React from "react";
3
+ import { useState } from "react";
4
+
5
+ import { Button, Icon, ScrollArea } from "@sparkle/components";
6
+ import {
7
+ Dialog,
8
+ DialogClose,
9
+ DialogContent,
10
+ DialogDescription,
11
+ DialogFooter,
12
+ DialogHeader,
13
+ DialogTitle,
14
+ DialogTrigger,
15
+ } from "@sparkle/components/Dialog";
16
+ import { ChevronLeftIcon, ChevronRightIcon } from "@sparkle/icons/app";
17
+ import { cn } from "@sparkle/lib/utils";
18
+
19
+ const MULTI_PAGE_DIALOG_SIZES = ["md", "lg", "xl"] as const;
20
+ type MultiPageDialogSizeType = (typeof MULTI_PAGE_DIALOG_SIZES)[number];
21
+
22
+ const multiPageDialogSizeClasses: Record<MultiPageDialogSizeType, string> = {
23
+ md: "s-h-100 s-max-h-screen",
24
+ lg: "s-h-125 s-max-h-screen",
25
+ xl: "s-h-150 s-max-h-screen",
26
+ };
27
+
28
+ const multiPageDialogHeightVariants = cva("", {
29
+ variants: {
30
+ size: multiPageDialogSizeClasses,
31
+ },
32
+ defaultVariants: {
33
+ size: "md",
34
+ },
35
+ });
36
+
37
+ const multiPageDialogLayoutVariants = cva(
38
+ cn("s-flex s-flex-col s-h-full s-overflow-hidden")
39
+ );
40
+
41
+ interface MultiPageDialogPage {
42
+ id: string;
43
+ title: string;
44
+ description?: string;
45
+ icon?: React.ComponentType;
46
+ content: React.ReactNode;
47
+ }
48
+
49
+ interface MultiPageDialogProps {
50
+ pages: MultiPageDialogPage[];
51
+ currentPageId: string;
52
+ onPageChange: (pageId: string) => void;
53
+ size?: MultiPageDialogSizeType;
54
+ trapFocusScope?: boolean;
55
+ isAlertDialog?: boolean;
56
+ showNavigation?: boolean;
57
+ showHeaderNavigation?: boolean;
58
+ footerContent?: React.ReactNode;
59
+ onSave?: (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
60
+ className?: string;
61
+ disableNext?: boolean;
62
+ disableSave?: boolean;
63
+ }
64
+
65
+ const MultiPageDialogRoot = Dialog;
66
+ const MultiPageDialogTrigger = DialogTrigger;
67
+ const MultiPageDialogClose = DialogClose;
68
+
69
+ interface MultiPageDialogContentProps extends MultiPageDialogProps {
70
+ children?: never;
71
+ }
72
+
73
+ const MultiPageDialogContent = React.forwardRef<
74
+ React.ElementRef<typeof DialogContent>,
75
+ MultiPageDialogContentProps
76
+ >(
77
+ (
78
+ {
79
+ pages,
80
+ currentPageId,
81
+ onPageChange,
82
+ size = "md",
83
+ trapFocusScope,
84
+ isAlertDialog,
85
+ showNavigation = true,
86
+ showHeaderNavigation = true,
87
+ footerContent,
88
+ onSave,
89
+ className,
90
+ disableNext = false,
91
+ disableSave = false,
92
+ ...props
93
+ },
94
+ ref
95
+ ) => {
96
+ const currentPageIndex = pages.findIndex(
97
+ (page) => page.id === currentPageId
98
+ );
99
+ const currentPage = pages[currentPageIndex];
100
+
101
+ const [isTransitioning, setIsTransitioning] = useState(false);
102
+ const [transitionDirection, setTransitionDirection] = useState<
103
+ "next" | "prev"
104
+ >("next");
105
+
106
+ const handlePrevious = (
107
+ e: React.MouseEvent<HTMLButtonElement, MouseEvent>
108
+ ) => {
109
+ e.preventDefault();
110
+ if (currentPageIndex > 0 && !isTransitioning) {
111
+ setTransitionDirection("prev");
112
+ setIsTransitioning(true);
113
+ setTimeout(() => {
114
+ onPageChange(pages[currentPageIndex - 1].id);
115
+ setTimeout(() => setIsTransitioning(false), 50);
116
+ }, 150);
117
+ }
118
+ };
119
+
120
+ const handleNext = (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
121
+ e.preventDefault();
122
+ if (currentPageIndex < pages.length - 1 && !isTransitioning) {
123
+ setTransitionDirection("next");
124
+ setIsTransitioning(true);
125
+ setTimeout(() => {
126
+ onPageChange(pages[currentPageIndex + 1].id);
127
+ setTimeout(() => setIsTransitioning(false), 50);
128
+ }, 150);
129
+ }
130
+ };
131
+
132
+ if (!currentPage) {
133
+ console.warn(`Page with id "${currentPageId}" not found`);
134
+ return null;
135
+ }
136
+
137
+ const hasPrevious = currentPageIndex > 0;
138
+ const hasNext = currentPageIndex < pages.length - 1;
139
+ const nextButtonDisabled = disableNext || !hasNext || isTransitioning;
140
+ const prevButtonDisabled = !hasPrevious || isTransitioning;
141
+
142
+ return (
143
+ <DialogContent
144
+ ref={ref}
145
+ size={size}
146
+ trapFocusScope={trapFocusScope}
147
+ isAlertDialog={isAlertDialog}
148
+ className={cn(multiPageDialogHeightVariants({ size }), className)}
149
+ {...props}
150
+ >
151
+ <div className={cn(multiPageDialogLayoutVariants())}>
152
+ <DialogHeader hideButton={true} className="s-flex-none">
153
+ <div className="s-flex s-items-center s-justify-between s-pr-8">
154
+ <div className="s-flex s-items-center s-gap-3">
155
+ {showNavigation && showHeaderNavigation && (
156
+ <div className="s-flex s-items-center s-gap-1">
157
+ <Button
158
+ icon={ChevronLeftIcon}
159
+ variant="ghost"
160
+ size="sm"
161
+ disabled={prevButtonDisabled}
162
+ onClick={handlePrevious}
163
+ tooltip={
164
+ hasPrevious && !isTransitioning
165
+ ? "Previous page"
166
+ : undefined
167
+ }
168
+ />
169
+ <Button
170
+ icon={ChevronRightIcon}
171
+ variant="ghost"
172
+ size="sm"
173
+ disabled={nextButtonDisabled}
174
+ onClick={handleNext}
175
+ tooltip={
176
+ hasNext && !disableNext && !isTransitioning
177
+ ? "Next page"
178
+ : undefined
179
+ }
180
+ />
181
+ </div>
182
+ )}
183
+ <div
184
+ className={cn(
185
+ "s-flex s-items-center s-gap-2 s-transition-all s-duration-200 s-ease-out",
186
+ {
187
+ "s-transform s-opacity-0": isTransitioning,
188
+ "s-translate-x-1":
189
+ isTransitioning && transitionDirection === "next",
190
+ "s--translate-x-1":
191
+ isTransitioning && transitionDirection === "prev",
192
+ "s-translate-x-0 s-opacity-100": !isTransitioning,
193
+ }
194
+ )}
195
+ >
196
+ {currentPage.icon && (
197
+ <Icon
198
+ visual={currentPage.icon}
199
+ size="lg"
200
+ className="s-text-foreground"
201
+ />
202
+ )}
203
+ <div>
204
+ <DialogTitle>{currentPage.title}</DialogTitle>
205
+ {currentPage.description && (
206
+ <DialogDescription>
207
+ {currentPage.description}
208
+ </DialogDescription>
209
+ )}
210
+ </div>
211
+ </div>
212
+ </div>
213
+ {showNavigation && pages.length > 1 && (
214
+ <div className="s-text-xs s-text-muted-foreground dark:s-text-muted-foreground-night">
215
+ {currentPageIndex + 1} / {pages.length}
216
+ </div>
217
+ )}
218
+ </div>
219
+ </DialogHeader>
220
+
221
+ <div className="s-min-h-0 s-flex-1 s-overflow-hidden">
222
+ <ScrollArea
223
+ className={cn(
224
+ "s-h-full s-transition-all s-duration-200 s-ease-out",
225
+ {
226
+ "s-transform s-opacity-0": isTransitioning,
227
+ "s-translate-x-2":
228
+ isTransitioning && transitionDirection === "next",
229
+ "s--translate-x-2":
230
+ isTransitioning && transitionDirection === "prev",
231
+ "s-translate-x-0 s-opacity-100": !isTransitioning,
232
+ }
233
+ )}
234
+ >
235
+ <div className="s-flex s-flex-col s-gap-2 s-px-5 s-py-4">
236
+ {currentPage.content}
237
+ </div>
238
+ </ScrollArea>
239
+ </div>
240
+
241
+ <DialogFooter
242
+ className="s-flex-none"
243
+ leftButtonProps={{
244
+ label: "Cancel",
245
+ variant: "outline",
246
+ size: "sm",
247
+ }}
248
+ rightButtonProps={
249
+ showNavigation && pages.length > 1 && hasPrevious
250
+ ? {
251
+ label: "Previous",
252
+ variant: "outline",
253
+ size: "sm",
254
+ disabled: isTransitioning,
255
+ onClick: handlePrevious,
256
+ }
257
+ : undefined
258
+ }
259
+ >
260
+ {showNavigation && pages.length > 1 && hasNext && (
261
+ <Button
262
+ label="Next"
263
+ variant="outline"
264
+ size="sm"
265
+ disabled={disableNext || isTransitioning}
266
+ onClick={handleNext}
267
+ />
268
+ )}
269
+ {showNavigation && pages.length > 1 && !hasNext && onSave && (
270
+ <Button
271
+ label="Save changes"
272
+ variant="primary"
273
+ size="sm"
274
+ disabled={disableSave || isTransitioning}
275
+ onClick={onSave}
276
+ />
277
+ )}
278
+ {footerContent}
279
+ </DialogFooter>
280
+ </div>
281
+ </DialogContent>
282
+ );
283
+ }
284
+ );
285
+
286
+ MultiPageDialogContent.displayName = "MultiPageDialogContent";
287
+
288
+ export {
289
+ MultiPageDialogRoot as MultiPageDialog,
290
+ MultiPageDialogClose,
291
+ MultiPageDialogContent,
292
+ type MultiPageDialogPage,
293
+ type MultiPageDialogProps,
294
+ MultiPageDialogTrigger,
295
+ };
@@ -30,6 +30,7 @@ interface MultiPageSheetProps {
30
30
  side?: React.ComponentProps<typeof SheetContent>["side"];
31
31
  trapFocusScope?: boolean;
32
32
  showNavigation?: boolean;
33
+ showHeaderNavigation?: boolean;
33
34
  footerContent?: React.ReactNode;
34
35
  onSave?: (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
35
36
  className?: string;
@@ -58,6 +59,7 @@ const MultiPageSheetContent = React.forwardRef<
58
59
  side = "right",
59
60
  trapFocusScope,
60
61
  showNavigation = true,
62
+ showHeaderNavigation = true,
61
63
  footerContent,
62
64
  onSave,
63
65
  className,
@@ -110,7 +112,7 @@ const MultiPageSheetContent = React.forwardRef<
110
112
  <SheetHeader hideButton={true}>
111
113
  <div className="s-flex s-items-center s-justify-between s-pr-8">
112
114
  <div className="s-flex s-items-center s-gap-3">
113
- {showNavigation && (
115
+ {showNavigation && showHeaderNavigation && (
114
116
  <div className="s-flex s-items-center s-gap-1">
115
117
  <Button
116
118
  icon={ChevronLeftIcon}