bmj-ui 1.0.16 → 1.0.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bmj-ui",
3
- "version": "1.0.16",
3
+ "version": "1.0.17",
4
4
  "description": "Headless component library meticulously crafted for rapid dashboard development. Professional, polished, and ready for production.",
5
5
  "license": "ISC",
6
6
  "author": "",
@@ -34,9 +34,9 @@ export function ThemeToggle({ className }: { className?: string }) {
34
34
  aria-label="Toggle theme"
35
35
  >
36
36
  {theme === "light" ? (
37
- <Moon className="w-5 h-5 transition-all" />
37
+ <Moon className="bmj-theme-toggle-icon" />
38
38
  ) : (
39
- <Sun className="w-5 h-5 transition-all" />
39
+ <Sun className="bmj-theme-toggle-icon" />
40
40
  )}
41
41
  </Button>
42
42
  );
@@ -52,7 +52,7 @@ export default function AppSidebar({
52
52
  const isCollapsed = state === "collapsed";
53
53
 
54
54
  return (
55
- <Sidebar variant="inset" collapsible="icon">
55
+ <Sidebar variant="sidebar" collapsible="icon">
56
56
  <SidebarHeader className="bmj-sidebar-header">
57
57
  <div className="bmj-sidebar-logo-container">
58
58
  <div className="bmj-sidebar-logo-box">B</div>
@@ -63,7 +63,7 @@ export default function AppSidebar({
63
63
  animate={{ opacity: 1, x: 0 }}
64
64
  exit={{ opacity: 0, x: -10 }}
65
65
  transition={{ duration: 0.2 }}
66
- className="whitespace-nowrap"
66
+ className="bmj-sidebar-logo-text"
67
67
  >
68
68
  BMJ UI
69
69
  </motion.span>
@@ -99,9 +99,9 @@ export default function AppSidebar({
99
99
  render={
100
100
  <button
101
101
  type="button"
102
- className="flex items-center w-full"
102
+ className="bmj-sidebar-menu-button-inner"
103
103
  >
104
- <item.icon className="shrink-0" />
104
+ <item.icon className="bmj-sidebar-menu-icon" />
105
105
  <AnimatePresence mode="wait">
106
106
  {!isCollapsed && (
107
107
  <motion.span
@@ -113,7 +113,7 @@ export default function AppSidebar({
113
113
  }}
114
114
  exit={{ opacity: 0, width: 0, marginLeft: 0 }}
115
115
  transition={{ duration: 0.2 }}
116
- className="overflow-hidden whitespace-nowrap"
116
+ className="bmj-sidebar-menu-text"
117
117
  >
118
118
  {item.title}
119
119
  </motion.span>
@@ -140,8 +140,8 @@ export default function AppSidebar({
140
140
  transition={{ duration: 0.2 }}
141
141
  className="bmj-sidebar-user-info"
142
142
  >
143
- <span className="text-sm font-medium">Bahry Jarbou</span>
144
- <span className="text-xs text-muted-foreground">Admin</span>
143
+ <span className="bmj-sidebar-user-name">Bahry Jarbou</span>
144
+ <span className="bmj-sidebar-user-role">Admin</span>
145
145
  </motion.div>
146
146
  )}
147
147
  </AnimatePresence>
@@ -36,6 +36,18 @@ interface ChartCardProps {
36
36
  type?: "area" | "bar" | "line" | "scatter";
37
37
  }
38
38
 
39
+ interface ChartCardProps {
40
+ title: string;
41
+ description?: string;
42
+ data: any[];
43
+ dataKey: string;
44
+ categoryKey: string;
45
+ color?: string;
46
+ className?: string;
47
+ loading?: boolean;
48
+ type?: "area" | "bar" | "line" | "scatter";
49
+ }
50
+
39
51
  export default function ChartCard({
40
52
  title,
41
53
  description,
@@ -51,11 +63,11 @@ export default function ChartCard({
51
63
  return (
52
64
  <Card className={cn("bmj-chart-card", className)}>
53
65
  <CardHeader>
54
- <Skeleton className="h-6 w-40 mb-2" />
55
- <Skeleton className="h-4 w-64" />
66
+ <Skeleton className="bmj-chart-card-skeleton-title" />
67
+ <Skeleton className="bmj-chart-card-skeleton-desc" />
56
68
  </CardHeader>
57
69
  <CardContent className="bmj-chart-content">
58
- <Skeleton className="h-full w-full rounded-lg" />
70
+ <Skeleton className="bmj-chart-card-skeleton-chart" />
59
71
  </CardContent>
60
72
  </Card>
61
73
  );
@@ -191,7 +203,7 @@ export default function ChartCard({
191
203
  return (
192
204
  <Card className={cn("bmj-chart-card", className)}>
193
205
  <CardHeader>
194
- <CardTitle className="text-lg font-semibold">{title}</CardTitle>
206
+ <CardTitle className="bmj-chart-card-title">{title}</CardTitle>
195
207
  {description && <CardDescription>{description}</CardDescription>}
196
208
  </CardHeader>
197
209
  <CardContent className="bmj-chart-content">
@@ -10,6 +10,13 @@ interface DashboardLayoutProps {
10
10
  activeSidebarItem?: string;
11
11
  }
12
12
 
13
+ interface DashboardLayoutProps {
14
+ children: React.ReactNode;
15
+ sidebarItems?: SidebarItem[];
16
+ onSidebarItemClick?: (title: string) => void;
17
+ activeSidebarItem?: string;
18
+ }
19
+
13
20
  export default function DashboardLayout({
14
21
  children,
15
22
  sidebarItems,
@@ -23,7 +30,7 @@ export default function DashboardLayout({
23
30
  onItemClick={onSidebarItemClick}
24
31
  activeItem={activeSidebarItem}
25
32
  />
26
- <SidebarInset className="flex flex-col">
33
+ <SidebarInset className="bmj-dashboard-inset">
27
34
  <Topbar />
28
35
  <main className="bmj-dashboard-main">{children}</main>
29
36
  </SidebarInset>
@@ -18,6 +18,19 @@ interface StatCardProps {
18
18
  loading?: boolean;
19
19
  }
20
20
 
21
+ interface StatCardProps {
22
+ title: string;
23
+ value: string | number;
24
+ description?: string;
25
+ trend?: {
26
+ value: number;
27
+ isPositive: boolean;
28
+ };
29
+ icon?: LucideIcon;
30
+ className?: string;
31
+ loading?: boolean;
32
+ }
33
+
21
34
  export default function StatCard({
22
35
  title,
23
36
  value,
@@ -31,12 +44,12 @@ export default function StatCard({
31
44
  return (
32
45
  <Card className={cn("bmj-stat-card", className)}>
33
46
  <CardHeader className="bmj-stat-card-header">
34
- <Skeleton className="h-4 w-24" />
35
- <Skeleton className="h-4 w-4 rounded-full" />
47
+ <Skeleton className="bmj-stat-card-skeleton-title" />
48
+ <Skeleton className="bmj-stat-card-skeleton-icon" />
36
49
  </CardHeader>
37
- <CardContent className="space-y-2">
38
- <Skeleton className="h-8 w-32" />
39
- <Skeleton className="h-3 w-40" />
50
+ <CardContent className="bmj-stat-card-skeleton-content">
51
+ <Skeleton className="bmj-stat-card-skeleton-value" />
52
+ <Skeleton className="bmj-stat-card-skeleton-desc" />
40
53
  </CardContent>
41
54
  </Card>
42
55
  );
@@ -67,9 +80,9 @@ export default function StatCard({
67
80
  )}
68
81
  >
69
82
  {trend.isPositive ? (
70
- <TrendingUp className="w-3 h-3 mr-1" />
83
+ <TrendingUp className="bmj-stat-card-trend-icon" />
71
84
  ) : (
72
- <TrendingDown className="w-3 h-3 mr-1" />
85
+ <TrendingDown className="bmj-stat-card-trend-icon" />
73
86
  )}
74
87
  {trend.value}%
75
88
  </span>
@@ -41,46 +41,61 @@ export default function Topbar() {
41
41
  className="bmj-topbar-search-input"
42
42
  />
43
43
  </div>
44
- <Button variant="ghost" size="icon" className="md:hidden">
45
- <Search className="w-5 h-5" />
44
+ <Button
45
+ variant="ghost"
46
+ size="icon"
47
+ className="bmj-topbar-mobile-search-trigger"
48
+ >
49
+ <Search className="bmj-topbar-icon" />
46
50
  </Button>
47
51
  </div>
48
52
 
49
53
  <div className="bmj-topbar-right">
50
- <div className="hidden xs:block">
54
+ <div className="bmj-topbar-theme-toggle-container">
51
55
  <ThemeToggle />
52
56
  </div>
53
- <Button variant="ghost" size="icon" className="relative">
54
- <Bell className="w-5 h-5" />
57
+ <Button
58
+ variant="ghost"
59
+ size="icon"
60
+ className="bmj-topbar-notification-button"
61
+ >
62
+ <Bell className="bmj-topbar-icon" />
55
63
  <span className="bmj-topbar-notification-dot" />
56
64
  </Button>
57
65
 
58
66
  <DropdownMenu>
59
67
  <DropdownMenuTrigger
60
68
  render={
61
- <Button variant="ghost" size="icon" className="rounded-full" />
69
+ <Button
70
+ variant="ghost"
71
+ size="icon"
72
+ className="bmj-topbar-user-button"
73
+ />
62
74
  }
63
75
  >
64
- <User className="w-5 h-5" />
76
+ <User className="bmj-topbar-icon" />
65
77
  </DropdownMenuTrigger>
66
- <DropdownMenuContent align="end" className="w-56">
78
+ <DropdownMenuContent
79
+ align="end"
80
+ className="bmj-topbar-dropdown-content"
81
+ >
67
82
  <DropdownMenuGroup>
68
83
  <DropdownMenuLabel>My Account</DropdownMenuLabel>
69
84
  <DropdownMenuSeparator />
70
85
  <DropdownMenuItem onClick={() => handleItemClick("Profile")}>
71
- <User className="mr-2 h-4 w-4" />
86
+ <User className="bmj-topbar-menu-icon" />
72
87
  <span>Profile</span>
73
88
  </DropdownMenuItem>
74
89
  <DropdownMenuItem onClick={() => handleItemClick("Billing")}>
75
- <CreditCard className="mr-2 h-4 w-4" />
90
+ <CreditCard className="bmj-topbar-menu-icon" />
76
91
  <span>Billing</span>
77
92
  </DropdownMenuItem>
78
93
  <DropdownMenuItem onClick={() => handleItemClick("Team")}>
79
- <Users className="mr-2 h-4 w-4" />
94
+ <Users className="bmj-topbar-menu-icon" />
80
95
  <span>Team</span>
81
96
  </DropdownMenuItem>
82
97
  <DropdownMenuItem onClick={() => handleItemClick("Subscription")}>
83
- <Zap className="mr-2 h-4 w-4" />
98
+ <Zap className="bmj-topbar-menu-icon" />
84
99
  <span>Subscription</span>
85
100
  </DropdownMenuItem>
86
101
  <DropdownMenuSeparator />
@@ -88,7 +103,7 @@ export default function Topbar() {
88
103
  variant="destructive"
89
104
  onClick={() => handleItemClick("Log out")}
90
105
  >
91
- <LogOut className="mr-2 h-4 w-4" />
106
+ <LogOut className="bmj-topbar-menu-icon" />
92
107
  <span>Log out</span>
93
108
  </DropdownMenuItem>
94
109
  </DropdownMenuGroup>
@@ -59,13 +59,13 @@ function DialogContent({
59
59
  render={
60
60
  <Button
61
61
  variant="ghost"
62
- className="absolute top-2 right-2"
62
+ className="ui-dialog-close-button"
63
63
  size="icon-sm"
64
64
  />
65
65
  }
66
66
  >
67
67
  <XIcon />
68
- <span className="sr-only">Close</span>
68
+ <span className="ui-sr-only">Close</span>
69
69
  </DialogPrimitive.Close>
70
70
  )}
71
71
  </DialogPrimitive.Popup>
@@ -33,7 +33,7 @@ function DropdownMenuContent({
33
33
  return (
34
34
  <MenuPrimitive.Portal>
35
35
  <MenuPrimitive.Positioner
36
- className="isolate z-50 outline-none"
36
+ className="ui-dropdown-menu-positioner"
37
37
  align={align}
38
38
  alignOffset={alignOffset}
39
39
  side={side}
@@ -110,7 +110,7 @@ function DropdownMenuSubTrigger({
110
110
  {...props}
111
111
  >
112
112
  {children}
113
- <ChevronRightIcon className="ml-auto" />
113
+ <ChevronRightIcon className="ui-dropdown-menu-sub-trigger-icon" />
114
114
  </MenuPrimitive.SubmenuTrigger>
115
115
  );
116
116
  }
@@ -154,7 +154,7 @@ function DropdownMenuCheckboxItem({
154
154
  {...props}
155
155
  >
156
156
  <span
157
- className="pointer-events-none absolute right-2 flex items-center justify-center"
157
+ className="ui-dropdown-menu-indicator"
158
158
  data-slot="dropdown-menu-checkbox-item-indicator"
159
159
  >
160
160
  <MenuPrimitive.CheckboxItemIndicator>
@@ -191,7 +191,7 @@ function DropdownMenuRadioItem({
191
191
  {...props}
192
192
  >
193
193
  <span
194
- className="pointer-events-none absolute right-2 flex items-center justify-center"
194
+ className="ui-dropdown-menu-indicator"
195
195
  data-slot="dropdown-menu-radio-item-indicator"
196
196
  >
197
197
  <MenuPrimitive.RadioItemIndicator>
@@ -1,4 +1,3 @@
1
- import * as React from "react";
2
1
  import { ScrollArea as ScrollAreaPrimitive } from "@base-ui/react/scroll-area";
3
2
 
4
3
  import { cn } from "../../lib/utils";
@@ -11,7 +10,7 @@ function ScrollArea({
11
10
  return (
12
11
  <ScrollAreaPrimitive.Root
13
12
  data-slot="scroll-area"
14
- className={cn("relative", className)}
13
+ className={cn("ui-scroll-area", className)}
15
14
  {...props}
16
15
  >
17
16
  <ScrollAreaPrimitive.Viewport
@@ -43,9 +43,7 @@ function SelectTrigger({
43
43
  >
44
44
  {children}
45
45
  <SelectPrimitive.Icon
46
- render={
47
- <ChevronDownIcon className="pointer-events-none size-4 text-muted-foreground" />
48
- }
46
+ render={<ChevronDownIcon className="ui-select-icon" />}
49
47
  />
50
48
  </SelectPrimitive.Trigger>
51
49
  );
@@ -73,7 +71,7 @@ function SelectContent({
73
71
  align={align}
74
72
  alignOffset={alignOffset}
75
73
  alignItemWithTrigger={alignItemWithTrigger}
76
- className="isolate z-50"
74
+ className="ui-select-positioner"
77
75
  >
78
76
  <SelectPrimitive.Popup
79
77
  data-slot="select-content"
@@ -114,15 +112,13 @@ function SelectItem({
114
112
  className={cn("ui-select-item", className)}
115
113
  {...props}
116
114
  >
117
- <SelectPrimitive.ItemText className="flex flex-1 shrink-0 gap-2 whitespace-nowrap">
115
+ <SelectPrimitive.ItemText className="ui-select-item-text">
118
116
  {children}
119
117
  </SelectPrimitive.ItemText>
120
118
  <SelectPrimitive.ItemIndicator
121
- render={
122
- <span className="pointer-events-none absolute right-2 flex size-4 items-center justify-center" />
123
- }
119
+ render={<span className="ui-select-item-indicator" />}
124
120
  >
125
- <CheckIcon className="pointer-events-none" />
121
+ <CheckIcon className="ui-select-check-icon" />
126
122
  </SelectPrimitive.ItemIndicator>
127
123
  </SelectPrimitive.Item>
128
124
  );
@@ -57,13 +57,13 @@ function SheetContent({
57
57
  render={
58
58
  <Button
59
59
  variant="ghost"
60
- className="absolute top-3 right-3"
60
+ className="ui-sheet-close-button"
61
61
  size="icon-sm"
62
62
  />
63
63
  }
64
64
  >
65
65
  <XIcon />
66
- <span className="sr-only">Close</span>
66
+ <span className="ui-sr-only">Close</span>
67
67
  </SheetPrimitive.Close>
68
68
  )}
69
69
  </SheetPrimitive.Popup>
@@ -185,11 +185,11 @@ function Sidebar({
185
185
  }
186
186
  side={side}
187
187
  >
188
- <SheetHeader className="sr-only">
188
+ <SheetHeader className="ui-sr-only">
189
189
  <SheetTitle>Sidebar</SheetTitle>
190
190
  <SheetDescription>Displays the mobile sidebar.</SheetDescription>
191
191
  </SheetHeader>
192
- <div className="flex h-full w-full flex-col">{children}</div>
192
+ <div className="ui-sidebar-mobile-content">{children}</div>
193
193
  </SheetContent>
194
194
  </Sheet>
195
195
  );
@@ -197,7 +197,7 @@ function Sidebar({
197
197
 
198
198
  return (
199
199
  <div
200
- className="group peer hidden text-sidebar-foreground md:block"
200
+ className={cn("group peer ui-sidebar-desktop-wrapper", className)}
201
201
  data-state={state}
202
202
  data-collapsible={state === "collapsed" ? collapsible : ""}
203
203
  data-variant={variant}
@@ -210,8 +210,8 @@ function Sidebar({
210
210
  className={cn(
211
211
  "ui-sidebar-gap",
212
212
  variant === "floating" || variant === "inset"
213
- ? "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]"
214
- : "group-data-[collapsible=icon]:w-(--sidebar-width-icon)",
213
+ ? "ui-sidebar-gap-floating"
214
+ : "ui-sidebar-gap-default",
215
215
  )}
216
216
  />
217
217
  <div
@@ -221,8 +221,8 @@ function Sidebar({
221
221
  "ui-sidebar-container",
222
222
  // Adjust the padding for floating and inset variants.
223
223
  variant === "floating" || variant === "inset"
224
- ? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]"
225
- : "group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l",
224
+ ? "ui-sidebar-container-floating"
225
+ : "ui-sidebar-container-default",
226
226
  className,
227
227
  )}
228
228
  {...props}
@@ -260,7 +260,7 @@ function SidebarTrigger({
260
260
  {...props}
261
261
  >
262
262
  <PanelLeftIcon />
263
- <span className="sr-only">Toggle Sidebar</span>
263
+ <span className="ui-sr-only">Toggle Sidebar</span>
264
264
  </Button>
265
265
  );
266
266
  }
@@ -446,13 +446,12 @@ const sidebarMenuButtonVariants = cva("ui-sidebar-menu-button", {
446
446
  variants: {
447
447
  variant: {
448
448
  default: "",
449
- outline:
450
- "bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]",
449
+ outline: "ui-sidebar-menu-button-outline",
451
450
  },
452
451
  size: {
453
- default: "h-8 text-sm",
454
- sm: "h-7 text-xs",
455
- lg: "h-12 text-sm group-data-[collapsible=icon]:p-0!",
452
+ default: "ui-sidebar-menu-button-size-default",
453
+ sm: "ui-sidebar-menu-button-size-sm",
454
+ lg: "ui-sidebar-menu-button-size-lg",
456
455
  },
457
456
  },
458
457
  defaultVariants: {
@@ -530,8 +529,7 @@ function SidebarMenuAction({
530
529
  {
531
530
  className: cn(
532
531
  "ui-sidebar-menu-action",
533
- showOnHover &&
534
- "group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 peer-data-active/menu-button:text-sidebar-accent-foreground aria-expanded:opacity-100 md:opacity-0",
532
+ showOnHover && "ui-sidebar-menu-action-hover",
535
533
  className,
536
534
  ),
537
535
  },
@@ -580,12 +578,12 @@ function SidebarMenuSkeleton({
580
578
  >
581
579
  {showIcon && (
582
580
  <Skeleton
583
- className="size-4 rounded-md"
581
+ className="ui-sidebar-menu-skeleton-icon"
584
582
  data-sidebar="menu-skeleton-icon"
585
583
  />
586
584
  )}
587
585
  <Skeleton
588
- className="h-4 max-w-(--skeleton-width) flex-1"
586
+ className="ui-sidebar-menu-skeleton-text"
589
587
  data-sidebar="menu-skeleton-text"
590
588
  style={
591
589
  {