@authdog/react-elements 0.0.40 → 0.0.43

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 (72) hide show
  1. package/.eslintrc.js +1 -1
  2. package/.storybook/main.ts +21 -0
  3. package/.storybook/preview.ts +17 -0
  4. package/.storybook/vitest.setup.ts +7 -0
  5. package/.turbo/turbo-build.log +48 -44
  6. package/CHANGELOG.md +19 -0
  7. package/dist/components/ui/alert.js.map +1 -1
  8. package/dist/components/ui/alert.mjs.map +1 -1
  9. package/dist/components/ui/avatar.js.map +1 -1
  10. package/dist/components/ui/avatar.mjs.map +1 -1
  11. package/dist/components/ui/badge.js.map +1 -1
  12. package/dist/components/ui/badge.mjs.map +1 -1
  13. package/dist/components/ui/card.js.map +1 -1
  14. package/dist/components/ui/card.mjs.map +1 -1
  15. package/dist/components/ui/dropdown-menu.js +1 -1
  16. package/dist/components/ui/dropdown-menu.js.map +1 -1
  17. package/dist/components/ui/dropdown-menu.mjs +1 -1
  18. package/dist/components/ui/dropdown-menu.mjs.map +1 -1
  19. package/dist/components/ui/input.js.map +1 -1
  20. package/dist/components/ui/input.mjs.map +1 -1
  21. package/dist/components/ui/label.js.map +1 -1
  22. package/dist/components/ui/label.mjs.map +1 -1
  23. package/dist/components/ui/separator.js.map +1 -1
  24. package/dist/components/ui/separator.mjs.map +1 -1
  25. package/dist/components/ui/sheet.js.map +1 -1
  26. package/dist/components/ui/sheet.mjs.map +1 -1
  27. package/dist/components/ui/theme-toggle.js +3 -0
  28. package/dist/components/ui/theme-toggle.js.map +1 -0
  29. package/dist/components/ui/theme-toggle.mjs +3 -0
  30. package/dist/components/ui/theme-toggle.mjs.map +1 -0
  31. package/dist/index.d.mts +5 -2
  32. package/dist/index.d.ts +5 -2
  33. package/dist/index.js +1 -1
  34. package/dist/index.js.map +1 -1
  35. package/dist/index.mjs +1 -1
  36. package/dist/index.mjs.map +1 -1
  37. package/dist/styles.css +314 -20
  38. package/package.json +23 -12
  39. package/src/components/core/navbar.tsx +145 -112
  40. package/src/components/core/user-dropdown.tsx +22 -4
  41. package/src/components/icons.tsx +6 -12
  42. package/src/components/ui/alert.tsx +1 -1
  43. package/src/components/ui/avatar.tsx +1 -1
  44. package/src/components/ui/badge.tsx +1 -1
  45. package/src/components/ui/card.tsx +1 -1
  46. package/src/components/ui/dropdown-menu.tsx +198 -197
  47. package/src/components/ui/input.tsx +1 -1
  48. package/src/components/ui/label.tsx +1 -1
  49. package/src/components/ui/separator.tsx +1 -1
  50. package/src/components/ui/sheet.tsx +1 -1
  51. package/src/components/ui/theme-toggle.tsx +55 -0
  52. package/src/stories/core/Navbar.stories.tsx +45 -0
  53. package/src/stories/core/PlaceholderAlert.stories.tsx +23 -0
  54. package/src/stories/core/UserDropdown.stories.tsx +56 -0
  55. package/src/stories/core/UserProfile.stories.tsx +47 -0
  56. package/src/stories/flow/LoginForm.stories.tsx +20 -0
  57. package/src/stories/flow/TotpValidator.stories.tsx +23 -0
  58. package/src/stories/showcase/Landing.stories.tsx +376 -0
  59. package/src/stories/ui/Button.stories.tsx +45 -0
  60. package/vitest.config.ts +39 -0
  61. package/vitest.shims.d.ts +1 -0
  62. package/wrangler.prod.toml +4 -0
  63. package/ladle.config.mjs +0 -21
  64. package/src/main.tsx +0 -9
  65. package/src/preview.tsx +0 -7
  66. package/src/stories/Button._stories.tsx +0 -28
  67. package/src/stories/LoginForm.stories.tsx +0 -29
  68. package/src/stories/Navbar._stories.tsx +0 -66
  69. package/src/stories/PlaceholderAlert._stories.tsx +0 -13
  70. package/src/stories/TotpValidator.stories.tsx +0 -16
  71. package/src/stories/UserDropdown.stories.tsx +0 -34
  72. package/src/stories/UserProfile.stories.tsx +0 -46
@@ -27,177 +27,178 @@ function DropdownMenuPortal({
27
27
  );
28
28
  }
29
29
 
30
- function DropdownMenuTrigger({
31
- ...props
32
- }: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {
33
- return (
34
- <DropdownMenuPrimitive.Trigger
35
- data-slot="dropdown-menu-trigger"
36
- {...props}
37
- />
38
- );
39
- }
40
-
41
- function DropdownMenuContent({
42
- className,
43
- sideOffset = 4,
44
- ...props
45
- }: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {
46
- return (
47
- <DropdownMenuPrimitive.Portal>
48
- <DropdownMenuPrimitive.Content
49
- data-slot="dropdown-menu-content"
50
- sideOffset={sideOffset}
51
- className={cn(
52
- "bg-popover text-popover-foreground 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-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md",
53
- className,
54
- )}
55
- {...props}
56
- />
57
- </DropdownMenuPrimitive.Portal>
58
- );
59
- }
30
+ const DropdownMenuTrigger = React.forwardRef<
31
+ React.ElementRef<typeof DropdownMenuPrimitive.Trigger>,
32
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Trigger>
33
+ >(({ ...props }, ref) => (
34
+ <DropdownMenuPrimitive.Trigger
35
+ ref={ref}
36
+ data-slot="dropdown-menu-trigger"
37
+ {...props}
38
+ />
39
+ ));
40
+ DropdownMenuTrigger.displayName = DropdownMenuPrimitive.Trigger.displayName;
60
41
 
61
- function DropdownMenuGroup({
62
- ...props
63
- }: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {
64
- return (
65
- <DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />
66
- );
67
- }
68
-
69
- function DropdownMenuItem({
70
- className,
71
- inset,
72
- variant = "default",
73
- ...props
74
- }: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
75
- inset?: boolean;
76
- variant?: "default" | "destructive";
77
- }) {
78
- return (
79
- <DropdownMenuPrimitive.Item
80
- data-slot="dropdown-menu-item"
81
- data-inset={inset}
82
- data-variant={variant}
42
+ const DropdownMenuContent = React.forwardRef<
43
+ React.ElementRef<typeof DropdownMenuPrimitive.Content>,
44
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
45
+ >(({ className, sideOffset = 4, ...props }, ref) => (
46
+ <DropdownMenuPrimitive.Portal>
47
+ <DropdownMenuPrimitive.Content
48
+ ref={ref}
49
+ data-slot="dropdown-menu-content"
50
+ sideOffset={sideOffset}
83
51
  className={cn(
84
- "focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
52
+ "bg-popover text-popover-foreground 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-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md",
85
53
  className,
86
54
  )}
87
55
  {...props}
88
56
  />
89
- );
90
- }
57
+ </DropdownMenuPrimitive.Portal>
58
+ ));
59
+ DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
91
60
 
92
- function DropdownMenuCheckboxItem({
93
- className,
94
- children,
95
- checked,
96
- ...props
97
- }: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>) {
98
- return (
99
- <DropdownMenuPrimitive.CheckboxItem
100
- data-slot="dropdown-menu-checkbox-item"
101
- className={cn(
102
- "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
103
- className,
104
- )}
105
- checked={checked}
106
- {...props}
107
- >
108
- <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
109
- <DropdownMenuPrimitive.ItemIndicator>
110
- <CheckIcon className="size-4" />
111
- </DropdownMenuPrimitive.ItemIndicator>
112
- </span>
113
- {children}
114
- </DropdownMenuPrimitive.CheckboxItem>
115
- );
116
- }
61
+ const DropdownMenuGroup = React.forwardRef<
62
+ React.ElementRef<typeof DropdownMenuPrimitive.Group>,
63
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Group>
64
+ >(({ ...props }, ref) => (
65
+ <DropdownMenuPrimitive.Group
66
+ ref={ref}
67
+ data-slot="dropdown-menu-group"
68
+ {...props}
69
+ />
70
+ ));
71
+ DropdownMenuGroup.displayName = DropdownMenuPrimitive.Group.displayName;
117
72
 
118
- function DropdownMenuRadioGroup({
119
- ...props
120
- }: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {
121
- return (
122
- <DropdownMenuPrimitive.RadioGroup
123
- data-slot="dropdown-menu-radio-group"
124
- {...props}
125
- />
126
- );
127
- }
73
+ const DropdownMenuItem = React.forwardRef<
74
+ React.ElementRef<typeof DropdownMenuPrimitive.Item>,
75
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
76
+ inset?: boolean;
77
+ variant?: "default" | "destructive";
78
+ }
79
+ >(({ className, inset, variant = "default", ...props }, ref) => (
80
+ <DropdownMenuPrimitive.Item
81
+ ref={ref}
82
+ data-slot="dropdown-menu-item"
83
+ data-inset={inset}
84
+ data-variant={variant}
85
+ className={cn(
86
+ "focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
87
+ className,
88
+ )}
89
+ {...props}
90
+ />
91
+ ));
92
+ DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
128
93
 
129
- function DropdownMenuRadioItem({
130
- className,
131
- children,
132
- ...props
133
- }: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>) {
134
- return (
135
- <DropdownMenuPrimitive.RadioItem
136
- data-slot="dropdown-menu-radio-item"
137
- className={cn(
138
- "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
139
- className,
140
- )}
141
- {...props}
142
- >
143
- <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
144
- <DropdownMenuPrimitive.ItemIndicator>
145
- <CircleIcon className="size-2 fill-current" />
146
- </DropdownMenuPrimitive.ItemIndicator>
147
- </span>
148
- {children}
149
- </DropdownMenuPrimitive.RadioItem>
150
- );
151
- }
94
+ const DropdownMenuCheckboxItem = React.forwardRef<
95
+ React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
96
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>
97
+ >(({ className, children, checked, ...props }, ref) => (
98
+ <DropdownMenuPrimitive.CheckboxItem
99
+ ref={ref}
100
+ data-slot="dropdown-menu-checkbox-item"
101
+ className={cn(
102
+ "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
103
+ className,
104
+ )}
105
+ checked={checked}
106
+ {...props}
107
+ >
108
+ <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
109
+ <DropdownMenuPrimitive.ItemIndicator>
110
+ <CheckIcon className="size-4" />
111
+ </DropdownMenuPrimitive.ItemIndicator>
112
+ </span>
113
+ {children}
114
+ </DropdownMenuPrimitive.CheckboxItem>
115
+ ));
116
+ DropdownMenuCheckboxItem.displayName =
117
+ DropdownMenuPrimitive.CheckboxItem.displayName;
152
118
 
153
- function DropdownMenuLabel({
154
- className,
155
- inset,
156
- ...props
157
- }: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {
158
- inset?: boolean;
159
- }) {
160
- return (
161
- <DropdownMenuPrimitive.Label
162
- data-slot="dropdown-menu-label"
163
- data-inset={inset}
164
- className={cn(
165
- "px-2 py-1.5 text-sm font-medium data-[inset]:pl-8",
166
- className,
167
- )}
168
- {...props}
169
- />
170
- );
171
- }
119
+ const DropdownMenuRadioGroup = React.forwardRef<
120
+ React.ElementRef<typeof DropdownMenuPrimitive.RadioGroup>,
121
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioGroup>
122
+ >(({ ...props }, ref) => (
123
+ <DropdownMenuPrimitive.RadioGroup
124
+ ref={ref}
125
+ data-slot="dropdown-menu-radio-group"
126
+ {...props}
127
+ />
128
+ ));
129
+ DropdownMenuRadioGroup.displayName =
130
+ DropdownMenuPrimitive.RadioGroup.displayName;
172
131
 
173
- function DropdownMenuSeparator({
174
- className,
175
- ...props
176
- }: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {
177
- return (
178
- <DropdownMenuPrimitive.Separator
179
- data-slot="dropdown-menu-separator"
180
- className={cn("bg-border -mx-1 my-1 h-px", className)}
181
- {...props}
182
- />
183
- );
184
- }
132
+ const DropdownMenuRadioItem = React.forwardRef<
133
+ React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
134
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>
135
+ >(({ className, children, ...props }, ref) => (
136
+ <DropdownMenuPrimitive.RadioItem
137
+ ref={ref}
138
+ data-slot="dropdown-menu-radio-item"
139
+ className={cn(
140
+ "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
141
+ className,
142
+ )}
143
+ {...props}
144
+ >
145
+ <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
146
+ <DropdownMenuPrimitive.ItemIndicator>
147
+ <CircleIcon className="size-2 fill-current" />
148
+ </DropdownMenuPrimitive.ItemIndicator>
149
+ </span>
150
+ {children}
151
+ </DropdownMenuPrimitive.RadioItem>
152
+ ));
153
+ DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
185
154
 
186
- function DropdownMenuShortcut({
187
- className,
188
- ...props
189
- }: React.ComponentProps<"span">) {
190
- return (
191
- <span
192
- data-slot="dropdown-menu-shortcut"
193
- className={cn(
194
- "text-muted-foreground ml-auto text-xs tracking-widest",
195
- className,
196
- )}
197
- {...props}
198
- />
199
- );
200
- }
155
+ const DropdownMenuLabel = React.forwardRef<
156
+ React.ElementRef<typeof DropdownMenuPrimitive.Label>,
157
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
158
+ inset?: boolean;
159
+ }
160
+ >(({ className, inset, ...props }, ref) => (
161
+ <DropdownMenuPrimitive.Label
162
+ ref={ref}
163
+ data-slot="dropdown-menu-label"
164
+ data-inset={inset}
165
+ className={cn(
166
+ "px-2 py-1.5 text-sm font-medium data-[inset]:pl-8",
167
+ className,
168
+ )}
169
+ {...props}
170
+ />
171
+ ));
172
+ DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
173
+
174
+ const DropdownMenuSeparator = React.forwardRef<
175
+ React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
176
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
177
+ >(({ className, ...props }, ref) => (
178
+ <DropdownMenuPrimitive.Separator
179
+ ref={ref}
180
+ data-slot="dropdown-menu-separator"
181
+ className={cn("bg-border -mx-1 my-1 h-px", className)}
182
+ {...props}
183
+ />
184
+ ));
185
+ DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
186
+
187
+ const DropdownMenuShortcut = React.forwardRef<
188
+ HTMLSpanElement,
189
+ React.ComponentPropsWithoutRef<"span">
190
+ >(({ className, ...props }, ref) => (
191
+ <span
192
+ ref={ref}
193
+ data-slot="dropdown-menu-shortcut"
194
+ className={cn(
195
+ "text-muted-foreground ml-auto text-xs tracking-widest",
196
+ className,
197
+ )}
198
+ {...props}
199
+ />
200
+ ));
201
+ DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
201
202
 
202
203
  function DropdownMenuSub({
203
204
  ...props
@@ -205,45 +206,45 @@ function DropdownMenuSub({
205
206
  return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />;
206
207
  }
207
208
 
208
- function DropdownMenuSubTrigger({
209
- className,
210
- inset,
211
- children,
212
- ...props
213
- }: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {
214
- inset?: boolean;
215
- }) {
216
- return (
217
- <DropdownMenuPrimitive.SubTrigger
218
- data-slot="dropdown-menu-sub-trigger"
219
- data-inset={inset}
220
- className={cn(
221
- "focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8",
222
- className,
223
- )}
224
- {...props}
225
- >
226
- {children}
227
- <ChevronRightIcon className="ml-auto size-4" />
228
- </DropdownMenuPrimitive.SubTrigger>
229
- );
230
- }
209
+ const DropdownMenuSubTrigger = React.forwardRef<
210
+ React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
211
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
212
+ inset?: boolean;
213
+ }
214
+ >(({ className, inset, children, ...props }, ref) => (
215
+ <DropdownMenuPrimitive.SubTrigger
216
+ ref={ref}
217
+ data-slot="dropdown-menu-sub-trigger"
218
+ data-inset={inset}
219
+ className={cn(
220
+ "focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8",
221
+ className,
222
+ )}
223
+ {...props}
224
+ >
225
+ {children}
226
+ <ChevronRightIcon className="ml-auto size-4" />
227
+ </DropdownMenuPrimitive.SubTrigger>
228
+ ));
229
+ DropdownMenuSubTrigger.displayName =
230
+ DropdownMenuPrimitive.SubTrigger.displayName;
231
231
 
232
- function DropdownMenuSubContent({
233
- className,
234
- ...props
235
- }: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {
236
- return (
237
- <DropdownMenuPrimitive.SubContent
238
- data-slot="dropdown-menu-sub-content"
239
- className={cn(
240
- "bg-popover text-popover-foreground 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-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg",
241
- className,
242
- )}
243
- {...props}
244
- />
245
- );
246
- }
232
+ const DropdownMenuSubContent = React.forwardRef<
233
+ React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
234
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
235
+ >(({ className, ...props }, ref) => (
236
+ <DropdownMenuPrimitive.SubContent
237
+ ref={ref}
238
+ data-slot="dropdown-menu-sub-content"
239
+ className={cn(
240
+ "bg-popover text-popover-foreground 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-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg",
241
+ className,
242
+ )}
243
+ {...props}
244
+ />
245
+ ));
246
+ DropdownMenuSubContent.displayName =
247
+ DropdownMenuPrimitive.SubContent.displayName;
247
248
 
248
249
  export {
249
250
  DropdownMenu,
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
2
 
3
- import { cn } from "@authdog/react-elements/lib/utils";
3
+ import { cn } from "../../lib/utils";
4
4
 
5
5
  function Input({ className, type, ...props }: React.ComponentProps<"input">) {
6
6
  return (
@@ -3,7 +3,7 @@
3
3
  import * as React from "react";
4
4
  import * as LabelPrimitive from "@radix-ui/react-label";
5
5
 
6
- import { cn } from "@authdog/react-elements/lib/utils";
6
+ import { cn } from "../../lib/utils";
7
7
 
8
8
  function Label({
9
9
  className,
@@ -3,7 +3,7 @@
3
3
  import * as React from "react";
4
4
  import * as SeparatorPrimitive from "@radix-ui/react-separator";
5
5
 
6
- import { cn } from "@authdog/react-elements/lib/utils";
6
+ import { cn } from "../../lib/utils";
7
7
 
8
8
  function Separator({
9
9
  className,
@@ -5,7 +5,7 @@ import * as SheetPrimitive from "@radix-ui/react-dialog";
5
5
  import { X } from "lucide-react";
6
6
  import type { ComponentType } from "react";
7
7
 
8
- import { cn } from "@authdog/react-elements/lib/utils";
8
+ import { cn } from "../../lib/utils";
9
9
 
10
10
  const XIcon = X as ComponentType<React.SVGProps<SVGSVGElement>>;
11
11
 
@@ -0,0 +1,55 @@
1
+ "use client";
2
+
3
+ import { useEffect, useState } from "react";
4
+ import { Sun, Moon } from "lucide-react";
5
+
6
+ import { Button } from "./button";
7
+
8
+ const STORAGE_KEY = "authdog-theme";
9
+
10
+ type ThemeMode = "light" | "dark";
11
+
12
+ const getPreferredTheme = (): ThemeMode => {
13
+ if (typeof window === "undefined") return "light";
14
+ const stored = window.localStorage.getItem(STORAGE_KEY);
15
+ if (stored === "light" || stored === "dark") {
16
+ return stored;
17
+ }
18
+ return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
19
+ };
20
+
21
+ const applyTheme = (mode: ThemeMode) => {
22
+ document.documentElement.classList.toggle("dark", mode === "dark");
23
+ };
24
+
25
+ export const ThemeToggle = () => {
26
+ const [mode, setMode] = useState<ThemeMode>("light");
27
+
28
+ useEffect(() => {
29
+ const initial = getPreferredTheme();
30
+ applyTheme(initial);
31
+ setMode(initial);
32
+ }, []);
33
+
34
+ const toggle = () => {
35
+ const nextMode: ThemeMode = mode === "dark" ? "light" : "dark";
36
+ applyTheme(nextMode);
37
+ try {
38
+ window.localStorage.setItem(STORAGE_KEY, nextMode);
39
+ } catch {
40
+ // ignore
41
+ }
42
+ setMode(nextMode);
43
+ };
44
+
45
+ return (
46
+ <Button
47
+ variant="ghost"
48
+ size="icon"
49
+ aria-label={mode === "dark" ? "Switch to light theme" : "Switch to dark theme"}
50
+ onClick={toggle}
51
+ >
52
+ {mode === "dark" ? <Sun className="h-4 w-4" /> : <Moon className="h-4 w-4" />}
53
+ </Button>
54
+ );
55
+ };
@@ -0,0 +1,45 @@
1
+ "use client";
2
+
3
+ import type { Meta, StoryObj } from "@storybook/react";
4
+
5
+ import { Navbar } from "../../components/core/navbar";
6
+ import React from "react";
7
+
8
+ const demoItems = [
9
+ { title: "Home", href: "/" },
10
+ { title: "Features", href: "/features" },
11
+ { title: "Pricing", href: "/pricing" },
12
+ // { title: "Contact", href: "/contact" },
13
+ ];
14
+
15
+ const demoUser = {
16
+ id: "user_123",
17
+ displayName: "Avery Stone",
18
+ emails: [{ value: "avery.stone@example.com" }],
19
+ photos: [{ value: "https://i.pravatar.cc/120?img=56" }],
20
+ };
21
+
22
+ const meta = {
23
+ title: "Core/Navbar",
24
+ component: Navbar,
25
+ tags: ["autodocs"],
26
+ parameters: {
27
+ layout: "fullscreen",
28
+ },
29
+ args: {
30
+ logoText: "Authdog",
31
+ items: demoItems,
32
+ },
33
+ } satisfies Meta<typeof Navbar>;
34
+
35
+ export default meta;
36
+
37
+ type Story = StoryObj<typeof Navbar>;
38
+
39
+ export const Guest: Story = {};
40
+
41
+ export const Authenticated: Story = {
42
+ args: {
43
+ user: demoUser,
44
+ },
45
+ };
@@ -0,0 +1,23 @@
1
+ "use client";
2
+
3
+ import type { Meta, StoryObj } from "@storybook/react";
4
+
5
+ import { PlaceholderAlert } from "../../components/core/placeholder-alert";
6
+ import React from "react";
7
+
8
+ const meta = {
9
+ title: "Core/Placeholder Alert",
10
+ component: PlaceholderAlert,
11
+ tags: ["autodocs"],
12
+ } satisfies Meta<typeof PlaceholderAlert>;
13
+
14
+ export default meta;
15
+
16
+ type Story = StoryObj<typeof PlaceholderAlert>;
17
+
18
+ export const Basic: Story = {
19
+ args: {
20
+ title: "Custom Alert Title",
21
+ description: "This is a custom description for the placeholder alert.",
22
+ },
23
+ };
@@ -0,0 +1,56 @@
1
+ "use client";
2
+
3
+ import type { Meta, StoryObj } from "@storybook/react";
4
+
5
+ import { UserDropdown } from "../../components/core/user-dropdown";
6
+ import {
7
+ Avatar,
8
+ AvatarFallback,
9
+ AvatarImage,
10
+ } from "../../components/ui/avatar";
11
+ import React from "react";
12
+
13
+ const demoUser = {
14
+ displayName: "Jane Doe",
15
+ emails: [{ value: "jane.doe@example.com" }],
16
+ photos: [{ value: "https://i.pravatar.cc/100" }],
17
+ };
18
+
19
+ const trigger = (
20
+ <span className="inline-flex h-10 w-10 items-center justify-center rounded-full border bg-white shadow">
21
+ <Avatar className="h-8 w-8 rounded-full">
22
+ <AvatarImage src="https://i.pravatar.cc/100" />
23
+ <AvatarFallback>JD</AvatarFallback>
24
+ </Avatar>
25
+ </span>
26
+ );
27
+
28
+ const meta = {
29
+ title: "Core/User Dropdown",
30
+ component: UserDropdown,
31
+ tags: ["autodocs"],
32
+ parameters: {
33
+ layout: "centered",
34
+ },
35
+ render: (args) => (
36
+ <div className="p-10">
37
+ <UserDropdown {...args} />
38
+ </div>
39
+ ),
40
+ } satisfies Meta<typeof UserDropdown>;
41
+
42
+ export default meta;
43
+
44
+ type Story = StoryObj<typeof UserDropdown>;
45
+
46
+ export const Default: Story = {
47
+ args: {
48
+ trigger,
49
+ user: demoUser,
50
+ links: [{ label: "My Organizations", href: "/organizations" }],
51
+ side: "bottom",
52
+ align: "start",
53
+ onManageAccount: () => console.log("Manage account"),
54
+ onSignout: () => console.log("Sign out"),
55
+ },
56
+ };