sonance-brand-mcp 1.2.4 → 1.3.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.
Files changed (90) hide show
  1. package/dist/assets/components/alert-dialog.stories.tsx +142 -0
  2. package/dist/assets/components/alert-dialog.tsx +142 -0
  3. package/dist/assets/components/aspect-ratio.stories.tsx +67 -0
  4. package/dist/assets/components/aspect-ratio.tsx +8 -0
  5. package/dist/assets/components/avatar.tsx +64 -20
  6. package/dist/assets/components/carousel.stories.tsx +158 -0
  7. package/dist/assets/components/carousel.tsx +262 -0
  8. package/dist/assets/components/chart.stories.tsx +376 -0
  9. package/dist/assets/components/chart.tsx +384 -0
  10. package/dist/assets/components/checkbox.tsx +12 -2
  11. package/dist/assets/components/code.tsx +22 -20
  12. package/dist/assets/components/collapsible.stories.tsx +128 -0
  13. package/dist/assets/components/collapsible.tsx +10 -0
  14. package/dist/assets/components/command.stories.tsx +183 -0
  15. package/dist/assets/components/command.tsx +170 -0
  16. package/dist/assets/components/context-menu.stories.tsx +159 -0
  17. package/dist/assets/components/context-menu.tsx +218 -0
  18. package/dist/assets/components/divider.tsx +38 -35
  19. package/dist/assets/components/dropdown-menu.tsx +217 -0
  20. package/dist/assets/components/hover-card.stories.tsx +113 -0
  21. package/dist/assets/components/hover-card.tsx +35 -0
  22. package/dist/assets/components/kbd.tsx +6 -6
  23. package/dist/assets/components/menubar.stories.tsx +208 -0
  24. package/dist/assets/components/menubar.tsx +251 -0
  25. package/dist/assets/components/navigation-menu.stories.tsx +237 -0
  26. package/dist/assets/components/navigation-menu.tsx +135 -0
  27. package/dist/assets/components/resizable.stories.tsx +197 -0
  28. package/dist/assets/components/resizable.tsx +47 -0
  29. package/dist/assets/components/scroll-area.stories.tsx +123 -0
  30. package/dist/assets/components/scroll-area.tsx +48 -0
  31. package/dist/assets/components/scroll-shadow.tsx +29 -7
  32. package/dist/assets/components/separator.tsx +32 -0
  33. package/dist/assets/components/sheet.tsx +141 -0
  34. package/dist/assets/components/sidebar.stories.tsx +351 -0
  35. package/dist/assets/components/sidebar.tsx +760 -0
  36. package/dist/assets/components/toggle-group.stories.tsx +153 -0
  37. package/dist/assets/components/toggle-group.tsx +61 -0
  38. package/dist/assets/components/toggle.stories.tsx +77 -0
  39. package/dist/assets/components/toggle.tsx +46 -0
  40. package/dist/assets/components/tooltip.tsx +23 -90
  41. package/dist/assets/globals.css +30 -0
  42. package/dist/assets/logos/40th-anniversary/Sonance_40_Logo_CMYK_BEAM_BLUE_40_AND_BEAM_DARK.png +0 -0
  43. package/dist/assets/logos/Sonance logo dark mode.png +0 -0
  44. package/dist/assets/logos/Sonance logo light mode.png +0 -0
  45. package/dist/assets/logos/blaze/BlazeBySonance_Logo_Lockup_2C_Light_RGB_05162025.png +0 -0
  46. package/dist/assets/logos/blaze/BlazeBySonance_Logo_Lockup_3C_Dark_RGB_05162025.png +0 -0
  47. package/dist/assets/logos/blaze/BlazeBySonance_Logo_Lockup_White_RGB_05162025.png +0 -0
  48. package/dist/assets/logos/iport/IPORT_Sonance_LockUp_2C_Dark_RGB.png +0 -0
  49. package/dist/assets/logos/iport/IPORT_Sonance_LockUp_2C_Light_RGB.png +0 -0
  50. package/dist/assets/logos/james/James_Logo_Black_CMYK.png +0 -0
  51. package/dist/assets/logos/james/James_Logo_Black_RGB.png +0 -0
  52. package/dist/assets/logos/james/James_Logo_LtGray_CMYK.png +0 -0
  53. package/dist/assets/logos/james/James_Logo_LtGray_RGB.png +0 -0
  54. package/dist/assets/logos/james/James_Logo_Polished_RGB.png +0 -0
  55. package/dist/assets/logos/james/James_Logo_Reverse_CMYK.png +0 -0
  56. package/dist/assets/logos/james/James_Logo_Reverse_RGB.png +0 -0
  57. package/dist/assets/logos/james/James_Logo_White_CMYK.png +0 -0
  58. package/dist/assets/logos/life-is-better/Sonance_LifeisBetter_Dark_RGB.png +0 -0
  59. package/dist/assets/logos/life-is-better/Sonance_LifeisBetter_Light_RGB.png +0 -0
  60. package/dist/assets/logos/my-sonance/My.Sonance_Logo_2C_Dark_RGB.png +0 -0
  61. package/dist/assets/logos/my-sonance/My.Sonance_Logo_2C_Light_RGB.png +0 -0
  62. package/dist/assets/logos/my-sonance/My.Sonance_Logo_2C_Reverse_RGB.png +0 -0
  63. package/dist/assets/logos/my-sonance/My.Sonance_Logo_Black_RGB.png +0 -0
  64. package/dist/assets/logos/my-sonance/My.Sonance_Logo_Reverse_RGB.png +0 -0
  65. package/dist/assets/logos/sonance/Sonance_Logo_2C_Dark_RGB.png +0 -0
  66. package/dist/assets/logos/sonance/Sonance_Logo_2C_Light_RGB.png +0 -0
  67. package/dist/assets/logos/sonance/Sonance_Logo_2C_Reverse_RGB.png +0 -0
  68. package/dist/assets/logos/sonance/Sonance_Logo_Black_RGB.png +0 -0
  69. package/dist/assets/logos/sonance/Sonance_Logo_Grayscale_RGB.png +0 -0
  70. package/dist/assets/logos/sonance/Sonance_Logo_Reverse_RGB.png +0 -0
  71. package/dist/assets/logos/sonance-academy/SonanceAcademy_Logo_Dark_CMYK.png +0 -0
  72. package/dist/assets/logos/sonance-academy/SonanceAcademy_Logo_Light_CMYK.png +0 -0
  73. package/dist/assets/logos/sonance-iport/Sonance_IPORT_LockUp_3C_Dark_RGB.png +0 -0
  74. package/dist/assets/logos/sonance-iport/Sonance_IPORT_LockUp_3C_Light_RGB.png +0 -0
  75. package/dist/assets/logos/sonance-iport/Sonance_IPORT_LockUp_3C_Reverse_RGB.png +0 -0
  76. package/dist/assets/logos/sonance-iport/Sonance_IPORT_LockUp_Black_RGB.png +0 -0
  77. package/dist/assets/logos/sonance-iport/Sonance_IPORT_LockUp_Grayscale_RGB.png +0 -0
  78. package/dist/assets/logos/sonance-iport/Sonance_IPORT_LockUp_Reverse_RGB.png +0 -0
  79. package/dist/assets/logos/sonance-james/Sonance_James_Lockup_Dark.png +0 -0
  80. package/dist/assets/logos/sonance-james/Sonance_James_Lockup_Light.png +0 -0
  81. package/dist/assets/logos/sonance-james-iport/Sonance_James_IPORT_LockupStacked_Dark.png +0 -0
  82. package/dist/assets/logos/sonance-james-iport/Sonance_James_IPORT_LockupStacked_Light.png +0 -0
  83. package/dist/assets/logos/sonance-james-iport/Sonance_James_IPORT_Lockup_Dark.png +0 -0
  84. package/dist/assets/logos/sonance-james-iport/Sonance_James_IPORT_Lockup_Light.png +0 -0
  85. package/dist/assets/logos/trufig/TrufigLogo_Black.png +0 -0
  86. package/dist/assets/logos/trufig/TrufigLogo_Light.png +0 -0
  87. package/dist/assets/logos/trufig/TrufigWatermark_Black.png +0 -0
  88. package/dist/assets/logos/trufig/TrufigWatermark_Light.png +0 -0
  89. package/dist/index.js +416 -17
  90. package/package.json +1 -1
@@ -0,0 +1,142 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import {
3
+ AlertDialog,
4
+ AlertDialogAction,
5
+ AlertDialogCancel,
6
+ AlertDialogContent,
7
+ AlertDialogDescription,
8
+ AlertDialogFooter,
9
+ AlertDialogHeader,
10
+ AlertDialogTitle,
11
+ AlertDialogTrigger,
12
+ } from "./alert-dialog";
13
+ import { Button } from "./button";
14
+
15
+ const meta: Meta<typeof AlertDialog> = {
16
+ title: "Components/Overlays/AlertDialog",
17
+ component: AlertDialog,
18
+ parameters: {
19
+ layout: "centered",
20
+ },
21
+ tags: ["autodocs"],
22
+ };
23
+
24
+ export default meta;
25
+ type Story = StoryObj<typeof AlertDialog>;
26
+
27
+ export const Default: Story = {
28
+ render: () => (
29
+ <AlertDialog>
30
+ <AlertDialogTrigger asChild>
31
+ <Button variant="secondary">Delete Account</Button>
32
+ </AlertDialogTrigger>
33
+ <AlertDialogContent>
34
+ <AlertDialogHeader>
35
+ <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
36
+ <AlertDialogDescription>
37
+ This action cannot be undone. This will permanently delete your
38
+ account and remove your data from our servers.
39
+ </AlertDialogDescription>
40
+ </AlertDialogHeader>
41
+ <AlertDialogFooter>
42
+ <AlertDialogCancel>Cancel</AlertDialogCancel>
43
+ <AlertDialogAction>Continue</AlertDialogAction>
44
+ </AlertDialogFooter>
45
+ </AlertDialogContent>
46
+ </AlertDialog>
47
+ ),
48
+ };
49
+
50
+ export const Destructive: Story = {
51
+ render: () => (
52
+ <AlertDialog>
53
+ <AlertDialogTrigger asChild>
54
+ <Button variant="primary">Delete Project</Button>
55
+ </AlertDialogTrigger>
56
+ <AlertDialogContent>
57
+ <AlertDialogHeader>
58
+ <AlertDialogTitle>Delete Project</AlertDialogTitle>
59
+ <AlertDialogDescription>
60
+ Are you sure you want to delete this project? All associated data,
61
+ including settings, files, and history will be permanently removed.
62
+ This action cannot be undone.
63
+ </AlertDialogDescription>
64
+ </AlertDialogHeader>
65
+ <AlertDialogFooter>
66
+ <AlertDialogCancel>Cancel</AlertDialogCancel>
67
+ <AlertDialogAction className="bg-error hover:bg-error/90">
68
+ Delete Project
69
+ </AlertDialogAction>
70
+ </AlertDialogFooter>
71
+ </AlertDialogContent>
72
+ </AlertDialog>
73
+ ),
74
+ };
75
+
76
+ export const ConfirmAction: Story = {
77
+ render: () => (
78
+ <AlertDialog>
79
+ <AlertDialogTrigger asChild>
80
+ <Button>Publish Changes</Button>
81
+ </AlertDialogTrigger>
82
+ <AlertDialogContent>
83
+ <AlertDialogHeader>
84
+ <AlertDialogTitle>Publish Changes</AlertDialogTitle>
85
+ <AlertDialogDescription>
86
+ You are about to publish your changes to the live website. This will
87
+ make your updates visible to all users. Are you sure you want to
88
+ continue?
89
+ </AlertDialogDescription>
90
+ </AlertDialogHeader>
91
+ <AlertDialogFooter>
92
+ <AlertDialogCancel>Review Again</AlertDialogCancel>
93
+ <AlertDialogAction>Publish Now</AlertDialogAction>
94
+ </AlertDialogFooter>
95
+ </AlertDialogContent>
96
+ </AlertDialog>
97
+ ),
98
+ };
99
+
100
+ export const WithLongContent: Story = {
101
+ render: () => (
102
+ <AlertDialog>
103
+ <AlertDialogTrigger asChild>
104
+ <Button variant="secondary">View Terms</Button>
105
+ </AlertDialogTrigger>
106
+ <AlertDialogContent>
107
+ <AlertDialogHeader>
108
+ <AlertDialogTitle>Terms of Service</AlertDialogTitle>
109
+ <AlertDialogDescription>
110
+ By using our services, you agree to these terms. Please read them
111
+ carefully before proceeding.
112
+ </AlertDialogDescription>
113
+ </AlertDialogHeader>
114
+ <div className="max-h-[200px] overflow-y-auto text-sm text-foreground-secondary border border-border rounded-sm p-4 my-4">
115
+ <p className="mb-4">
116
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
117
+ eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
118
+ ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
119
+ aliquip ex ea commodo consequat.
120
+ </p>
121
+ <p className="mb-4">
122
+ Duis aute irure dolor in reprehenderit in voluptate velit esse
123
+ cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
124
+ cupidatat non proident, sunt in culpa qui officia deserunt mollit
125
+ anim id est laborum.
126
+ </p>
127
+ <p>
128
+ Sed ut perspiciatis unde omnis iste natus error sit voluptatem
129
+ accusantium doloremque laudantium, totam rem aperiam, eaque ipsa
130
+ quae ab illo inventore veritatis et quasi architecto beatae vitae
131
+ dicta sunt explicabo.
132
+ </p>
133
+ </div>
134
+ <AlertDialogFooter>
135
+ <AlertDialogCancel>Decline</AlertDialogCancel>
136
+ <AlertDialogAction>Accept Terms</AlertDialogAction>
137
+ </AlertDialogFooter>
138
+ </AlertDialogContent>
139
+ </AlertDialog>
140
+ ),
141
+ };
142
+
@@ -0,0 +1,142 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
5
+ import { cn } from "@/lib/utils";
6
+
7
+ const AlertDialog = AlertDialogPrimitive.Root;
8
+ const AlertDialogTrigger = AlertDialogPrimitive.Trigger;
9
+ const AlertDialogPortal = AlertDialogPrimitive.Portal;
10
+
11
+ const AlertDialogOverlay = React.forwardRef<
12
+ React.ElementRef<typeof AlertDialogPrimitive.Overlay>,
13
+ React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>
14
+ >(({ className, ...props }, ref) => (
15
+ <AlertDialogPrimitive.Overlay
16
+ className={cn(
17
+ "fixed inset-0 z-50 bg-overlay data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
18
+ className
19
+ )}
20
+ {...props}
21
+ ref={ref}
22
+ />
23
+ ));
24
+ AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;
25
+
26
+ const AlertDialogContent = React.forwardRef<
27
+ React.ElementRef<typeof AlertDialogPrimitive.Content>,
28
+ React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>
29
+ >(({ className, ...props }, ref) => (
30
+ <AlertDialogPortal>
31
+ <AlertDialogOverlay />
32
+ <AlertDialogPrimitive.Content
33
+ ref={ref}
34
+ className={cn(
35
+ "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-border bg-background p-6 shadow-lg duration-200",
36
+ "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]",
37
+ "rounded-sm",
38
+ className
39
+ )}
40
+ {...props}
41
+ />
42
+ </AlertDialogPortal>
43
+ ));
44
+ AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;
45
+
46
+ const AlertDialogHeader = ({
47
+ className,
48
+ ...props
49
+ }: React.HTMLAttributes<HTMLDivElement>) => (
50
+ <div
51
+ className={cn(
52
+ "flex flex-col space-y-2 text-center sm:text-left",
53
+ className
54
+ )}
55
+ {...props}
56
+ />
57
+ );
58
+ AlertDialogHeader.displayName = "AlertDialogHeader";
59
+
60
+ const AlertDialogFooter = ({
61
+ className,
62
+ ...props
63
+ }: React.HTMLAttributes<HTMLDivElement>) => (
64
+ <div
65
+ className={cn(
66
+ "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
67
+ className
68
+ )}
69
+ {...props}
70
+ />
71
+ );
72
+ AlertDialogFooter.displayName = "AlertDialogFooter";
73
+
74
+ const AlertDialogTitle = React.forwardRef<
75
+ React.ElementRef<typeof AlertDialogPrimitive.Title>,
76
+ React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>
77
+ >(({ className, ...props }, ref) => (
78
+ <AlertDialogPrimitive.Title
79
+ ref={ref}
80
+ className={cn("text-lg font-medium text-foreground", className)}
81
+ {...props}
82
+ />
83
+ ));
84
+ AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;
85
+
86
+ const AlertDialogDescription = React.forwardRef<
87
+ React.ElementRef<typeof AlertDialogPrimitive.Description>,
88
+ React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>
89
+ >(({ className, ...props }, ref) => (
90
+ <AlertDialogPrimitive.Description
91
+ ref={ref}
92
+ className={cn("text-sm text-foreground-secondary", className)}
93
+ {...props}
94
+ />
95
+ ));
96
+ AlertDialogDescription.displayName =
97
+ AlertDialogPrimitive.Description.displayName;
98
+
99
+ const AlertDialogAction = React.forwardRef<
100
+ React.ElementRef<typeof AlertDialogPrimitive.Action>,
101
+ React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>
102
+ >(({ className, ...props }, ref) => (
103
+ <AlertDialogPrimitive.Action
104
+ ref={ref}
105
+ className={cn(
106
+ "inline-flex h-10 items-center justify-center rounded-sm bg-primary px-4 py-2 text-sm font-medium uppercase tracking-wide text-primary-foreground transition-colors hover:opacity-90 focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
107
+ className
108
+ )}
109
+ {...props}
110
+ />
111
+ ));
112
+ AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;
113
+
114
+ const AlertDialogCancel = React.forwardRef<
115
+ React.ElementRef<typeof AlertDialogPrimitive.Cancel>,
116
+ React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>
117
+ >(({ className, ...props }, ref) => (
118
+ <AlertDialogPrimitive.Cancel
119
+ ref={ref}
120
+ className={cn(
121
+ "mt-2 inline-flex h-10 items-center justify-center rounded-sm border border-border bg-transparent px-4 py-2 text-sm font-medium uppercase tracking-wide text-foreground transition-colors hover:bg-secondary-hover focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 sm:mt-0",
122
+ className
123
+ )}
124
+ {...props}
125
+ />
126
+ ));
127
+ AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;
128
+
129
+ export {
130
+ AlertDialog,
131
+ AlertDialogPortal,
132
+ AlertDialogOverlay,
133
+ AlertDialogTrigger,
134
+ AlertDialogContent,
135
+ AlertDialogHeader,
136
+ AlertDialogFooter,
137
+ AlertDialogTitle,
138
+ AlertDialogDescription,
139
+ AlertDialogAction,
140
+ AlertDialogCancel,
141
+ };
142
+
@@ -0,0 +1,67 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { AspectRatio } from "./aspect-ratio";
3
+
4
+ const meta: Meta<typeof AspectRatio> = {
5
+ title: "Components/Data Display/AspectRatio",
6
+ component: AspectRatio,
7
+ parameters: {
8
+ layout: "centered",
9
+ },
10
+ tags: ["autodocs"],
11
+ };
12
+
13
+ export default meta;
14
+ type Story = StoryObj<typeof AspectRatio>;
15
+
16
+ export const Default: Story = {
17
+ render: () => (
18
+ <div className="w-[450px]">
19
+ <AspectRatio ratio={16 / 9} className="bg-secondary-hover rounded-sm overflow-hidden">
20
+ <img
21
+ src="https://images.unsplash.com/photo-1588345921523-c2dcdb7f1dcd?w=800&dpr=2&q=80"
22
+ alt="Photo by Drew Beamer"
23
+ className="h-full w-full object-cover"
24
+ />
25
+ </AspectRatio>
26
+ </div>
27
+ ),
28
+ };
29
+
30
+ export const Square: Story = {
31
+ render: () => (
32
+ <div className="w-[300px]">
33
+ <AspectRatio ratio={1} className="bg-secondary-hover rounded-sm overflow-hidden">
34
+ <img
35
+ src="https://images.unsplash.com/photo-1588345921523-c2dcdb7f1dcd?w=800&dpr=2&q=80"
36
+ alt="Photo by Drew Beamer"
37
+ className="h-full w-full object-cover"
38
+ />
39
+ </AspectRatio>
40
+ </div>
41
+ ),
42
+ };
43
+
44
+ export const Portrait: Story = {
45
+ render: () => (
46
+ <div className="w-[250px]">
47
+ <AspectRatio ratio={3 / 4} className="bg-secondary-hover rounded-sm overflow-hidden">
48
+ <img
49
+ src="https://images.unsplash.com/photo-1588345921523-c2dcdb7f1dcd?w=800&dpr=2&q=80"
50
+ alt="Photo by Drew Beamer"
51
+ className="h-full w-full object-cover"
52
+ />
53
+ </AspectRatio>
54
+ </div>
55
+ ),
56
+ };
57
+
58
+ export const WithPlaceholder: Story = {
59
+ render: () => (
60
+ <div className="w-[450px]">
61
+ <AspectRatio ratio={16 / 9} className="bg-secondary-hover rounded-sm flex items-center justify-center">
62
+ <span className="text-foreground-muted text-sm">16:9 Aspect Ratio</span>
63
+ </AspectRatio>
64
+ </div>
65
+ ),
66
+ };
67
+
@@ -0,0 +1,8 @@
1
+ "use client";
2
+
3
+ import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio";
4
+
5
+ const AspectRatio = AspectRatioPrimitive.Root;
6
+
7
+ export { AspectRatio };
8
+
@@ -1,4 +1,7 @@
1
- import { forwardRef } from "react";
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import * as AvatarPrimitive from "@radix-ui/react-avatar";
2
5
  import { cva, type VariantProps } from "class-variance-authority";
3
6
  import { User } from "lucide-react";
4
7
  import { cn } from "@/lib/utils";
@@ -27,15 +30,21 @@ const avatarVariants = cva(
27
30
  );
28
31
 
29
32
  interface AvatarProps
30
- extends React.HTMLAttributes<HTMLDivElement>,
33
+ extends React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>,
31
34
  VariantProps<typeof avatarVariants> {
32
35
  src?: string;
33
36
  alt?: string;
34
37
  fallback?: string;
35
38
  }
36
39
 
37
- export const Avatar = forwardRef<HTMLDivElement, AvatarProps>(
38
- ({ className, size, shape, src, alt, fallback, ...props }, ref) => {
40
+ const Avatar = React.forwardRef<
41
+ React.ElementRef<typeof AvatarPrimitive.Root>,
42
+ AvatarProps
43
+ >(({ className, size, shape, src, alt, fallback, children, ...props }, ref) => {
44
+ // Logic for legacy props (src/fallback)
45
+ const showLegacy = (src || fallback) && React.Children.count(children) === 0;
46
+
47
+ if (showLegacy) {
39
48
  const initials = fallback
40
49
  ? fallback
41
50
  .split(" ")
@@ -46,28 +55,62 @@ export const Avatar = forwardRef<HTMLDivElement, AvatarProps>(
46
55
  : null;
47
56
 
48
57
  return (
49
- <div
58
+ <AvatarPrimitive.Root
50
59
  ref={ref}
51
60
  className={cn(avatarVariants({ size, shape }), className)}
52
61
  {...props}
53
62
  >
54
- {src ? (
55
- <img
56
- src={src}
57
- alt={alt || "Avatar"}
58
- className="h-full w-full object-cover"
59
- />
60
- ) : initials ? (
61
- <span className="font-medium text-foreground-muted">{initials}</span>
62
- ) : (
63
- <User className="h-1/2 w-1/2 text-foreground-muted" />
64
- )}
65
- </div>
63
+ <AvatarImage src={src} alt={alt} />
64
+ <AvatarFallback>
65
+ {initials ? (
66
+ <span className="font-medium text-foreground-muted">{initials}</span>
67
+ ) : (
68
+ <User className="h-1/2 w-1/2 text-foreground-muted" />
69
+ )}
70
+ </AvatarFallback>
71
+ </AvatarPrimitive.Root>
66
72
  );
67
73
  }
68
- );
69
74
 
70
- Avatar.displayName = "Avatar";
75
+ // Modern composable usage
76
+ return (
77
+ <AvatarPrimitive.Root
78
+ ref={ref}
79
+ className={cn(avatarVariants({ size, shape }), className)}
80
+ {...props}
81
+ >
82
+ {children}
83
+ </AvatarPrimitive.Root>
84
+ );
85
+ });
86
+ Avatar.displayName = AvatarPrimitive.Root.displayName;
87
+
88
+ const AvatarImage = React.forwardRef<
89
+ React.ElementRef<typeof AvatarPrimitive.Image>,
90
+ React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>
91
+ >(({ className, ...props }, ref) => (
92
+ <AvatarPrimitive.Image
93
+ ref={ref}
94
+ className={cn("aspect-square h-full w-full object-cover", className)}
95
+ {...props}
96
+ />
97
+ ));
98
+ AvatarImage.displayName = AvatarPrimitive.Image.displayName;
99
+
100
+ const AvatarFallback = React.forwardRef<
101
+ React.ElementRef<typeof AvatarPrimitive.Fallback>,
102
+ React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>
103
+ >(({ className, ...props }, ref) => (
104
+ <AvatarPrimitive.Fallback
105
+ ref={ref}
106
+ className={cn(
107
+ "flex h-full w-full items-center justify-center rounded-full bg-muted",
108
+ className
109
+ )}
110
+ {...props}
111
+ />
112
+ ));
113
+ AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
71
114
 
72
115
  // Avatar Group
73
116
  interface AvatarGroupProps {
@@ -77,7 +120,7 @@ interface AvatarGroupProps {
77
120
  className?: string;
78
121
  }
79
122
 
80
- export function AvatarGroup({ children, max, size = "md", className }: AvatarGroupProps) {
123
+ function AvatarGroup({ children, max, size = "md", className }: AvatarGroupProps) {
81
124
  const avatars = Array.isArray(children) ? children : [children];
82
125
  const displayAvatars = max ? avatars.slice(0, max) : avatars;
83
126
  const excess = max ? Math.max(0, avatars.length - max) : 0;
@@ -103,3 +146,4 @@ export function AvatarGroup({ children, max, size = "md", className }: AvatarGro
103
146
  );
104
147
  }
105
148
 
149
+ export { Avatar, AvatarImage, AvatarFallback, AvatarGroup };
@@ -0,0 +1,158 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import {
3
+ Carousel,
4
+ CarouselContent,
5
+ CarouselItem,
6
+ CarouselNext,
7
+ CarouselPrevious,
8
+ } from "./carousel";
9
+ import { Card, CardContent } from "./card";
10
+
11
+ const meta: Meta<typeof Carousel> = {
12
+ title: "Components/Data Display/Carousel",
13
+ component: Carousel,
14
+ parameters: {
15
+ layout: "centered",
16
+ },
17
+ tags: ["autodocs"],
18
+ };
19
+
20
+ export default meta;
21
+ type Story = StoryObj<typeof Carousel>;
22
+
23
+ export const Default: Story = {
24
+ render: () => (
25
+ <Carousel className="w-full max-w-xs">
26
+ <CarouselContent>
27
+ {Array.from({ length: 5 }).map((_, index) => (
28
+ <CarouselItem key={index}>
29
+ <div className="p-1">
30
+ <Card>
31
+ <CardContent className="flex aspect-square items-center justify-center p-6">
32
+ <span className="text-4xl font-medium">{index + 1}</span>
33
+ </CardContent>
34
+ </Card>
35
+ </div>
36
+ </CarouselItem>
37
+ ))}
38
+ </CarouselContent>
39
+ <CarouselPrevious />
40
+ <CarouselNext />
41
+ </Carousel>
42
+ ),
43
+ };
44
+
45
+ export const Multiple: Story = {
46
+ render: () => (
47
+ <Carousel
48
+ opts={{
49
+ align: "start",
50
+ }}
51
+ className="w-full max-w-sm"
52
+ >
53
+ <CarouselContent>
54
+ {Array.from({ length: 5 }).map((_, index) => (
55
+ <CarouselItem key={index} className="md:basis-1/2 lg:basis-1/3">
56
+ <div className="p-1">
57
+ <Card>
58
+ <CardContent className="flex aspect-square items-center justify-center p-6">
59
+ <span className="text-3xl font-medium">{index + 1}</span>
60
+ </CardContent>
61
+ </Card>
62
+ </div>
63
+ </CarouselItem>
64
+ ))}
65
+ </CarouselContent>
66
+ <CarouselPrevious />
67
+ <CarouselNext />
68
+ </Carousel>
69
+ ),
70
+ };
71
+
72
+ export const Vertical: Story = {
73
+ render: () => (
74
+ <Carousel
75
+ opts={{
76
+ align: "start",
77
+ }}
78
+ orientation="vertical"
79
+ className="w-full max-w-xs"
80
+ >
81
+ <CarouselContent className="-mt-1 h-[200px]">
82
+ {Array.from({ length: 5 }).map((_, index) => (
83
+ <CarouselItem key={index} className="pt-1 md:basis-1/2">
84
+ <div className="p-1">
85
+ <Card>
86
+ <CardContent className="flex items-center justify-center p-6">
87
+ <span className="text-3xl font-medium">{index + 1}</span>
88
+ </CardContent>
89
+ </Card>
90
+ </div>
91
+ </CarouselItem>
92
+ ))}
93
+ </CarouselContent>
94
+ <CarouselPrevious />
95
+ <CarouselNext />
96
+ </Carousel>
97
+ ),
98
+ };
99
+
100
+ export const ProductGallery: Story = {
101
+ render: () => (
102
+ <Carousel className="w-full max-w-lg">
103
+ <CarouselContent>
104
+ {[
105
+ "Architectural Series",
106
+ "Landscape Series",
107
+ "Patio Series",
108
+ "Invisible Series",
109
+ ].map((product, index) => (
110
+ <CarouselItem key={index}>
111
+ <div className="p-1">
112
+ <Card>
113
+ <CardContent className="flex flex-col aspect-video items-center justify-center p-6 bg-secondary-hover">
114
+ <span className="text-foreground-muted text-sm mb-2">
115
+ Image {index + 1}
116
+ </span>
117
+ <span className="text-lg font-medium text-foreground">
118
+ {product}
119
+ </span>
120
+ </CardContent>
121
+ </Card>
122
+ </div>
123
+ </CarouselItem>
124
+ ))}
125
+ </CarouselContent>
126
+ <CarouselPrevious />
127
+ <CarouselNext />
128
+ </Carousel>
129
+ ),
130
+ };
131
+
132
+ export const Autoplay: Story = {
133
+ render: () => (
134
+ <Carousel
135
+ opts={{
136
+ loop: true,
137
+ }}
138
+ className="w-full max-w-xs"
139
+ >
140
+ <CarouselContent>
141
+ {Array.from({ length: 5 }).map((_, index) => (
142
+ <CarouselItem key={index}>
143
+ <div className="p-1">
144
+ <Card>
145
+ <CardContent className="flex aspect-square items-center justify-center p-6">
146
+ <span className="text-4xl font-medium">{index + 1}</span>
147
+ </CardContent>
148
+ </Card>
149
+ </div>
150
+ </CarouselItem>
151
+ ))}
152
+ </CarouselContent>
153
+ <CarouselPrevious />
154
+ <CarouselNext />
155
+ </Carousel>
156
+ ),
157
+ };
158
+