@auto-engineer/generate-react-client 1.63.0 → 1.65.0
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/CHANGELOG.md +45 -0
- package/dist/starter/.storybook/main.ts +17 -22
- package/dist/starter/.storybook/manager-head.html +31 -31
- package/dist/starter/.storybook/manager.ts +133 -133
- package/dist/starter/.storybook/preview-head.html +12 -12
- package/dist/starter/.storybook/preview.tsx +79 -79
- package/dist/starter/biome.json +126 -0
- package/dist/starter/codegen.ts +11 -11
- package/dist/starter/components.json +27 -27
- package/dist/starter/package.json +86 -80
- package/dist/starter/public/mockServiceWorker.js +261 -261
- package/dist/starter/scripts/build-component-db.ts +17 -20
- package/dist/starter/src/App.tsx +15 -17
- package/dist/starter/src/components/ui/Accordion.stories.tsx +35 -35
- package/dist/starter/src/components/ui/Accordion.tsx +33 -33
- package/dist/starter/src/components/ui/Alert.stories.tsx +15 -15
- package/dist/starter/src/components/ui/Alert.tsx +32 -32
- package/dist/starter/src/components/ui/AlertDialog.stories.tsx +50 -50
- package/dist/starter/src/components/ui/AlertDialog.tsx +114 -115
- package/dist/starter/src/components/ui/AspectRatio.stories.tsx +20 -20
- package/dist/starter/src/components/ui/AspectRatio.tsx +1 -1
- package/dist/starter/src/components/ui/Avatar.stories.tsx +27 -27
- package/dist/starter/src/components/ui/Avatar.tsx +63 -63
- package/dist/starter/src/components/ui/Badge.stories.tsx +14 -14
- package/dist/starter/src/components/ui/Badge.tsx +27 -27
- package/dist/starter/src/components/ui/Breadcrumb.stories.tsx +38 -38
- package/dist/starter/src/components/ui/Breadcrumb.tsx +63 -62
- package/dist/starter/src/components/ui/Button.stories.tsx +55 -55
- package/dist/starter/src/components/ui/Button.tsx +49 -49
- package/dist/starter/src/components/ui/ButtonGroup.stories.tsx +17 -17
- package/dist/starter/src/components/ui/ButtonGroup.tsx +52 -53
- package/dist/starter/src/components/ui/Calendar.stories.tsx +20 -19
- package/dist/starter/src/components/ui/Calendar.tsx +142 -143
- package/dist/starter/src/components/ui/Card.stories.tsx +29 -29
- package/dist/starter/src/components/ui/Card.tsx +31 -31
- package/dist/starter/src/components/ui/Carousel.stories.tsx +41 -41
- package/dist/starter/src/components/ui/Carousel.tsx +171 -172
- package/dist/starter/src/components/ui/Chart.stories.tsx +21 -21
- package/dist/starter/src/components/ui/Chart.tsx +244 -247
- package/dist/starter/src/components/ui/Checkbox.stories.tsx +11 -11
- package/dist/starter/src/components/ui/Checkbox.tsx +18 -18
- package/dist/starter/src/components/ui/Collapsible.stories.tsx +40 -40
- package/dist/starter/src/components/ui/Collapsible.tsx +3 -3
- package/dist/starter/src/components/ui/Combobox.stories.tsx +48 -48
- package/dist/starter/src/components/ui/Combobox.tsx +204 -205
- package/dist/starter/src/components/ui/Command.stories.tsx +55 -55
- package/dist/starter/src/components/ui/Command.tsx +102 -103
- package/dist/starter/src/components/ui/ContextMenu.stories.tsx +52 -52
- package/dist/starter/src/components/ui/ContextMenu.tsx +151 -151
- package/dist/starter/src/components/ui/DesignSystem-Colors.stories.tsx +92 -92
- package/dist/starter/src/components/ui/DesignSystem-Layout.stories.tsx +139 -139
- package/dist/starter/src/components/ui/DesignSystem-Overview.stories.tsx +676 -657
- package/dist/starter/src/components/ui/DesignSystem-Typography.stories.tsx +59 -59
- package/dist/starter/src/components/ui/Dialog.stories.tsx +56 -56
- package/dist/starter/src/components/ui/Dialog.tsx +97 -98
- package/dist/starter/src/components/ui/Direction.stories.tsx +20 -20
- package/dist/starter/src/components/ui/Direction.tsx +7 -7
- package/dist/starter/src/components/ui/Drawer.stories.tsx +54 -54
- package/dist/starter/src/components/ui/Drawer.tsx +70 -70
- package/dist/starter/src/components/ui/DropdownMenu.stories.tsx +58 -58
- package/dist/starter/src/components/ui/DropdownMenu.tsx +157 -157
- package/dist/starter/src/components/ui/Empty.stories.tsx +22 -22
- package/dist/starter/src/components/ui/Empty.tsx +58 -58
- package/dist/starter/src/components/ui/Field.stories.tsx +31 -31
- package/dist/starter/src/components/ui/Field.tsx +180 -181
- package/dist/starter/src/components/ui/Form.stories.tsx +29 -29
- package/dist/starter/src/components/ui/Form.tsx +93 -96
- package/dist/starter/src/components/ui/HoverCard.stories.tsx +34 -34
- package/dist/starter/src/components/ui/HoverCard.tsx +21 -21
- package/dist/starter/src/components/ui/Input.stories.tsx +18 -18
- package/dist/starter/src/components/ui/Input.tsx +14 -14
- package/dist/starter/src/components/ui/InputGroup.stories.tsx +34 -34
- package/dist/starter/src/components/ui/InputGroup.tsx +110 -111
- package/dist/starter/src/components/ui/InputOTP.stories.tsx +28 -28
- package/dist/starter/src/components/ui/InputOTP.tsx +43 -43
- package/dist/starter/src/components/ui/Item.stories.tsx +45 -45
- package/dist/starter/src/components/ui/Item.tsx +113 -114
- package/dist/starter/src/components/ui/Kbd.stories.tsx +31 -31
- package/dist/starter/src/components/ui/Kbd.tsx +11 -11
- package/dist/starter/src/components/ui/Label.stories.tsx +62 -62
- package/dist/starter/src/components/ui/Label.tsx +26 -25
- package/dist/starter/src/components/ui/Menubar.stories.tsx +62 -62
- package/dist/starter/src/components/ui/Menubar.tsx +173 -173
- package/dist/starter/src/components/ui/NativeSelect.stories.tsx +26 -26
- package/dist/starter/src/components/ui/NativeSelect.tsx +29 -29
- package/dist/starter/src/components/ui/NavigationMenu.stories.tsx +64 -64
- package/dist/starter/src/components/ui/NavigationMenu.tsx +103 -103
- package/dist/starter/src/components/ui/Pagination.stories.tsx +61 -61
- package/dist/starter/src/components/ui/Pagination.tsx +69 -71
- package/dist/starter/src/components/ui/Popover.stories.tsx +38 -38
- package/dist/starter/src/components/ui/Popover.tsx +25 -25
- package/dist/starter/src/components/ui/Progress.stories.tsx +9 -9
- package/dist/starter/src/components/ui/Progress.tsx +14 -14
- package/dist/starter/src/components/ui/RadioGroup.stories.tsx +35 -35
- package/dist/starter/src/components/ui/RadioGroup.tsx +19 -19
- package/dist/starter/src/components/ui/Resizable.stories.tsx +54 -54
- package/dist/starter/src/components/ui/Resizable.tsx +29 -29
- package/dist/starter/src/components/ui/ScrollArea.stories.tsx +27 -27
- package/dist/starter/src/components/ui/ScrollArea.tsx +34 -34
- package/dist/starter/src/components/ui/Select.stories.tsx +43 -43
- package/dist/starter/src/components/ui/Select.tsx +120 -120
- package/dist/starter/src/components/ui/Separator.stories.tsx +27 -27
- package/dist/starter/src/components/ui/Separator.tsx +17 -17
- package/dist/starter/src/components/ui/Sheet.stories.tsx +53 -53
- package/dist/starter/src/components/ui/Sheet.tsx +69 -69
- package/dist/starter/src/components/ui/Sidebar.stories.tsx +77 -77
- package/dist/starter/src/components/ui/Sidebar.tsx +563 -564
- package/dist/starter/src/components/ui/Skeleton.stories.tsx +25 -25
- package/dist/starter/src/components/ui/Skeleton.tsx +1 -1
- package/dist/starter/src/components/ui/Slider.stories.tsx +5 -5
- package/dist/starter/src/components/ui/Slider.tsx +45 -44
- package/dist/starter/src/components/ui/Sonner.stories.tsx +32 -32
- package/dist/starter/src/components/ui/Sonner.tsx +23 -23
- package/dist/starter/src/components/ui/Spinner.stories.tsx +8 -8
- package/dist/starter/src/components/ui/Spinner.tsx +1 -1
- package/dist/starter/src/components/ui/Switch.stories.tsx +16 -17
- package/dist/starter/src/components/ui/Switch.tsx +24 -24
- package/dist/starter/src/components/ui/Table.stories.tsx +50 -50
- package/dist/starter/src/components/ui/Table.tsx +45 -45
- package/dist/starter/src/components/ui/Tabs.stories.tsx +39 -39
- package/dist/starter/src/components/ui/Tabs.tsx +47 -47
- package/dist/starter/src/components/ui/Textarea.stories.tsx +9 -9
- package/dist/starter/src/components/ui/Textarea.tsx +11 -11
- package/dist/starter/src/components/ui/Toast.stories.tsx +77 -77
- package/dist/starter/src/components/ui/Toast.tsx +75 -75
- package/dist/starter/src/components/ui/Toaster.tsx +17 -19
- package/dist/starter/src/components/ui/Toggle.stories.tsx +20 -20
- package/dist/starter/src/components/ui/Toggle.tsx +26 -26
- package/dist/starter/src/components/ui/ToggleGroup.stories.tsx +41 -41
- package/dist/starter/src/components/ui/ToggleGroup.tsx +61 -62
- package/dist/starter/src/components/ui/Tooltip.stories.tsx +26 -26
- package/dist/starter/src/components/ui/Tooltip.tsx +24 -24
- package/dist/starter/src/gql/execute.ts +1 -1
- package/dist/starter/src/gql/fragment-masking.ts +1 -1
- package/dist/starter/src/gql/graphql.ts +3 -0
- package/dist/starter/src/hooks/use-mobile.ts +11 -11
- package/dist/starter/src/hooks/use-toast.ts +135 -135
- package/dist/starter/src/index.css +105 -105
- package/dist/starter/src/lib/utils.ts +1 -1
- package/dist/starter/src/main.tsx +4 -1
- package/dist/starter/tsconfig.app.json +24 -24
- package/dist/starter/tsconfig.json +8 -8
- package/dist/starter/vite.config.ts +38 -37
- package/package.json +3 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
1
|
+
import type * as React from 'react';
|
|
2
2
|
|
|
3
3
|
import { cn } from '@/lib/utils';
|
|
4
4
|
|
|
@@ -7,60 +7,60 @@ import { cn } from '@/lib/utils';
|
|
|
7
7
|
* Compose with CardHeader, CardTitle, CardDescription, CardContent, CardFooter, and CardAction.
|
|
8
8
|
*/
|
|
9
9
|
function Card({ className, ...props }: React.ComponentProps<'div'>) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
return (
|
|
11
|
+
<div
|
|
12
|
+
data-slot="card"
|
|
13
|
+
className={cn('bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm', className)}
|
|
14
|
+
{...props}
|
|
15
|
+
/>
|
|
16
|
+
);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
/** The top section of a Card, containing the title, description, and optional action slot. */
|
|
20
20
|
function CardHeader({ className, ...props }: React.ComponentProps<'div'>) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
21
|
+
return (
|
|
22
|
+
<div
|
|
23
|
+
data-slot="card-header"
|
|
24
|
+
className={cn(
|
|
25
|
+
'@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6',
|
|
26
|
+
className,
|
|
27
|
+
)}
|
|
28
|
+
{...props}
|
|
29
|
+
/>
|
|
30
|
+
);
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
/** The primary heading of a Card, rendered as semibold text. */
|
|
34
34
|
function CardTitle({ className, ...props }: React.ComponentProps<'div'>) {
|
|
35
|
-
|
|
35
|
+
return <div data-slot="card-title" className={cn('leading-none font-semibold', className)} {...props} />;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
/** A short summary below the CardTitle, styled in muted foreground. */
|
|
39
39
|
function CardDescription({ className, ...props }: React.ComponentProps<'div'>) {
|
|
40
|
-
|
|
40
|
+
return <div data-slot="card-description" className={cn('text-muted-foreground text-sm', className)} {...props} />;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
/** An optional action element (e.g., a button or menu) aligned to the top-right of the CardHeader. */
|
|
44
44
|
function CardAction({ className, ...props }: React.ComponentProps<'div'>) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
45
|
+
return (
|
|
46
|
+
<div
|
|
47
|
+
data-slot="card-action"
|
|
48
|
+
className={cn('col-start-2 row-span-2 row-start-1 self-start justify-self-end', className)}
|
|
49
|
+
{...props}
|
|
50
|
+
/>
|
|
51
|
+
);
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
/** The main body area of a Card for arbitrary content. */
|
|
55
55
|
function CardContent({ className, ...props }: React.ComponentProps<'div'>) {
|
|
56
|
-
|
|
56
|
+
return <div data-slot="card-content" className={cn('px-6', className)} {...props} />;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
/** The bottom section of a Card, typically used for action buttons or metadata. */
|
|
60
60
|
function CardFooter({ className, ...props }: React.ComponentProps<'div'>) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
return (
|
|
62
|
+
<div data-slot="card-footer" className={cn('flex items-center px-6 [.border-t]:pt-6', className)} {...props} />
|
|
63
|
+
);
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
export { Card, CardHeader, CardFooter, CardTitle, CardAction, CardDescription, CardContent };
|
|
@@ -1,56 +1,56 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
-
import { Carousel, CarouselContent, CarouselItem, CarouselPrevious, CarouselNext } from '@/components/ui/Carousel';
|
|
3
2
|
import { Card, CardContent } from '@/components/ui/Card';
|
|
3
|
+
import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from '@/components/ui/Carousel';
|
|
4
4
|
|
|
5
5
|
const meta: Meta<typeof Carousel> = {
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
title: 'UI Components/Carousel',
|
|
7
|
+
component: Carousel,
|
|
8
8
|
};
|
|
9
9
|
export default meta;
|
|
10
10
|
type Story = StoryObj<typeof Carousel>;
|
|
11
11
|
|
|
12
12
|
/** Shows a basic carousel with one full-width slide visible at a time and navigation arrows. */
|
|
13
13
|
export const Default: Story = {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
14
|
+
render: () => (
|
|
15
|
+
<div className="w-full max-w-xs mx-auto">
|
|
16
|
+
<Carousel>
|
|
17
|
+
<CarouselContent>
|
|
18
|
+
{Array.from({ length: 5 }).map((_, index) => (
|
|
19
|
+
<CarouselItem key={index}>
|
|
20
|
+
<Card>
|
|
21
|
+
<CardContent className="flex aspect-square items-center justify-center p-6">
|
|
22
|
+
<span className="text-4xl font-semibold">{index + 1}</span>
|
|
23
|
+
</CardContent>
|
|
24
|
+
</Card>
|
|
25
|
+
</CarouselItem>
|
|
26
|
+
))}
|
|
27
|
+
</CarouselContent>
|
|
28
|
+
<CarouselPrevious />
|
|
29
|
+
<CarouselNext />
|
|
30
|
+
</Carousel>
|
|
31
|
+
</div>
|
|
32
|
+
),
|
|
33
33
|
};
|
|
34
34
|
|
|
35
35
|
/** Demonstrates showing three slides simultaneously using `basis-1/3` on each CarouselItem. */
|
|
36
36
|
export const ThirdWidth: Story = {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
37
|
+
render: () => (
|
|
38
|
+
<div className="w-full max-w-sm mx-auto">
|
|
39
|
+
<Carousel>
|
|
40
|
+
<CarouselContent>
|
|
41
|
+
{Array.from({ length: 5 }).map((_, index) => (
|
|
42
|
+
<CarouselItem key={index} className="basis-1/3">
|
|
43
|
+
<Card>
|
|
44
|
+
<CardContent className="flex aspect-square items-center justify-center p-2">
|
|
45
|
+
<span className="text-2xl font-semibold">{index + 1}</span>
|
|
46
|
+
</CardContent>
|
|
47
|
+
</Card>
|
|
48
|
+
</CarouselItem>
|
|
49
|
+
))}
|
|
50
|
+
</CarouselContent>
|
|
51
|
+
<CarouselPrevious />
|
|
52
|
+
<CarouselNext />
|
|
53
|
+
</Carousel>
|
|
54
|
+
</div>
|
|
55
|
+
),
|
|
56
56
|
};
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import * as React from 'react';
|
|
4
3
|
import useEmblaCarousel, { type UseEmblaCarouselType } from 'embla-carousel-react';
|
|
5
4
|
import { ArrowLeft, ArrowRight } from 'lucide-react';
|
|
6
|
-
|
|
7
|
-
import { cn } from '@/lib/utils';
|
|
5
|
+
import * as React from 'react';
|
|
8
6
|
import { Button } from '@/components/ui/Button';
|
|
7
|
+
import { cn } from '@/lib/utils';
|
|
9
8
|
|
|
10
9
|
type CarouselApi = UseEmblaCarouselType[1];
|
|
11
10
|
type UseCarouselParameters = Parameters<typeof useEmblaCarousel>;
|
|
@@ -13,31 +12,31 @@ type CarouselOptions = UseCarouselParameters[0];
|
|
|
13
12
|
type CarouselPlugin = UseCarouselParameters[1];
|
|
14
13
|
|
|
15
14
|
type CarouselProps = {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
opts?: CarouselOptions;
|
|
16
|
+
plugins?: CarouselPlugin;
|
|
17
|
+
orientation?: 'horizontal' | 'vertical';
|
|
18
|
+
setApi?: (api: CarouselApi) => void;
|
|
20
19
|
};
|
|
21
20
|
|
|
22
21
|
type CarouselContextProps = {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
carouselRef: ReturnType<typeof useEmblaCarousel>[0];
|
|
23
|
+
api: ReturnType<typeof useEmblaCarousel>[1];
|
|
24
|
+
scrollPrev: () => void;
|
|
25
|
+
scrollNext: () => void;
|
|
26
|
+
canScrollPrev: boolean;
|
|
27
|
+
canScrollNext: boolean;
|
|
29
28
|
} & CarouselProps;
|
|
30
29
|
|
|
31
30
|
const CarouselContext = React.createContext<CarouselContextProps | null>(null);
|
|
32
31
|
|
|
33
32
|
function useCarousel() {
|
|
34
|
-
|
|
33
|
+
const context = React.useContext(CarouselContext);
|
|
35
34
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
if (!context) {
|
|
36
|
+
throw new Error('useCarousel must be used within a <Carousel />');
|
|
37
|
+
}
|
|
39
38
|
|
|
40
|
-
|
|
39
|
+
return context;
|
|
41
40
|
}
|
|
42
41
|
|
|
43
42
|
/**
|
|
@@ -46,180 +45,180 @@ function useCarousel() {
|
|
|
46
45
|
* Supports horizontal and vertical orientation, and accepts Embla plugins (e.g., autoplay).
|
|
47
46
|
*/
|
|
48
47
|
function Carousel({
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
48
|
+
orientation = 'horizontal',
|
|
49
|
+
opts,
|
|
50
|
+
setApi,
|
|
51
|
+
plugins,
|
|
52
|
+
className,
|
|
53
|
+
children,
|
|
54
|
+
...props
|
|
56
55
|
}: React.ComponentProps<'div'> & CarouselProps) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
56
|
+
const [carouselRef, api] = useEmblaCarousel(
|
|
57
|
+
{
|
|
58
|
+
...opts,
|
|
59
|
+
axis: orientation === 'horizontal' ? 'x' : 'y',
|
|
60
|
+
},
|
|
61
|
+
plugins,
|
|
62
|
+
);
|
|
63
|
+
const [canScrollPrev, setCanScrollPrev] = React.useState(false);
|
|
64
|
+
const [canScrollNext, setCanScrollNext] = React.useState(false);
|
|
65
|
+
|
|
66
|
+
const onSelect = React.useCallback((api: CarouselApi) => {
|
|
67
|
+
if (!api) return;
|
|
68
|
+
setCanScrollPrev(api.canScrollPrev());
|
|
69
|
+
setCanScrollNext(api.canScrollNext());
|
|
70
|
+
}, []);
|
|
71
|
+
|
|
72
|
+
const scrollPrev = React.useCallback(() => {
|
|
73
|
+
api?.scrollPrev();
|
|
74
|
+
}, [api]);
|
|
75
|
+
|
|
76
|
+
const scrollNext = React.useCallback(() => {
|
|
77
|
+
api?.scrollNext();
|
|
78
|
+
}, [api]);
|
|
79
|
+
|
|
80
|
+
const handleKeyDown = React.useCallback(
|
|
81
|
+
(event: React.KeyboardEvent<HTMLDivElement>) => {
|
|
82
|
+
if (event.key === 'ArrowLeft') {
|
|
83
|
+
event.preventDefault();
|
|
84
|
+
scrollPrev();
|
|
85
|
+
} else if (event.key === 'ArrowRight') {
|
|
86
|
+
event.preventDefault();
|
|
87
|
+
scrollNext();
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
[scrollPrev, scrollNext],
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
React.useEffect(() => {
|
|
94
|
+
if (!api || !setApi) return;
|
|
95
|
+
setApi(api);
|
|
96
|
+
}, [api, setApi]);
|
|
97
|
+
|
|
98
|
+
React.useEffect(() => {
|
|
99
|
+
if (!api) return;
|
|
100
|
+
onSelect(api);
|
|
101
|
+
api.on('reInit', onSelect);
|
|
102
|
+
api.on('select', onSelect);
|
|
103
|
+
|
|
104
|
+
return () => {
|
|
105
|
+
api?.off('select', onSelect);
|
|
106
|
+
};
|
|
107
|
+
}, [api, onSelect]);
|
|
108
|
+
|
|
109
|
+
return (
|
|
110
|
+
<CarouselContext.Provider
|
|
111
|
+
value={{
|
|
112
|
+
carouselRef,
|
|
113
|
+
api: api,
|
|
114
|
+
opts,
|
|
115
|
+
orientation: orientation || (opts?.axis === 'y' ? 'vertical' : 'horizontal'),
|
|
116
|
+
scrollPrev,
|
|
117
|
+
scrollNext,
|
|
118
|
+
canScrollPrev,
|
|
119
|
+
canScrollNext,
|
|
120
|
+
}}
|
|
121
|
+
>
|
|
122
|
+
<div
|
|
123
|
+
onKeyDownCapture={handleKeyDown}
|
|
124
|
+
className={cn('relative', className)}
|
|
125
|
+
role="region"
|
|
126
|
+
aria-roledescription="carousel"
|
|
127
|
+
data-slot="carousel"
|
|
128
|
+
{...props}
|
|
129
|
+
>
|
|
130
|
+
{children}
|
|
131
|
+
</div>
|
|
132
|
+
</CarouselContext.Provider>
|
|
133
|
+
);
|
|
135
134
|
}
|
|
136
135
|
|
|
137
136
|
/** The scrollable container for carousel slides. Wraps CarouselItem children in a flex layout. */
|
|
138
137
|
function CarouselContent({ className, ...props }: React.ComponentProps<'div'>) {
|
|
139
|
-
|
|
138
|
+
const { carouselRef, orientation } = useCarousel();
|
|
140
139
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
140
|
+
return (
|
|
141
|
+
<div ref={carouselRef} className="overflow-hidden" data-slot="carousel-content">
|
|
142
|
+
<div className={cn('flex', orientation === 'horizontal' ? '-ml-4' : '-mt-4 flex-col', className)} {...props} />
|
|
143
|
+
</div>
|
|
144
|
+
);
|
|
146
145
|
}
|
|
147
146
|
|
|
148
147
|
/** A single slide within the carousel. Takes full width by default; use `basis-*` classes to show multiple slides. */
|
|
149
148
|
function CarouselItem({ className, ...props }: React.ComponentProps<'div'>) {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
149
|
+
const { orientation } = useCarousel();
|
|
150
|
+
|
|
151
|
+
return (
|
|
152
|
+
<div
|
|
153
|
+
role="group"
|
|
154
|
+
aria-roledescription="slide"
|
|
155
|
+
data-slot="carousel-item"
|
|
156
|
+
className={cn('min-w-0 shrink-0 grow-0 basis-full', orientation === 'horizontal' ? 'pl-4' : 'pt-4', className)}
|
|
157
|
+
{...props}
|
|
158
|
+
/>
|
|
159
|
+
);
|
|
161
160
|
}
|
|
162
161
|
|
|
163
162
|
/** Navigation button to scroll to the previous slide, automatically disabled at the beginning. */
|
|
164
163
|
function CarouselPrevious({
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
164
|
+
className,
|
|
165
|
+
variant = 'outline',
|
|
166
|
+
size = 'icon',
|
|
167
|
+
...props
|
|
169
168
|
}: React.ComponentProps<typeof Button>) {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
169
|
+
const { orientation, scrollPrev, canScrollPrev } = useCarousel();
|
|
170
|
+
|
|
171
|
+
return (
|
|
172
|
+
<Button
|
|
173
|
+
data-slot="carousel-previous"
|
|
174
|
+
variant={variant}
|
|
175
|
+
size={size}
|
|
176
|
+
className={cn(
|
|
177
|
+
'absolute size-8 rounded-full',
|
|
178
|
+
orientation === 'horizontal'
|
|
179
|
+
? 'top-1/2 -left-12 -translate-y-1/2'
|
|
180
|
+
: '-top-12 left-1/2 -translate-x-1/2 rotate-90',
|
|
181
|
+
className,
|
|
182
|
+
)}
|
|
183
|
+
disabled={!canScrollPrev}
|
|
184
|
+
onClick={scrollPrev}
|
|
185
|
+
{...props}
|
|
186
|
+
>
|
|
187
|
+
<ArrowLeft />
|
|
188
|
+
<span className="sr-only">Previous slide</span>
|
|
189
|
+
</Button>
|
|
190
|
+
);
|
|
192
191
|
}
|
|
193
192
|
|
|
194
193
|
/** Navigation button to scroll to the next slide, automatically disabled at the end. */
|
|
195
194
|
function CarouselNext({
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
195
|
+
className,
|
|
196
|
+
variant = 'outline',
|
|
197
|
+
size = 'icon',
|
|
198
|
+
...props
|
|
200
199
|
}: React.ComponentProps<typeof Button>) {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
200
|
+
const { orientation, scrollNext, canScrollNext } = useCarousel();
|
|
201
|
+
|
|
202
|
+
return (
|
|
203
|
+
<Button
|
|
204
|
+
data-slot="carousel-next"
|
|
205
|
+
variant={variant}
|
|
206
|
+
size={size}
|
|
207
|
+
className={cn(
|
|
208
|
+
'absolute size-8 rounded-full',
|
|
209
|
+
orientation === 'horizontal'
|
|
210
|
+
? 'top-1/2 -right-12 -translate-y-1/2'
|
|
211
|
+
: '-bottom-12 left-1/2 -translate-x-1/2 rotate-90',
|
|
212
|
+
className,
|
|
213
|
+
)}
|
|
214
|
+
disabled={!canScrollNext}
|
|
215
|
+
onClick={scrollNext}
|
|
216
|
+
{...props}
|
|
217
|
+
>
|
|
218
|
+
<ArrowRight />
|
|
219
|
+
<span className="sr-only">Next slide</span>
|
|
220
|
+
</Button>
|
|
221
|
+
);
|
|
223
222
|
}
|
|
224
223
|
|
|
225
224
|
export { type CarouselApi, Carousel, CarouselContent, CarouselItem, CarouselPrevious, CarouselNext };
|
|
@@ -3,37 +3,37 @@ import { Bar, BarChart, XAxis, YAxis } from 'recharts';
|
|
|
3
3
|
import { type ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/Chart';
|
|
4
4
|
|
|
5
5
|
const meta: Meta<typeof ChartContainer> = {
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
title: 'UI Components/Chart',
|
|
7
|
+
component: ChartContainer,
|
|
8
8
|
};
|
|
9
9
|
export default meta;
|
|
10
10
|
type Story = StoryObj<typeof ChartContainer>;
|
|
11
11
|
|
|
12
12
|
const chartData = [
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
{ month: 'Jan', desktop: 186, mobile: 80 },
|
|
14
|
+
{ month: 'Feb', desktop: 305, mobile: 200 },
|
|
15
|
+
{ month: 'Mar', desktop: 237, mobile: 120 },
|
|
16
|
+
{ month: 'Apr', desktop: 73, mobile: 190 },
|
|
17
|
+
{ month: 'May', desktop: 209, mobile: 130 },
|
|
18
|
+
{ month: 'Jun', desktop: 214, mobile: 140 },
|
|
19
19
|
];
|
|
20
20
|
|
|
21
21
|
const chartConfig = {
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
desktop: { label: 'Desktop', color: 'var(--chart-1)' },
|
|
23
|
+
mobile: { label: 'Mobile', color: 'var(--chart-2)' },
|
|
24
24
|
} satisfies ChartConfig;
|
|
25
25
|
|
|
26
26
|
/** Shows a grouped bar chart with desktop and mobile data series, tooltips, and themed colors. */
|
|
27
27
|
export const Default: Story = {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
28
|
+
render: () => (
|
|
29
|
+
<ChartContainer config={chartConfig} className="min-h-[200px] w-full">
|
|
30
|
+
<BarChart data={chartData}>
|
|
31
|
+
<XAxis dataKey="month" />
|
|
32
|
+
<YAxis />
|
|
33
|
+
<ChartTooltip content={<ChartTooltipContent />} />
|
|
34
|
+
<Bar dataKey="desktop" fill="var(--color-desktop)" radius={4} />
|
|
35
|
+
<Bar dataKey="mobile" fill="var(--color-mobile)" radius={4} />
|
|
36
|
+
</BarChart>
|
|
37
|
+
</ChartContainer>
|
|
38
|
+
),
|
|
39
39
|
};
|