@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/cjs/index.js +1 -1
- package/dist/esm/components/MultiPageDialog.d.ts +34 -0
- package/dist/esm/components/MultiPageDialog.d.ts.map +1 -0
- package/dist/esm/components/MultiPageDialog.js +116 -0
- package/dist/esm/components/MultiPageDialog.js.map +1 -0
- package/dist/esm/components/MultiPageSheet.d.ts +1 -0
- package/dist/esm/components/MultiPageSheet.d.ts.map +1 -1
- package/dist/esm/components/MultiPageSheet.js +2 -2
- package/dist/esm/components/MultiPageSheet.js.map +1 -1
- package/dist/esm/stories/MultiPageDialog.stories.d.ts +10 -0
- package/dist/esm/stories/MultiPageDialog.stories.d.ts.map +1 -0
- package/dist/esm/stories/MultiPageDialog.stories.js +301 -0
- package/dist/esm/stories/MultiPageDialog.stories.js.map +1 -0
- package/dist/sparkle.css +47 -0
- package/package.json +1 -1
- package/src/components/MultiPageDialog.tsx +295 -0
- package/src/components/MultiPageSheet.tsx +3 -1
- package/src/stories/MultiPageDialog.stories.tsx +592 -0
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
|
@@ -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}
|