@auto-engineer/generate-react-client 1.33.0 → 1.35.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 (135) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/dist/starter/.storybook/main.ts +4 -1
  3. package/dist/starter/.storybook/manager.ts +4 -5
  4. package/dist/starter/codegen.ts +17 -0
  5. package/dist/starter/package.json +8 -4
  6. package/dist/starter/pnpm-lock.yaml +2643 -69
  7. package/dist/starter/scripts/build-component-db.ts +157 -0
  8. package/dist/starter/src/components/ui/Accordion.stories.tsx +2 -0
  9. package/dist/starter/src/components/ui/Accordion.tsx +4 -0
  10. package/dist/starter/src/components/ui/Alert.stories.tsx +2 -0
  11. package/dist/starter/src/components/ui/Alert.tsx +7 -0
  12. package/dist/starter/src/components/ui/AlertDialog.stories.tsx +2 -0
  13. package/dist/starter/src/components/ui/AlertDialog.tsx +15 -0
  14. package/dist/starter/src/components/ui/AspectRatio.stories.tsx +2 -0
  15. package/dist/starter/src/components/ui/AspectRatio.tsx +4 -0
  16. package/dist/starter/src/components/ui/Avatar.stories.tsx +3 -0
  17. package/dist/starter/src/components/ui/Avatar.tsx +11 -0
  18. package/dist/starter/src/components/ui/Badge.stories.tsx +5 -0
  19. package/dist/starter/src/components/ui/Badge.tsx +5 -0
  20. package/dist/starter/src/components/ui/Breadcrumb.stories.tsx +2 -0
  21. package/dist/starter/src/components/ui/Breadcrumb.tsx +12 -0
  22. package/dist/starter/src/components/ui/Button.stories.tsx +10 -0
  23. package/dist/starter/src/components/ui/Button.tsx +5 -0
  24. package/dist/starter/src/components/ui/ButtonGroup.stories.tsx +2 -0
  25. package/dist/starter/src/components/ui/ButtonGroup.tsx +6 -0
  26. package/dist/starter/src/components/ui/Calendar.stories.tsx +2 -0
  27. package/dist/starter/src/components/ui/Calendar.tsx +6 -0
  28. package/dist/starter/src/components/ui/Card.stories.tsx +2 -0
  29. package/dist/starter/src/components/ui/Card.tsx +10 -0
  30. package/dist/starter/src/components/ui/Carousel.stories.tsx +2 -0
  31. package/dist/starter/src/components/ui/Carousel.tsx +9 -0
  32. package/dist/starter/src/components/ui/Chart.stories.tsx +1 -0
  33. package/dist/starter/src/components/ui/Chart.tsx +9 -0
  34. package/dist/starter/src/components/ui/Checkbox.stories.tsx +4 -0
  35. package/dist/starter/src/components/ui/Checkbox.tsx +1 -0
  36. package/dist/starter/src/components/ui/Collapsible.stories.tsx +2 -0
  37. package/dist/starter/src/components/ui/Collapsible.tsx +3 -0
  38. package/dist/starter/src/components/ui/Combobox.stories.tsx +2 -0
  39. package/dist/starter/src/components/ui/Combobox.tsx +29 -0
  40. package/dist/starter/src/components/ui/Command.stories.tsx +2 -0
  41. package/dist/starter/src/components/ui/Command.tsx +20 -0
  42. package/dist/starter/src/components/ui/ContextMenu.stories.tsx +2 -0
  43. package/dist/starter/src/components/ui/ContextMenu.tsx +20 -0
  44. package/dist/starter/src/components/ui/DesignSystem-Colors.stories.tsx +1 -0
  45. package/dist/starter/src/components/ui/DesignSystem-Layout.stories.tsx +1 -0
  46. package/dist/starter/src/components/ui/DesignSystem-Overview.stories.tsx +1 -0
  47. package/dist/starter/src/components/ui/DesignSystem-Typography.stories.tsx +1 -0
  48. package/dist/starter/src/components/ui/Dialog.stories.tsx +2 -0
  49. package/dist/starter/src/components/ui/Dialog.tsx +18 -0
  50. package/dist/starter/src/components/ui/Direction.stories.tsx +2 -0
  51. package/dist/starter/src/components/ui/Direction.tsx +6 -0
  52. package/dist/starter/src/components/ui/Drawer.stories.tsx +2 -0
  53. package/dist/starter/src/components/ui/Drawer.tsx +18 -0
  54. package/dist/starter/src/components/ui/DropdownMenu.stories.tsx +2 -0
  55. package/dist/starter/src/components/ui/DropdownMenu.tsx +20 -0
  56. package/dist/starter/src/components/ui/Empty.stories.tsx +2 -0
  57. package/dist/starter/src/components/ui/Empty.tsx +13 -0
  58. package/dist/starter/src/components/ui/Field.stories.tsx +3 -0
  59. package/dist/starter/src/components/ui/Field.tsx +25 -0
  60. package/dist/starter/src/components/ui/Form.stories.tsx +1 -0
  61. package/dist/starter/src/components/ui/Form.tsx +15 -3
  62. package/dist/starter/src/components/ui/HoverCard.stories.tsx +2 -0
  63. package/dist/starter/src/components/ui/HoverCard.tsx +3 -0
  64. package/dist/starter/src/components/ui/Input.stories.tsx +4 -0
  65. package/dist/starter/src/components/ui/Input.tsx +1 -0
  66. package/dist/starter/src/components/ui/InputGroup.stories.tsx +3 -0
  67. package/dist/starter/src/components/ui/InputGroup.tsx +6 -0
  68. package/dist/starter/src/components/ui/InputOTP.stories.tsx +2 -0
  69. package/dist/starter/src/components/ui/InputOTP.tsx +4 -0
  70. package/dist/starter/src/components/ui/Item.stories.tsx +3 -0
  71. package/dist/starter/src/components/ui/Item.tsx +10 -0
  72. package/dist/starter/src/components/ui/Kbd.stories.tsx +5 -0
  73. package/dist/starter/src/components/ui/Kbd.tsx +4 -0
  74. package/dist/starter/src/components/ui/Label.stories.tsx +5 -0
  75. package/dist/starter/src/components/ui/Label.tsx +4 -0
  76. package/dist/starter/src/components/ui/Menubar.stories.tsx +2 -0
  77. package/dist/starter/src/components/ui/Menubar.tsx +15 -0
  78. package/dist/starter/src/components/ui/NativeSelect.stories.tsx +3 -0
  79. package/dist/starter/src/components/ui/NativeSelect.tsx +6 -0
  80. package/dist/starter/src/components/ui/NavigationMenu.stories.tsx +2 -0
  81. package/dist/starter/src/components/ui/NavigationMenu.tsx +10 -0
  82. package/dist/starter/src/components/ui/Pagination.stories.tsx +2 -0
  83. package/dist/starter/src/components/ui/Pagination.tsx +8 -0
  84. package/dist/starter/src/components/ui/Popover.stories.tsx +2 -0
  85. package/dist/starter/src/components/ui/Popover.tsx +5 -0
  86. package/dist/starter/src/components/ui/Progress.stories.tsx +4 -0
  87. package/dist/starter/src/components/ui/Progress.tsx +1 -0
  88. package/dist/starter/src/components/ui/RadioGroup.stories.tsx +2 -0
  89. package/dist/starter/src/components/ui/RadioGroup.tsx +5 -0
  90. package/dist/starter/src/components/ui/Resizable.stories.tsx +3 -0
  91. package/dist/starter/src/components/ui/Resizable.tsx +7 -0
  92. package/dist/starter/src/components/ui/ScrollArea.stories.tsx +2 -0
  93. package/dist/starter/src/components/ui/ScrollArea.tsx +5 -0
  94. package/dist/starter/src/components/ui/Select.stories.tsx +2 -0
  95. package/dist/starter/src/components/ui/Select.tsx +9 -0
  96. package/dist/starter/src/components/ui/Separator.stories.tsx +2 -0
  97. package/dist/starter/src/components/ui/Separator.tsx +1 -0
  98. package/dist/starter/src/components/ui/Sheet.stories.tsx +2 -0
  99. package/dist/starter/src/components/ui/Sheet.tsx +8 -0
  100. package/dist/starter/src/components/ui/Sidebar.stories.tsx +2 -0
  101. package/dist/starter/src/components/ui/Sidebar.tsx +20 -0
  102. package/dist/starter/src/components/ui/Skeleton.stories.tsx +2 -0
  103. package/dist/starter/src/components/ui/Skeleton.tsx +4 -0
  104. package/dist/starter/src/components/ui/Slider.stories.tsx +3 -0
  105. package/dist/starter/src/components/ui/Slider.tsx +1 -0
  106. package/dist/starter/src/components/ui/Sonner.stories.tsx +1 -0
  107. package/dist/starter/src/components/ui/Sonner.tsx +4 -0
  108. package/dist/starter/src/components/ui/Spinner.stories.tsx +3 -0
  109. package/dist/starter/src/components/ui/Spinner.tsx +4 -0
  110. package/dist/starter/src/components/ui/Switch.stories.tsx +4 -0
  111. package/dist/starter/src/components/ui/Switch.tsx +2 -0
  112. package/dist/starter/src/components/ui/Table.stories.tsx +2 -0
  113. package/dist/starter/src/components/ui/Table.tsx +11 -0
  114. package/dist/starter/src/components/ui/Tabs.stories.tsx +2 -0
  115. package/dist/starter/src/components/ui/Tabs.tsx +6 -0
  116. package/dist/starter/src/components/ui/Textarea.stories.tsx +3 -0
  117. package/dist/starter/src/components/ui/Textarea.tsx +4 -0
  118. package/dist/starter/src/components/ui/Toast.stories.tsx +4 -0
  119. package/dist/starter/src/components/ui/Toast.tsx +9 -0
  120. package/dist/starter/src/components/ui/Toaster.tsx +4 -0
  121. package/dist/starter/src/components/ui/Toggle.stories.tsx +4 -0
  122. package/dist/starter/src/components/ui/Toggle.tsx +1 -0
  123. package/dist/starter/src/components/ui/ToggleGroup.stories.tsx +3 -0
  124. package/dist/starter/src/components/ui/ToggleGroup.tsx +3 -0
  125. package/dist/starter/src/components/ui/Tooltip.stories.tsx +2 -0
  126. package/dist/starter/src/components/ui/Tooltip.tsx +6 -0
  127. package/dist/starter/src/gql/execute.ts +11 -0
  128. package/dist/starter/src/gql/fragment-masking.ts +83 -0
  129. package/dist/starter/src/gql/gql.ts +9 -0
  130. package/dist/starter/src/gql/graphql.ts +182 -0
  131. package/dist/starter/src/gql/index.ts +2 -0
  132. package/dist/starter/src/graphql/mutations.ts +0 -0
  133. package/dist/starter/src/graphql/queries.ts +0 -0
  134. package/dist/starter/tsconfig.json +6 -0
  135. package/package.json +2 -2
@@ -0,0 +1,157 @@
1
+ import { writeFileSync, mkdirSync } from "node:fs";
2
+ import { dirname, resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { parseArgs } from "node:util";
5
+
6
+ const __dirname = dirname(fileURLToPath(import.meta.url));
7
+ const OUTPUT_DIR = resolve(__dirname, "../../.context");
8
+ const OUTPUT_FILE = resolve(OUTPUT_DIR, "components-db.json");
9
+
10
+ const { values } = parseArgs({
11
+ options: { port: { type: "string", default: "6006" } },
12
+ });
13
+ const PORT = Number(values.port);
14
+
15
+ interface IndexEntry {
16
+ id: string;
17
+ name: string;
18
+ title: string;
19
+ type: string;
20
+ subtype?: string;
21
+ exportName: string;
22
+ tags: string[];
23
+ componentPath?: string;
24
+ importPath?: string;
25
+ storiesImports?: string[];
26
+ }
27
+
28
+ interface ComponentStory {
29
+ name: string;
30
+ snippet: string;
31
+ description: string;
32
+ }
33
+
34
+ interface ComponentEntry {
35
+ id: string;
36
+ name: string;
37
+ path: string;
38
+ stories?: ComponentStory[];
39
+ import: string;
40
+ jsDocTags: Record<string, unknown>;
41
+ description: string;
42
+ reactDocgen: Record<string, unknown>;
43
+ }
44
+
45
+ interface ComponentsManifest {
46
+ v: number;
47
+ components: Record<string, ComponentEntry>;
48
+ }
49
+
50
+ interface IndexJson {
51
+ entries: Record<string, IndexEntry>;
52
+ }
53
+
54
+ async function checkStorybookRunning(port: number): Promise<void> {
55
+ const delays = [5000, 10000, 20000];
56
+ for (let attempt = 0; attempt <= delays.length; attempt++) {
57
+ try {
58
+ const response = await fetch(`http://localhost:${port}`);
59
+ if (!response.ok)
60
+ throw new Error("Storybook responded with non-OK status");
61
+ return;
62
+ } catch {
63
+ if (attempt === delays.length) {
64
+ throw new Error(
65
+ `Storybook is not running on port ${port}. Start it with \`pnpm storybook\` in the client directory.`,
66
+ );
67
+ }
68
+ console.log(
69
+ `Waiting for Storybook on port ${port}... (attempt ${attempt + 1}/3, retrying in ${delays[attempt] / 1000}s)`,
70
+ );
71
+ await new Promise((r) => setTimeout(r, delays[attempt]));
72
+ }
73
+ }
74
+ }
75
+
76
+ async function fetchWithRetry<T>(url: string, maxAttempts = 3): Promise<T> {
77
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
78
+ try {
79
+ const res = await fetch(url);
80
+ if (!res.ok)
81
+ throw new Error(`${url} responded with status ${res.status}`);
82
+ return await res.json();
83
+ } catch (err) {
84
+ if (attempt === maxAttempts) throw err;
85
+ await new Promise((r) => setTimeout(r, 1000));
86
+ }
87
+ }
88
+ throw new Error("unreachable");
89
+ }
90
+
91
+ function merge(componentsJson: ComponentsManifest, indexJson: IndexJson) {
92
+ const entries = indexJson.entries ?? {};
93
+
94
+ const storysByComponent = new Map<string, IndexEntry[]>();
95
+ const docsByComponent = new Map<string, IndexEntry>();
96
+
97
+ for (const entry of Object.values(entries)) {
98
+ const componentId = entry.id.replace(/--.*$/, "");
99
+
100
+ if (entry.type === "docs") {
101
+ docsByComponent.set(componentId, entry);
102
+ } else {
103
+ if (!storysByComponent.has(componentId))
104
+ storysByComponent.set(componentId, []);
105
+ storysByComponent.get(componentId)!.push(entry);
106
+ }
107
+ }
108
+
109
+ const components = Object.values(componentsJson.components);
110
+ return components.map((component) => {
111
+ const indexStories = storysByComponent.get(component.id) ?? [];
112
+ const docsEntry = docsByComponent.get(component.id);
113
+
114
+ const firstStory = indexStories[0];
115
+ const merged: Record<string, unknown> = { ...component };
116
+
117
+ if (firstStory) {
118
+ merged.componentPath = firstStory.componentPath;
119
+ merged.title = firstStory.title;
120
+ merged.tags = firstStory.tags;
121
+ }
122
+
123
+ if (component.stories) {
124
+ merged.stories = component.stories.map((story) => {
125
+ const match = indexStories.find((s) => s.name === story.name);
126
+ if (!match) return story;
127
+ return {
128
+ ...story,
129
+ id: match.id,
130
+ exportName: match.exportName,
131
+ type: match.type,
132
+ subtype: match.subtype,
133
+ };
134
+ });
135
+ }
136
+
137
+ if (docsEntry) {
138
+ merged.docs = docsEntry;
139
+ }
140
+
141
+ return merged;
142
+ });
143
+ }
144
+
145
+ await checkStorybookRunning(PORT);
146
+
147
+ const [componentsJson, indexJson] = await Promise.all([
148
+ fetchWithRetry<ComponentsManifest>(`http://localhost:${PORT}/manifests/components.json`),
149
+ fetchWithRetry<IndexJson>(`http://localhost:${PORT}/index.json`),
150
+ ]);
151
+
152
+ const merged = merge(componentsJson, indexJson);
153
+
154
+ mkdirSync(OUTPUT_DIR, { recursive: true });
155
+ writeFileSync(OUTPUT_FILE, JSON.stringify(merged, null, 2) + "\n");
156
+
157
+ console.log(`Wrote ${merged.length} components to ${OUTPUT_FILE}`);
@@ -8,6 +8,7 @@ const meta: Meta<typeof Accordion> = {
8
8
  export default meta;
9
9
  type Story = StoryObj<typeof Accordion>;
10
10
 
11
+ /** Shows the accordion in single-select mode where only one item can be open at a time, with collapsible behavior. */
11
12
  export const Default: Story = {
12
13
  render: () => (
13
14
  <Accordion type="single" collapsible className="w-full max-w-md">
@@ -27,6 +28,7 @@ export const Default: Story = {
27
28
  ),
28
29
  };
29
30
 
31
+ /** Demonstrates multiple panels open simultaneously using `type="multiple"`. */
30
32
  export const Multiple: Story = {
31
33
  render: () => (
32
34
  <Accordion type="multiple" className="w-full max-w-md">
@@ -4,10 +4,12 @@ import { Accordion as AccordionPrimitive } from 'radix-ui';
4
4
 
5
5
  import { cn } from '@/lib/utils';
6
6
 
7
+ /** Expandable content sections. Use `type="single"` for one open at a time, `type="multiple"` for many. */
7
8
  function Accordion({ ...props }: React.ComponentProps<typeof AccordionPrimitive.Root>) {
8
9
  return <AccordionPrimitive.Root data-slot="accordion" {...props} />;
9
10
  }
10
11
 
12
+ /** A single collapsible section within an Accordion, identified by a unique `value` prop. */
11
13
  function AccordionItem({ className, ...props }: React.ComponentProps<typeof AccordionPrimitive.Item>) {
12
14
  return (
13
15
  <AccordionPrimitive.Item
@@ -18,6 +20,7 @@ function AccordionItem({ className, ...props }: React.ComponentProps<typeof Acco
18
20
  );
19
21
  }
20
22
 
23
+ /** The clickable heading that toggles the visibility of its associated AccordionContent. Renders a chevron icon that rotates when open. */
21
24
  function AccordionTrigger({ className, children, ...props }: React.ComponentProps<typeof AccordionPrimitive.Trigger>) {
22
25
  return (
23
26
  <AccordionPrimitive.Header className="flex">
@@ -36,6 +39,7 @@ function AccordionTrigger({ className, children, ...props }: React.ComponentProp
36
39
  );
37
40
  }
38
41
 
42
+ /** The collapsible body of an AccordionItem, animated with slide-up/slide-down transitions. */
39
43
  function AccordionContent({ className, children, ...props }: React.ComponentProps<typeof AccordionPrimitive.Content>) {
40
44
  return (
41
45
  <AccordionPrimitive.Content
@@ -8,6 +8,7 @@ const meta: Meta<typeof Alert> = {
8
8
  export default meta;
9
9
  type Story = StoryObj<typeof Alert>;
10
10
 
11
+ /** Shows the default informational alert variant with a title and description. */
11
12
  export const Default: Story = {
12
13
  render: () => (
13
14
  <Alert>
@@ -17,6 +18,7 @@ export const Default: Story = {
17
18
  ),
18
19
  };
19
20
 
21
+ /** Shows the destructive variant used for error or warning messages. */
20
22
  export const Destructive: Story = {
21
23
  render: () => (
22
24
  <Alert variant="destructive">
@@ -19,10 +19,16 @@ const alertVariants = cva(
19
19
  },
20
20
  );
21
21
 
22
+ /**
23
+ * Displays a callout message to attract user attention.
24
+ * Supports `default` and `destructive` variants. Compose with AlertTitle and AlertDescription.
25
+ * An optional leading SVG icon is automatically laid out in a grid column.
26
+ */
22
27
  function Alert({ className, variant, ...props }: React.ComponentProps<'div'> & VariantProps<typeof alertVariants>) {
23
28
  return <div data-slot="alert" role="alert" className={cn(alertVariants({ variant }), className)} {...props} />;
24
29
  }
25
30
 
31
+ /** The heading of an Alert, rendered as a single-line truncated title. */
26
32
  function AlertTitle({ className, ...props }: React.ComponentProps<'div'>) {
27
33
  return (
28
34
  <div
@@ -33,6 +39,7 @@ function AlertTitle({ className, ...props }: React.ComponentProps<'div'>) {
33
39
  );
34
40
  }
35
41
 
42
+ /** The body text of an Alert, styled in muted foreground for secondary emphasis. */
36
43
  function AlertDescription({ className, ...props }: React.ComponentProps<'div'>) {
37
44
  return (
38
45
  <div
@@ -19,6 +19,7 @@ const meta: Meta<typeof AlertDialog> = {
19
19
  export default meta;
20
20
  type Story = StoryObj<typeof AlertDialog>;
21
21
 
22
+ /** Shows a standard confirmation dialog with cancel and continue actions. */
22
23
  export const Default: Story = {
23
24
  render: () => (
24
25
  <AlertDialog>
@@ -42,6 +43,7 @@ export const Default: Story = {
42
43
  ),
43
44
  };
44
45
 
46
+ /** Demonstrates a destructive confirmation using the destructive button variant for dangerous actions like deletion. */
45
47
  export const DestructiveAction: Story = {
46
48
  render: () => (
47
49
  <AlertDialog>
@@ -6,18 +6,22 @@ import { AlertDialog as AlertDialogPrimitive } from 'radix-ui';
6
6
  import { cn } from '@/lib/utils';
7
7
  import { Button } from '@/components/ui/Button';
8
8
 
9
+ /** A confirmation modal requiring explicit user action. Unlike Dialog, cannot be dismissed by clicking outside. */
9
10
  function AlertDialog({ ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Root>) {
10
11
  return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />;
11
12
  }
12
13
 
14
+ /** The element that opens the AlertDialog when clicked. */
13
15
  function AlertDialogTrigger({ ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>) {
14
16
  return <AlertDialogPrimitive.Trigger data-slot="alert-dialog-trigger" {...props} />;
15
17
  }
16
18
 
19
+ /** Portals the dialog content into document.body to avoid z-index and overflow issues. */
17
20
  function AlertDialogPortal({ ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Portal>) {
18
21
  return <AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} />;
19
22
  }
20
23
 
24
+ /** The semi-transparent backdrop rendered behind the dialog content. */
21
25
  function AlertDialogOverlay({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Overlay>) {
22
26
  return (
23
27
  <AlertDialogPrimitive.Overlay
@@ -31,6 +35,10 @@ function AlertDialogOverlay({ className, ...props }: React.ComponentProps<typeof
31
35
  );
32
36
  }
33
37
 
38
+ /**
39
+ * The centered modal panel containing the dialog's content. Automatically renders overlay and portal.
40
+ * @param size - Controls the max-width: `"default"` for standard dialogs, `"sm"` for compact confirmations.
41
+ */
34
42
  function AlertDialogContent({
35
43
  className,
36
44
  size = 'default',
@@ -54,6 +62,7 @@ function AlertDialogContent({
54
62
  );
55
63
  }
56
64
 
65
+ /** Layout container for the dialog's title, description, and optional media icon. */
57
66
  function AlertDialogHeader({ className, ...props }: React.ComponentProps<'div'>) {
58
67
  return (
59
68
  <div
@@ -67,6 +76,7 @@ function AlertDialogHeader({ className, ...props }: React.ComponentProps<'div'>)
67
76
  );
68
77
  }
69
78
 
79
+ /** Layout container for the dialog's action buttons, typically Cancel and a primary action. */
70
80
  function AlertDialogFooter({ className, ...props }: React.ComponentProps<'div'>) {
71
81
  return (
72
82
  <div
@@ -80,6 +90,7 @@ function AlertDialogFooter({ className, ...props }: React.ComponentProps<'div'>)
80
90
  );
81
91
  }
82
92
 
93
+ /** The accessible title of the dialog, announced by screen readers when the dialog opens. */
83
94
  function AlertDialogTitle({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {
84
95
  return (
85
96
  <AlertDialogPrimitive.Title
@@ -93,6 +104,7 @@ function AlertDialogTitle({ className, ...props }: React.ComponentProps<typeof A
93
104
  );
94
105
  }
95
106
 
107
+ /** The accessible description providing additional context about the dialog's purpose. */
96
108
  function AlertDialogDescription({
97
109
  className,
98
110
  ...props
@@ -106,6 +118,7 @@ function AlertDialogDescription({
106
118
  );
107
119
  }
108
120
 
121
+ /** An optional icon or image slot displayed alongside the title in the dialog header. */
109
122
  function AlertDialogMedia({ className, ...props }: React.ComponentProps<'div'>) {
110
123
  return (
111
124
  <div
@@ -119,6 +132,7 @@ function AlertDialogMedia({ className, ...props }: React.ComponentProps<'div'>)
119
132
  );
120
133
  }
121
134
 
135
+ /** The primary confirmation button that closes the dialog and triggers the intended action. Renders as a Button. */
122
136
  function AlertDialogAction({
123
137
  className,
124
138
  variant = 'default',
@@ -133,6 +147,7 @@ function AlertDialogAction({
133
147
  );
134
148
  }
135
149
 
150
+ /** The cancel button that dismisses the dialog without taking action. Renders as an outline Button by default. */
136
151
  function AlertDialogCancel({
137
152
  className,
138
153
  variant = 'outline',
@@ -8,6 +8,7 @@ const meta: Meta<typeof AspectRatio> = {
8
8
  export default meta;
9
9
  type Story = StoryObj<typeof AspectRatio>;
10
10
 
11
+ /** Shows a 16:9 widescreen aspect ratio container. */
11
12
  export const Default: Story = {
12
13
  render: () => (
13
14
  <div className="w-[450px]">
@@ -20,6 +21,7 @@ export const Default: Story = {
20
21
  ),
21
22
  };
22
23
 
24
+ /** Shows a 1:1 square aspect ratio container. */
23
25
  export const Square: Story = {
24
26
  render: () => (
25
27
  <div className="w-[300px]">
@@ -2,6 +2,10 @@
2
2
 
3
3
  import { AspectRatio as AspectRatioPrimitive } from 'radix-ui';
4
4
 
5
+ /**
6
+ * Constrains its child element to a specified width-to-height ratio (e.g., 16/9, 1/1).
7
+ * Useful for responsive images, videos, and media containers that must maintain proportions.
8
+ */
5
9
  function AspectRatio({ ...props }: React.ComponentProps<typeof AspectRatioPrimitive.Root>) {
6
10
  return <AspectRatioPrimitive.Root data-slot="aspect-ratio" {...props} />;
7
11
  }
@@ -8,6 +8,7 @@ const meta: Meta<typeof Avatar> = {
8
8
  export default meta;
9
9
  type Story = StoryObj<typeof Avatar>;
10
10
 
11
+ /** Shows an avatar with a loaded profile image and fallback initials. */
11
12
  export const WithImage: Story = {
12
13
  render: () => (
13
14
  <Avatar>
@@ -17,6 +18,7 @@ export const WithImage: Story = {
17
18
  ),
18
19
  };
19
20
 
21
+ /** Shows an avatar displaying only fallback initials without an image. */
20
22
  export const FallbackOnly: Story = {
21
23
  render: () => (
22
24
  <Avatar>
@@ -25,6 +27,7 @@ export const FallbackOnly: Story = {
25
27
  ),
26
28
  };
27
29
 
30
+ /** Demonstrates the three available avatar sizes: sm, default, and lg. */
28
31
  export const Sizes: Story = {
29
32
  render: () => (
30
33
  <div className="flex items-center gap-4">
@@ -3,8 +3,14 @@ import { Avatar as AvatarPrimitive } from 'radix-ui';
3
3
 
4
4
  import { cn } from '@/lib/utils';
5
5
 
6
+ /**
7
+ * Displays a user profile image with a fallback for missing photos.
8
+ * Compose with AvatarImage, AvatarFallback, and optionally AvatarBadge.
9
+ * Use AvatarGroup to render overlapping stacks of avatars.
10
+ */
6
11
  function Avatar({
7
12
  className,
13
+ /** Controls the avatar dimensions: `"sm"` (24px), `"default"` (32px), or `"lg"` (40px). */
8
14
  size = 'default',
9
15
  ...props
10
16
  }: React.ComponentProps<typeof AvatarPrimitive.Root> & {
@@ -23,12 +29,14 @@ function Avatar({
23
29
  );
24
30
  }
25
31
 
32
+ /** The profile image rendered inside an Avatar. Automatically hidden if the image fails to load. */
26
33
  function AvatarImage({ className, ...props }: React.ComponentProps<typeof AvatarPrimitive.Image>) {
27
34
  return (
28
35
  <AvatarPrimitive.Image data-slot="avatar-image" className={cn('aspect-square size-full', className)} {...props} />
29
36
  );
30
37
  }
31
38
 
39
+ /** Fallback content shown when AvatarImage is loading or unavailable, typically initials or an icon. */
32
40
  function AvatarFallback({ className, ...props }: React.ComponentProps<typeof AvatarPrimitive.Fallback>) {
33
41
  return (
34
42
  <AvatarPrimitive.Fallback
@@ -42,6 +50,7 @@ function AvatarFallback({ className, ...props }: React.ComponentProps<typeof Ava
42
50
  );
43
51
  }
44
52
 
53
+ /** A small status indicator (e.g., online/offline dot) positioned at the bottom-right corner of an Avatar. */
45
54
  function AvatarBadge({ className, ...props }: React.ComponentProps<'span'>) {
46
55
  return (
47
56
  <span
@@ -58,6 +67,7 @@ function AvatarBadge({ className, ...props }: React.ComponentProps<'span'>) {
58
67
  );
59
68
  }
60
69
 
70
+ /** Renders multiple Avatars in an overlapping horizontal stack with ring borders. */
61
71
  function AvatarGroup({ className, ...props }: React.ComponentProps<'div'>) {
62
72
  return (
63
73
  <div
@@ -71,6 +81,7 @@ function AvatarGroup({ className, ...props }: React.ComponentProps<'div'>) {
71
81
  );
72
82
  }
73
83
 
84
+ /** Displays a count of additional avatars not shown in the group (e.g., "+5"). */
74
85
  function AvatarGroupCount({ className, ...props }: React.ComponentProps<'div'>) {
75
86
  return (
76
87
  <div
@@ -8,22 +8,27 @@ const meta: Meta<typeof Badge> = {
8
8
  export default meta;
9
9
  type Story = StoryObj<typeof Badge>;
10
10
 
11
+ /** Shows the primary filled badge variant. */
11
12
  export const Default: Story = {
12
13
  render: () => <Badge>Default</Badge>,
13
14
  };
14
15
 
16
+ /** Shows the secondary badge variant with muted background. */
15
17
  export const Secondary: Story = {
16
18
  render: () => <Badge variant="secondary">Secondary</Badge>,
17
19
  };
18
20
 
21
+ /** Shows the destructive badge variant for error or warning indicators. */
19
22
  export const Destructive: Story = {
20
23
  render: () => <Badge variant="destructive">Destructive</Badge>,
21
24
  };
22
25
 
26
+ /** Shows the outline badge variant with a visible border and no fill. */
23
27
  export const Outline: Story = {
24
28
  render: () => <Badge variant="outline">Outline</Badge>,
25
29
  };
26
30
 
31
+ /** Displays all badge variants side by side for visual comparison. */
27
32
  export const AllVariants: Story = {
28
33
  render: () => (
29
34
  <div className="flex flex-wrap gap-2">
@@ -24,9 +24,14 @@ const badgeVariants = cva(
24
24
  },
25
25
  );
26
26
 
27
+ /**
28
+ * A small label used to highlight status, category, or count.
29
+ * Supports multiple visual variants: default, secondary, destructive, outline, ghost, and link.
30
+ */
27
31
  function Badge({
28
32
  className,
29
33
  variant = 'default',
34
+ /** Merges props onto the child element instead of rendering a span. Use with custom wrapper elements. */
30
35
  asChild = false,
31
36
  ...props
32
37
  }: React.ComponentProps<'span'> & VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
@@ -15,6 +15,7 @@ const meta: Meta<typeof Breadcrumb> = {
15
15
  export default meta;
16
16
  type Story = StoryObj<typeof Breadcrumb>;
17
17
 
18
+ /** Shows a three-level breadcrumb trail with home, category, and current page. */
18
19
  export const Default: Story = {
19
20
  render: () => (
20
21
  <Breadcrumb>
@@ -35,6 +36,7 @@ export const Default: Story = {
35
36
  ),
36
37
  };
37
38
 
39
+ /** Shows a minimal two-level breadcrumb with just a parent link and current page. */
38
40
  export const TwoLevels: Story = {
39
41
  render: () => (
40
42
  <Breadcrumb>
@@ -4,10 +4,16 @@ import { Slot } from 'radix-ui';
4
4
 
5
5
  import { cn } from '@/lib/utils';
6
6
 
7
+ /**
8
+ * A navigation aid that shows the user's current location within a site hierarchy.
9
+ * Compose with BreadcrumbList, BreadcrumbItem, BreadcrumbLink, BreadcrumbPage, and BreadcrumbSeparator.
10
+ * Renders as a `<nav>` with `aria-label="breadcrumb"` for accessibility.
11
+ */
7
12
  function Breadcrumb({ ...props }: React.ComponentProps<'nav'>) {
8
13
  return <nav aria-label="breadcrumb" data-slot="breadcrumb" {...props} />;
9
14
  }
10
15
 
16
+ /** The ordered list container for breadcrumb items, handling wrapping and spacing. */
11
17
  function BreadcrumbList({ className, ...props }: React.ComponentProps<'ol'>) {
12
18
  return (
13
19
  <ol
@@ -21,11 +27,14 @@ function BreadcrumbList({ className, ...props }: React.ComponentProps<'ol'>) {
21
27
  );
22
28
  }
23
29
 
30
+ /** A single step in the breadcrumb trail, wrapping a link or the current page label. */
24
31
  function BreadcrumbItem({ className, ...props }: React.ComponentProps<'li'>) {
25
32
  return <li data-slot="breadcrumb-item" className={cn('inline-flex items-center gap-1.5', className)} {...props} />;
26
33
  }
27
34
 
35
+ /** A navigable link within a breadcrumb item. Use `asChild` to render a router Link component instead of an anchor. */
28
36
  function BreadcrumbLink({
37
+ /** Merges props onto the child element instead of rendering an anchor tag. */
29
38
  asChild,
30
39
  className,
31
40
  ...props
@@ -39,6 +48,7 @@ function BreadcrumbLink({
39
48
  );
40
49
  }
41
50
 
51
+ /** The current page label in the breadcrumb trail, marked with `aria-current="page"` and rendered as non-interactive text. */
42
52
  function BreadcrumbPage({ className, ...props }: React.ComponentProps<'span'>) {
43
53
  return (
44
54
  <span
@@ -52,6 +62,7 @@ function BreadcrumbPage({ className, ...props }: React.ComponentProps<'span'>) {
52
62
  );
53
63
  }
54
64
 
65
+ /** A visual divider between breadcrumb items, defaulting to a chevron-right icon. Pass children to customize the separator. */
55
66
  function BreadcrumbSeparator({ children, className, ...props }: React.ComponentProps<'li'>) {
56
67
  return (
57
68
  <li
@@ -66,6 +77,7 @@ function BreadcrumbSeparator({ children, className, ...props }: React.ComponentP
66
77
  );
67
78
  }
68
79
 
80
+ /** A "..." indicator used to collapse intermediate breadcrumb levels when the trail is too long. */
69
81
  function BreadcrumbEllipsis({ className, ...props }: React.ComponentProps<'span'>) {
70
82
  return (
71
83
  <span
@@ -8,12 +8,14 @@ const meta: Meta<typeof Button> = {
8
8
  export default meta;
9
9
  type Story = StoryObj<typeof Button>;
10
10
 
11
+ /** Shows the primary filled button variant. */
11
12
  export const Default: Story = {
12
13
  args: {
13
14
  children: 'Button',
14
15
  },
15
16
  };
16
17
 
18
+ /** Shows the secondary button variant with muted styling. */
17
19
  export const Secondary: Story = {
18
20
  args: {
19
21
  variant: 'secondary',
@@ -21,6 +23,7 @@ export const Secondary: Story = {
21
23
  },
22
24
  };
23
25
 
26
+ /** Shows the destructive button variant for dangerous actions like delete. */
24
27
  export const Destructive: Story = {
25
28
  args: {
26
29
  variant: 'destructive',
@@ -28,6 +31,7 @@ export const Destructive: Story = {
28
31
  },
29
32
  };
30
33
 
34
+ /** Shows the outline button variant with a border and transparent background. */
31
35
  export const Outline: Story = {
32
36
  args: {
33
37
  variant: 'outline',
@@ -35,6 +39,7 @@ export const Outline: Story = {
35
39
  },
36
40
  };
37
41
 
42
+ /** Shows the ghost button variant with no background until hovered. */
38
43
  export const Ghost: Story = {
39
44
  args: {
40
45
  variant: 'ghost',
@@ -42,6 +47,7 @@ export const Ghost: Story = {
42
47
  },
43
48
  };
44
49
 
50
+ /** Shows the link button variant styled as an inline text link with underline on hover. */
45
51
  export const Link: Story = {
46
52
  args: {
47
53
  variant: 'link',
@@ -49,6 +55,7 @@ export const Link: Story = {
49
55
  },
50
56
  };
51
57
 
58
+ /** Shows a compact small-sized button. */
52
59
  export const Small: Story = {
53
60
  args: {
54
61
  size: 'sm',
@@ -56,6 +63,7 @@ export const Small: Story = {
56
63
  },
57
64
  };
58
65
 
66
+ /** Shows a larger button with more padding. */
59
67
  export const Large: Story = {
60
68
  args: {
61
69
  size: 'lg',
@@ -63,6 +71,7 @@ export const Large: Story = {
63
71
  },
64
72
  };
65
73
 
74
+ /** Shows an icon-only square button. */
66
75
  export const Icon: Story = {
67
76
  args: {
68
77
  size: 'icon',
@@ -70,6 +79,7 @@ export const Icon: Story = {
70
79
  },
71
80
  };
72
81
 
82
+ /** Displays all button variants and sizes side by side for visual comparison. */
73
83
  export const AllVariants: Story = {
74
84
  render: () => (
75
85
  <div className="flex flex-col gap-4">
@@ -36,10 +36,15 @@ const buttonVariants = cva(
36
36
  },
37
37
  );
38
38
 
39
+ /**
40
+ * A clickable element that triggers an action or navigation.
41
+ * Supports six visual variants (default, secondary, destructive, outline, ghost, link) and multiple sizes including icon-only modes.
42
+ */
39
43
  function Button({
40
44
  className,
41
45
  variant = 'default',
42
46
  size = 'default',
47
+ /** Merges props onto the child element instead of rendering a button. Use with Link or anchor components for navigation. */
43
48
  asChild = false,
44
49
  ...props
45
50
  }: React.ComponentProps<'button'> &
@@ -9,6 +9,7 @@ const meta: Meta<typeof ButtonGroup> = {
9
9
  export default meta;
10
10
  type Story = StoryObj<typeof ButtonGroup>;
11
11
 
12
+ /** Shows a horizontal group of three outline buttons with connected borders. */
12
13
  export const Default: Story = {
13
14
  render: () => (
14
15
  <ButtonGroup>
@@ -19,6 +20,7 @@ export const Default: Story = {
19
20
  ),
20
21
  };
21
22
 
23
+ /** Shows a vertically stacked button group. */
22
24
  export const Vertical: Story = {
23
25
  render: () => (
24
26
  <ButtonGroup orientation="vertical">