@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.
Files changed (144) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/dist/starter/.storybook/main.ts +17 -22
  3. package/dist/starter/.storybook/manager-head.html +31 -31
  4. package/dist/starter/.storybook/manager.ts +133 -133
  5. package/dist/starter/.storybook/preview-head.html +12 -12
  6. package/dist/starter/.storybook/preview.tsx +79 -79
  7. package/dist/starter/biome.json +126 -0
  8. package/dist/starter/codegen.ts +11 -11
  9. package/dist/starter/components.json +27 -27
  10. package/dist/starter/package.json +86 -80
  11. package/dist/starter/public/mockServiceWorker.js +261 -261
  12. package/dist/starter/scripts/build-component-db.ts +17 -20
  13. package/dist/starter/src/App.tsx +15 -17
  14. package/dist/starter/src/components/ui/Accordion.stories.tsx +35 -35
  15. package/dist/starter/src/components/ui/Accordion.tsx +33 -33
  16. package/dist/starter/src/components/ui/Alert.stories.tsx +15 -15
  17. package/dist/starter/src/components/ui/Alert.tsx +32 -32
  18. package/dist/starter/src/components/ui/AlertDialog.stories.tsx +50 -50
  19. package/dist/starter/src/components/ui/AlertDialog.tsx +114 -115
  20. package/dist/starter/src/components/ui/AspectRatio.stories.tsx +20 -20
  21. package/dist/starter/src/components/ui/AspectRatio.tsx +1 -1
  22. package/dist/starter/src/components/ui/Avatar.stories.tsx +27 -27
  23. package/dist/starter/src/components/ui/Avatar.tsx +63 -63
  24. package/dist/starter/src/components/ui/Badge.stories.tsx +14 -14
  25. package/dist/starter/src/components/ui/Badge.tsx +27 -27
  26. package/dist/starter/src/components/ui/Breadcrumb.stories.tsx +38 -38
  27. package/dist/starter/src/components/ui/Breadcrumb.tsx +63 -62
  28. package/dist/starter/src/components/ui/Button.stories.tsx +55 -55
  29. package/dist/starter/src/components/ui/Button.tsx +49 -49
  30. package/dist/starter/src/components/ui/ButtonGroup.stories.tsx +17 -17
  31. package/dist/starter/src/components/ui/ButtonGroup.tsx +52 -53
  32. package/dist/starter/src/components/ui/Calendar.stories.tsx +20 -19
  33. package/dist/starter/src/components/ui/Calendar.tsx +142 -143
  34. package/dist/starter/src/components/ui/Card.stories.tsx +29 -29
  35. package/dist/starter/src/components/ui/Card.tsx +31 -31
  36. package/dist/starter/src/components/ui/Carousel.stories.tsx +41 -41
  37. package/dist/starter/src/components/ui/Carousel.tsx +171 -172
  38. package/dist/starter/src/components/ui/Chart.stories.tsx +21 -21
  39. package/dist/starter/src/components/ui/Chart.tsx +244 -247
  40. package/dist/starter/src/components/ui/Checkbox.stories.tsx +11 -11
  41. package/dist/starter/src/components/ui/Checkbox.tsx +18 -18
  42. package/dist/starter/src/components/ui/Collapsible.stories.tsx +40 -40
  43. package/dist/starter/src/components/ui/Collapsible.tsx +3 -3
  44. package/dist/starter/src/components/ui/Combobox.stories.tsx +48 -48
  45. package/dist/starter/src/components/ui/Combobox.tsx +204 -205
  46. package/dist/starter/src/components/ui/Command.stories.tsx +55 -55
  47. package/dist/starter/src/components/ui/Command.tsx +102 -103
  48. package/dist/starter/src/components/ui/ContextMenu.stories.tsx +52 -52
  49. package/dist/starter/src/components/ui/ContextMenu.tsx +151 -151
  50. package/dist/starter/src/components/ui/DesignSystem-Colors.stories.tsx +92 -92
  51. package/dist/starter/src/components/ui/DesignSystem-Layout.stories.tsx +139 -139
  52. package/dist/starter/src/components/ui/DesignSystem-Overview.stories.tsx +676 -657
  53. package/dist/starter/src/components/ui/DesignSystem-Typography.stories.tsx +59 -59
  54. package/dist/starter/src/components/ui/Dialog.stories.tsx +56 -56
  55. package/dist/starter/src/components/ui/Dialog.tsx +97 -98
  56. package/dist/starter/src/components/ui/Direction.stories.tsx +20 -20
  57. package/dist/starter/src/components/ui/Direction.tsx +7 -7
  58. package/dist/starter/src/components/ui/Drawer.stories.tsx +54 -54
  59. package/dist/starter/src/components/ui/Drawer.tsx +70 -70
  60. package/dist/starter/src/components/ui/DropdownMenu.stories.tsx +58 -58
  61. package/dist/starter/src/components/ui/DropdownMenu.tsx +157 -157
  62. package/dist/starter/src/components/ui/Empty.stories.tsx +22 -22
  63. package/dist/starter/src/components/ui/Empty.tsx +58 -58
  64. package/dist/starter/src/components/ui/Field.stories.tsx +31 -31
  65. package/dist/starter/src/components/ui/Field.tsx +180 -181
  66. package/dist/starter/src/components/ui/Form.stories.tsx +29 -29
  67. package/dist/starter/src/components/ui/Form.tsx +93 -96
  68. package/dist/starter/src/components/ui/HoverCard.stories.tsx +34 -34
  69. package/dist/starter/src/components/ui/HoverCard.tsx +21 -21
  70. package/dist/starter/src/components/ui/Input.stories.tsx +18 -18
  71. package/dist/starter/src/components/ui/Input.tsx +14 -14
  72. package/dist/starter/src/components/ui/InputGroup.stories.tsx +34 -34
  73. package/dist/starter/src/components/ui/InputGroup.tsx +110 -111
  74. package/dist/starter/src/components/ui/InputOTP.stories.tsx +28 -28
  75. package/dist/starter/src/components/ui/InputOTP.tsx +43 -43
  76. package/dist/starter/src/components/ui/Item.stories.tsx +45 -45
  77. package/dist/starter/src/components/ui/Item.tsx +113 -114
  78. package/dist/starter/src/components/ui/Kbd.stories.tsx +31 -31
  79. package/dist/starter/src/components/ui/Kbd.tsx +11 -11
  80. package/dist/starter/src/components/ui/Label.stories.tsx +62 -62
  81. package/dist/starter/src/components/ui/Label.tsx +26 -25
  82. package/dist/starter/src/components/ui/Menubar.stories.tsx +62 -62
  83. package/dist/starter/src/components/ui/Menubar.tsx +173 -173
  84. package/dist/starter/src/components/ui/NativeSelect.stories.tsx +26 -26
  85. package/dist/starter/src/components/ui/NativeSelect.tsx +29 -29
  86. package/dist/starter/src/components/ui/NavigationMenu.stories.tsx +64 -64
  87. package/dist/starter/src/components/ui/NavigationMenu.tsx +103 -103
  88. package/dist/starter/src/components/ui/Pagination.stories.tsx +61 -61
  89. package/dist/starter/src/components/ui/Pagination.tsx +69 -71
  90. package/dist/starter/src/components/ui/Popover.stories.tsx +38 -38
  91. package/dist/starter/src/components/ui/Popover.tsx +25 -25
  92. package/dist/starter/src/components/ui/Progress.stories.tsx +9 -9
  93. package/dist/starter/src/components/ui/Progress.tsx +14 -14
  94. package/dist/starter/src/components/ui/RadioGroup.stories.tsx +35 -35
  95. package/dist/starter/src/components/ui/RadioGroup.tsx +19 -19
  96. package/dist/starter/src/components/ui/Resizable.stories.tsx +54 -54
  97. package/dist/starter/src/components/ui/Resizable.tsx +29 -29
  98. package/dist/starter/src/components/ui/ScrollArea.stories.tsx +27 -27
  99. package/dist/starter/src/components/ui/ScrollArea.tsx +34 -34
  100. package/dist/starter/src/components/ui/Select.stories.tsx +43 -43
  101. package/dist/starter/src/components/ui/Select.tsx +120 -120
  102. package/dist/starter/src/components/ui/Separator.stories.tsx +27 -27
  103. package/dist/starter/src/components/ui/Separator.tsx +17 -17
  104. package/dist/starter/src/components/ui/Sheet.stories.tsx +53 -53
  105. package/dist/starter/src/components/ui/Sheet.tsx +69 -69
  106. package/dist/starter/src/components/ui/Sidebar.stories.tsx +77 -77
  107. package/dist/starter/src/components/ui/Sidebar.tsx +563 -564
  108. package/dist/starter/src/components/ui/Skeleton.stories.tsx +25 -25
  109. package/dist/starter/src/components/ui/Skeleton.tsx +1 -1
  110. package/dist/starter/src/components/ui/Slider.stories.tsx +5 -5
  111. package/dist/starter/src/components/ui/Slider.tsx +45 -44
  112. package/dist/starter/src/components/ui/Sonner.stories.tsx +32 -32
  113. package/dist/starter/src/components/ui/Sonner.tsx +23 -23
  114. package/dist/starter/src/components/ui/Spinner.stories.tsx +8 -8
  115. package/dist/starter/src/components/ui/Spinner.tsx +1 -1
  116. package/dist/starter/src/components/ui/Switch.stories.tsx +16 -17
  117. package/dist/starter/src/components/ui/Switch.tsx +24 -24
  118. package/dist/starter/src/components/ui/Table.stories.tsx +50 -50
  119. package/dist/starter/src/components/ui/Table.tsx +45 -45
  120. package/dist/starter/src/components/ui/Tabs.stories.tsx +39 -39
  121. package/dist/starter/src/components/ui/Tabs.tsx +47 -47
  122. package/dist/starter/src/components/ui/Textarea.stories.tsx +9 -9
  123. package/dist/starter/src/components/ui/Textarea.tsx +11 -11
  124. package/dist/starter/src/components/ui/Toast.stories.tsx +77 -77
  125. package/dist/starter/src/components/ui/Toast.tsx +75 -75
  126. package/dist/starter/src/components/ui/Toaster.tsx +17 -19
  127. package/dist/starter/src/components/ui/Toggle.stories.tsx +20 -20
  128. package/dist/starter/src/components/ui/Toggle.tsx +26 -26
  129. package/dist/starter/src/components/ui/ToggleGroup.stories.tsx +41 -41
  130. package/dist/starter/src/components/ui/ToggleGroup.tsx +61 -62
  131. package/dist/starter/src/components/ui/Tooltip.stories.tsx +26 -26
  132. package/dist/starter/src/components/ui/Tooltip.tsx +24 -24
  133. package/dist/starter/src/gql/execute.ts +1 -1
  134. package/dist/starter/src/gql/fragment-masking.ts +1 -1
  135. package/dist/starter/src/gql/graphql.ts +3 -0
  136. package/dist/starter/src/hooks/use-mobile.ts +11 -11
  137. package/dist/starter/src/hooks/use-toast.ts +135 -135
  138. package/dist/starter/src/index.css +105 -105
  139. package/dist/starter/src/lib/utils.ts +1 -1
  140. package/dist/starter/src/main.tsx +4 -1
  141. package/dist/starter/tsconfig.app.json +24 -24
  142. package/dist/starter/tsconfig.json +8 -8
  143. package/dist/starter/vite.config.ts +38 -37
  144. 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
- 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
- );
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
- 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
- );
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
- return <div data-slot="card-title" className={cn('leading-none font-semibold', className)} {...props} />;
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
- return <div data-slot="card-description" className={cn('text-muted-foreground text-sm', className)} {...props} />;
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
- 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
- );
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
- return <div data-slot="card-content" className={cn('px-6', className)} {...props} />;
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
- return (
62
- <div data-slot="card-footer" className={cn('flex items-center px-6 [.border-t]:pt-6', className)} {...props} />
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
- title: 'UI Components/Carousel',
7
- component: Carousel,
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
- 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
- ),
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
- 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
- ),
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
- opts?: CarouselOptions;
17
- plugins?: CarouselPlugin;
18
- orientation?: 'horizontal' | 'vertical';
19
- setApi?: (api: CarouselApi) => void;
15
+ opts?: CarouselOptions;
16
+ plugins?: CarouselPlugin;
17
+ orientation?: 'horizontal' | 'vertical';
18
+ setApi?: (api: CarouselApi) => void;
20
19
  };
21
20
 
22
21
  type CarouselContextProps = {
23
- carouselRef: ReturnType<typeof useEmblaCarousel>[0];
24
- api: ReturnType<typeof useEmblaCarousel>[1];
25
- scrollPrev: () => void;
26
- scrollNext: () => void;
27
- canScrollPrev: boolean;
28
- canScrollNext: boolean;
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
- const context = React.useContext(CarouselContext);
33
+ const context = React.useContext(CarouselContext);
35
34
 
36
- if (!context) {
37
- throw new Error('useCarousel must be used within a <Carousel />');
38
- }
35
+ if (!context) {
36
+ throw new Error('useCarousel must be used within a <Carousel />');
37
+ }
39
38
 
40
- return context;
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
- orientation = 'horizontal',
50
- opts,
51
- setApi,
52
- plugins,
53
- className,
54
- children,
55
- ...props
48
+ orientation = 'horizontal',
49
+ opts,
50
+ setApi,
51
+ plugins,
52
+ className,
53
+ children,
54
+ ...props
56
55
  }: React.ComponentProps<'div'> & CarouselProps) {
57
- const [carouselRef, api] = useEmblaCarousel(
58
- {
59
- ...opts,
60
- axis: orientation === 'horizontal' ? 'x' : 'y',
61
- },
62
- plugins,
63
- );
64
- const [canScrollPrev, setCanScrollPrev] = React.useState(false);
65
- const [canScrollNext, setCanScrollNext] = React.useState(false);
66
-
67
- const onSelect = React.useCallback((api: CarouselApi) => {
68
- if (!api) return;
69
- setCanScrollPrev(api.canScrollPrev());
70
- setCanScrollNext(api.canScrollNext());
71
- }, []);
72
-
73
- const scrollPrev = React.useCallback(() => {
74
- api?.scrollPrev();
75
- }, [api]);
76
-
77
- const scrollNext = React.useCallback(() => {
78
- api?.scrollNext();
79
- }, [api]);
80
-
81
- const handleKeyDown = React.useCallback(
82
- (event: React.KeyboardEvent<HTMLDivElement>) => {
83
- if (event.key === 'ArrowLeft') {
84
- event.preventDefault();
85
- scrollPrev();
86
- } else if (event.key === 'ArrowRight') {
87
- event.preventDefault();
88
- scrollNext();
89
- }
90
- },
91
- [scrollPrev, scrollNext],
92
- );
93
-
94
- React.useEffect(() => {
95
- if (!api || !setApi) return;
96
- setApi(api);
97
- }, [api, setApi]);
98
-
99
- React.useEffect(() => {
100
- if (!api) return;
101
- onSelect(api);
102
- api.on('reInit', onSelect);
103
- api.on('select', onSelect);
104
-
105
- return () => {
106
- api?.off('select', onSelect);
107
- };
108
- }, [api, onSelect]);
109
-
110
- return (
111
- <CarouselContext.Provider
112
- value={{
113
- carouselRef,
114
- api: api,
115
- opts,
116
- orientation: orientation || (opts?.axis === 'y' ? 'vertical' : 'horizontal'),
117
- scrollPrev,
118
- scrollNext,
119
- canScrollPrev,
120
- canScrollNext,
121
- }}
122
- >
123
- <div
124
- onKeyDownCapture={handleKeyDown}
125
- className={cn('relative', className)}
126
- role="region"
127
- aria-roledescription="carousel"
128
- data-slot="carousel"
129
- {...props}
130
- >
131
- {children}
132
- </div>
133
- </CarouselContext.Provider>
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
- const { carouselRef, orientation } = useCarousel();
138
+ const { carouselRef, orientation } = useCarousel();
140
139
 
141
- return (
142
- <div ref={carouselRef} className="overflow-hidden" data-slot="carousel-content">
143
- <div className={cn('flex', orientation === 'horizontal' ? '-ml-4' : '-mt-4 flex-col', className)} {...props} />
144
- </div>
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
- const { orientation } = useCarousel();
151
-
152
- return (
153
- <div
154
- role="group"
155
- aria-roledescription="slide"
156
- data-slot="carousel-item"
157
- className={cn('min-w-0 shrink-0 grow-0 basis-full', orientation === 'horizontal' ? 'pl-4' : 'pt-4', className)}
158
- {...props}
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
- className,
166
- variant = 'outline',
167
- size = 'icon',
168
- ...props
164
+ className,
165
+ variant = 'outline',
166
+ size = 'icon',
167
+ ...props
169
168
  }: React.ComponentProps<typeof Button>) {
170
- const { orientation, scrollPrev, canScrollPrev } = useCarousel();
171
-
172
- return (
173
- <Button
174
- data-slot="carousel-previous"
175
- variant={variant}
176
- size={size}
177
- className={cn(
178
- 'absolute size-8 rounded-full',
179
- orientation === 'horizontal'
180
- ? 'top-1/2 -left-12 -translate-y-1/2'
181
- : '-top-12 left-1/2 -translate-x-1/2 rotate-90',
182
- className,
183
- )}
184
- disabled={!canScrollPrev}
185
- onClick={scrollPrev}
186
- {...props}
187
- >
188
- <ArrowLeft />
189
- <span className="sr-only">Previous slide</span>
190
- </Button>
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
- className,
197
- variant = 'outline',
198
- size = 'icon',
199
- ...props
195
+ className,
196
+ variant = 'outline',
197
+ size = 'icon',
198
+ ...props
200
199
  }: React.ComponentProps<typeof Button>) {
201
- const { orientation, scrollNext, canScrollNext } = useCarousel();
202
-
203
- return (
204
- <Button
205
- data-slot="carousel-next"
206
- variant={variant}
207
- size={size}
208
- className={cn(
209
- 'absolute size-8 rounded-full',
210
- orientation === 'horizontal'
211
- ? 'top-1/2 -right-12 -translate-y-1/2'
212
- : '-bottom-12 left-1/2 -translate-x-1/2 rotate-90',
213
- className,
214
- )}
215
- disabled={!canScrollNext}
216
- onClick={scrollNext}
217
- {...props}
218
- >
219
- <ArrowRight />
220
- <span className="sr-only">Next slide</span>
221
- </Button>
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
- title: 'UI Components/Chart',
7
- component: ChartContainer,
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
- { 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 },
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
- desktop: { label: 'Desktop', color: 'var(--chart-1)' },
23
- mobile: { label: 'Mobile', color: 'var(--chart-2)' },
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
- 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
- ),
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
  };