bmj-ui 1.0.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.
@@ -0,0 +1,14 @@
1
+ import * as React from "react";
2
+ import { cn } from "../../lib/utils";
3
+
4
+ function Skeleton({ className, ...props }: React.ComponentProps<"div">) {
5
+ return (
6
+ <div
7
+ data-slot="skeleton"
8
+ className={cn("animate-pulse rounded-md bg-muted", className)}
9
+ {...props}
10
+ />
11
+ );
12
+ }
13
+
14
+ export { Skeleton };
@@ -0,0 +1,116 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+
5
+ import { cn } from "../../lib/utils";
6
+
7
+ function Table({ className, ...props }: React.ComponentProps<"table">) {
8
+ return (
9
+ <div
10
+ data-slot="table-container"
11
+ className="relative w-full overflow-x-auto"
12
+ >
13
+ <table
14
+ data-slot="table"
15
+ className={cn("w-full caption-bottom text-sm", className)}
16
+ {...props}
17
+ />
18
+ </div>
19
+ );
20
+ }
21
+
22
+ function TableHeader({ className, ...props }: React.ComponentProps<"thead">) {
23
+ return (
24
+ <thead
25
+ data-slot="table-header"
26
+ className={cn("[&_tr]:border-b", className)}
27
+ {...props}
28
+ />
29
+ );
30
+ }
31
+
32
+ function TableBody({ className, ...props }: React.ComponentProps<"tbody">) {
33
+ return (
34
+ <tbody
35
+ data-slot="table-body"
36
+ className={cn("[&_tr:last-child]:border-0", className)}
37
+ {...props}
38
+ />
39
+ );
40
+ }
41
+
42
+ function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) {
43
+ return (
44
+ <tfoot
45
+ data-slot="table-footer"
46
+ className={cn(
47
+ "border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",
48
+ className,
49
+ )}
50
+ {...props}
51
+ />
52
+ );
53
+ }
54
+
55
+ function TableRow({ className, ...props }: React.ComponentProps<"tr">) {
56
+ return (
57
+ <tr
58
+ data-slot="table-row"
59
+ className={cn(
60
+ "border-b transition-colors hover:bg-muted/50 has-aria-expanded:bg-muted/50 data-[state=selected]:bg-muted",
61
+ className,
62
+ )}
63
+ {...props}
64
+ />
65
+ );
66
+ }
67
+
68
+ function TableHead({ className, ...props }: React.ComponentProps<"th">) {
69
+ return (
70
+ <th
71
+ data-slot="table-head"
72
+ className={cn(
73
+ "h-10 px-2 text-left align-middle font-medium whitespace-nowrap text-foreground [&:has([role=checkbox])]:pr-0",
74
+ className,
75
+ )}
76
+ {...props}
77
+ />
78
+ );
79
+ }
80
+
81
+ function TableCell({ className, ...props }: React.ComponentProps<"td">) {
82
+ return (
83
+ <td
84
+ data-slot="table-cell"
85
+ className={cn(
86
+ "p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0",
87
+ className,
88
+ )}
89
+ {...props}
90
+ />
91
+ );
92
+ }
93
+
94
+ function TableCaption({
95
+ className,
96
+ ...props
97
+ }: React.ComponentProps<"caption">) {
98
+ return (
99
+ <caption
100
+ data-slot="table-caption"
101
+ className={cn("mt-4 text-sm text-muted-foreground", className)}
102
+ {...props}
103
+ />
104
+ );
105
+ }
106
+
107
+ export {
108
+ Table,
109
+ TableHeader,
110
+ TableBody,
111
+ TableFooter,
112
+ TableHead,
113
+ TableRow,
114
+ TableCell,
115
+ TableCaption,
116
+ };
@@ -0,0 +1,80 @@
1
+ import { Tabs as TabsPrimitive } from "@base-ui/react/tabs";
2
+ import { cva, type VariantProps } from "class-variance-authority";
3
+
4
+ import { cn } from "../../lib/utils";
5
+
6
+ function Tabs({
7
+ className,
8
+ orientation = "horizontal",
9
+ ...props
10
+ }: TabsPrimitive.Root.Props) {
11
+ return (
12
+ <TabsPrimitive.Root
13
+ data-slot="tabs"
14
+ data-orientation={orientation}
15
+ className={cn(
16
+ "group/tabs flex gap-2 data-horizontal:flex-col",
17
+ className,
18
+ )}
19
+ {...props}
20
+ />
21
+ );
22
+ }
23
+
24
+ const tabsListVariants = cva(
25
+ "group/tabs-list inline-flex w-fit items-center justify-center rounded-lg p-[3px] text-muted-foreground group-data-horizontal/tabs:h-8 group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col data-[variant=line]:rounded-none",
26
+ {
27
+ variants: {
28
+ variant: {
29
+ default: "bg-muted",
30
+ line: "gap-1 bg-transparent",
31
+ },
32
+ },
33
+ defaultVariants: {
34
+ variant: "default",
35
+ },
36
+ },
37
+ );
38
+
39
+ function TabsList({
40
+ className,
41
+ variant = "default",
42
+ ...props
43
+ }: TabsPrimitive.List.Props & VariantProps<typeof tabsListVariants>) {
44
+ return (
45
+ <TabsPrimitive.List
46
+ data-slot="tabs-list"
47
+ data-variant={variant}
48
+ className={cn(tabsListVariants({ variant }), className)}
49
+ {...props}
50
+ />
51
+ );
52
+ }
53
+
54
+ function TabsTrigger({ className, ...props }: TabsPrimitive.Tab.Props) {
55
+ return (
56
+ <TabsPrimitive.Tab
57
+ data-slot="tabs-trigger"
58
+ className={cn(
59
+ "relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-1.5 py-0.5 text-sm font-medium whitespace-nowrap text-foreground/60 transition-all group-data-vertical/tabs:w-full group-data-vertical/tabs:justify-start hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 has-data-[icon=inline-end]:pr-1 has-data-[icon=inline-start]:pl-1 aria-disabled:pointer-events-none aria-disabled:opacity-50 dark:text-muted-foreground dark:hover:text-foreground group-data-[variant=default]/tabs-list:data-active:shadow-sm group-data-[variant=line]/tabs-list:data-active:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
60
+ "group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent",
61
+ "data-active:bg-background data-active:text-foreground dark:data-active:border-input dark:data-active:bg-input/30 dark:data-active:text-foreground",
62
+ "after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-horizontal/tabs:after:inset-x-0 group-data-horizontal/tabs:after:-bottom-1.25 group-data-horizontal/tabs:after:h-0.5 group-data-vertical/tabs:after:inset-y-0 group-data-vertical/tabs:after:-right-1 group-data-vertical/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-active:after:opacity-100",
63
+ className,
64
+ )}
65
+ {...props}
66
+ />
67
+ );
68
+ }
69
+
70
+ function TabsContent({ className, ...props }: TabsPrimitive.Panel.Props) {
71
+ return (
72
+ <TabsPrimitive.Panel
73
+ data-slot="tabs-content"
74
+ className={cn("flex-1 text-sm outline-none", className)}
75
+ {...props}
76
+ />
77
+ );
78
+ }
79
+
80
+ export { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants };
@@ -0,0 +1,66 @@
1
+ "use client";
2
+
3
+ import { Tooltip as TooltipPrimitive } from "@base-ui/react/tooltip";
4
+
5
+ import { cn } from "../../lib/utils";
6
+
7
+ function TooltipProvider({
8
+ delay = 0,
9
+ ...props
10
+ }: TooltipPrimitive.Provider.Props) {
11
+ return (
12
+ <TooltipPrimitive.Provider
13
+ data-slot="tooltip-provider"
14
+ delay={delay}
15
+ {...props}
16
+ />
17
+ );
18
+ }
19
+
20
+ function Tooltip({ ...props }: TooltipPrimitive.Root.Props) {
21
+ return <TooltipPrimitive.Root data-slot="tooltip" {...props} />;
22
+ }
23
+
24
+ function TooltipTrigger({ ...props }: TooltipPrimitive.Trigger.Props) {
25
+ return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />;
26
+ }
27
+
28
+ function TooltipContent({
29
+ className,
30
+ side = "top",
31
+ sideOffset = 4,
32
+ align = "center",
33
+ alignOffset = 0,
34
+ children,
35
+ ...props
36
+ }: TooltipPrimitive.Popup.Props &
37
+ Pick<
38
+ TooltipPrimitive.Positioner.Props,
39
+ "align" | "alignOffset" | "side" | "sideOffset"
40
+ >) {
41
+ return (
42
+ <TooltipPrimitive.Portal>
43
+ <TooltipPrimitive.Positioner
44
+ align={align}
45
+ alignOffset={alignOffset}
46
+ side={side}
47
+ sideOffset={sideOffset}
48
+ className="isolate z-50"
49
+ >
50
+ <TooltipPrimitive.Popup
51
+ data-slot="tooltip-content"
52
+ className={cn(
53
+ "z-50 inline-flex w-fit max-w-xs origin-(--transform-origin) items-center gap-1.5 rounded-md bg-foreground px-3 py-1.5 text-xs text-background has-data-[slot=kbd]:pr-1.5 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-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 **:data-[slot=kbd]:relative **:data-[slot=kbd]:isolate **:data-[slot=kbd]:z-50 **:data-[slot=kbd]:rounded-sm data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
54
+ className,
55
+ )}
56
+ {...props}
57
+ >
58
+ {children}
59
+ <TooltipPrimitive.Arrow className="z-50 size-2.5 translate-y-[calc(-50%-2px)] rotate-45 rounded-xs bg-foreground fill-foreground data-[side=bottom]:top-1 data-[side=inline-end]:top-1/2! data-[side=inline-end]:-left-1 data-[side=inline-end]:-translate-y-1/2 data-[side=inline-start]:top-1/2! data-[side=inline-start]:-right-1 data-[side=inline-start]:-translate-y-1/2 data-[side=left]:top-1/2! data-[side=left]:-right-1 data-[side=left]:-translate-y-1/2 data-[side=right]:top-1/2! data-[side=right]:-left-1 data-[side=right]:-translate-y-1/2 data-[side=top]:-bottom-2.5" />
60
+ </TooltipPrimitive.Popup>
61
+ </TooltipPrimitive.Positioner>
62
+ </TooltipPrimitive.Portal>
63
+ );
64
+ }
65
+
66
+ export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
@@ -0,0 +1,19 @@
1
+ import * as React from "react"
2
+
3
+ const MOBILE_BREAKPOINT = 768
4
+
5
+ export function useIsMobile() {
6
+ const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined)
7
+
8
+ React.useEffect(() => {
9
+ const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)
10
+ const onChange = () => {
11
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
12
+ }
13
+ mql.addEventListener("change", onChange)
14
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
15
+ return () => mql.removeEventListener("change", onChange)
16
+ }, [])
17
+
18
+ return !!isMobile
19
+ }
package/src/index.css ADDED
@@ -0,0 +1,155 @@
1
+ @import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap");
2
+ @import "tailwindcss";
3
+ @import "tw-animate-css";
4
+ @import "shadcn/tailwind.css";
5
+
6
+ @custom-variant dark (&:is(.dark *));
7
+
8
+ @theme inline {
9
+ --font-heading: "Inter", var(--font-sans);
10
+ --font-sans: "Inter", sans-serif;
11
+ --font-mono: "JetBrains Mono", monospace;
12
+ --color-sidebar-ring: var(--sidebar-ring);
13
+ --color-sidebar-border: var(--sidebar-border);
14
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
15
+ --color-sidebar-accent: var(--sidebar-accent);
16
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
17
+ --color-sidebar-primary: var(--sidebar-primary);
18
+ --color-sidebar-foreground: var(--sidebar-foreground);
19
+ --color-sidebar: var(--sidebar);
20
+ --color-chart-5: var(--chart-5);
21
+ --color-chart-4: var(--chart-4);
22
+ --color-chart-3: var(--chart-3);
23
+ --color-chart-2: var(--chart-2);
24
+ --color-chart-1: var(--chart-1);
25
+ --color-ring: var(--ring);
26
+ --color-input: var(--input);
27
+ --color-border: var(--border);
28
+ --color-destructive: var(--destructive);
29
+ --color-accent-foreground: var(--accent-foreground);
30
+ --color-accent: var(--accent);
31
+ --color-muted-foreground: var(--muted-foreground);
32
+ --color-muted: var(--muted);
33
+ --color-secondary-foreground: var(--secondary-foreground);
34
+ --color-secondary: var(--secondary);
35
+ --color-primary-foreground: var(--primary-foreground);
36
+ --color-primary: var(--primary);
37
+ --color-popover-foreground: var(--popover-foreground);
38
+ --color-popover: var(--popover);
39
+ --color-card-foreground: var(--card-foreground);
40
+ --color-card: var(--card);
41
+ --color-foreground: var(--foreground);
42
+ --color-background: var(--background);
43
+ --radius-sm: calc(var(--radius) * 0.6);
44
+ --radius-md: calc(var(--radius) * 0.8);
45
+ --radius-lg: var(--radius);
46
+ --radius-xl: calc(var(--radius) * 1.4);
47
+ --radius-2xl: calc(var(--radius) * 1.8);
48
+ --radius-3xl: calc(var(--radius) * 2.2);
49
+ --radius-4xl: calc(var(--radius) * 2.6);
50
+
51
+ --breakpoint-xs: 480px;
52
+ }
53
+
54
+ :root {
55
+ --background: oklch(1 0 0);
56
+ --foreground: oklch(0.145 0 0);
57
+ --card: oklch(1 0 0);
58
+ --card-foreground: oklch(0.145 0 0);
59
+ --popover: oklch(1 0 0);
60
+ --popover-foreground: oklch(0.145 0 0);
61
+ --primary: oklch(0.205 0 0);
62
+ --primary-foreground: oklch(0.985 0 0);
63
+ --secondary: oklch(0.97 0 0);
64
+ --secondary-foreground: oklch(0.205 0 0);
65
+ --muted: oklch(0.97 0 0);
66
+ --muted-foreground: oklch(0.556 0 0);
67
+ --accent: oklch(0.97 0 0);
68
+ --accent-foreground: oklch(0.205 0 0);
69
+ --destructive: oklch(0.577 0.245 27.325);
70
+ --border: oklch(0.922 0 0);
71
+ --input: oklch(0.922 0 0);
72
+ --ring: oklch(0.708 0 0);
73
+ --chart-1: oklch(0.87 0 0);
74
+ --chart-2: oklch(0.556 0 0);
75
+ --chart-3: oklch(0.439 0 0);
76
+ --chart-4: oklch(0.371 0 0);
77
+ --chart-5: oklch(0.269 0 0);
78
+ --radius: 0.625rem;
79
+ --sidebar: oklch(0.985 0 0);
80
+ --sidebar-foreground: oklch(0.145 0 0);
81
+ --sidebar-primary: oklch(0.205 0 0);
82
+ --sidebar-primary-foreground: oklch(0.985 0 0);
83
+ --sidebar-accent: oklch(0.97 0 0);
84
+ --sidebar-accent-foreground: oklch(0.205 0 0);
85
+ --sidebar-border: oklch(0.922 0 0);
86
+ --sidebar-ring: oklch(0.708 0 0);
87
+ }
88
+
89
+ .dark {
90
+ --background: oklch(0.145 0 0);
91
+ --foreground: oklch(0.985 0 0);
92
+ --card: oklch(0.205 0 0);
93
+ --card-foreground: oklch(0.985 0 0);
94
+ --popover: oklch(0.205 0 0);
95
+ --popover-foreground: oklch(0.985 0 0);
96
+ --primary: oklch(0.922 0 0);
97
+ --primary-foreground: oklch(0.205 0 0);
98
+ --secondary: oklch(0.269 0 0);
99
+ --secondary-foreground: oklch(0.985 0 0);
100
+ --muted: oklch(0.269 0 0);
101
+ --muted-foreground: oklch(0.708 0 0);
102
+ --accent: oklch(0.269 0 0);
103
+ --accent-foreground: oklch(0.985 0 0);
104
+ --destructive: oklch(0.704 0.191 22.216);
105
+ --border: oklch(1 0 0 / 10%);
106
+ --input: oklch(1 0 0 / 15%);
107
+ --ring: oklch(0.556 0 0);
108
+ --chart-1: oklch(0.87 0 0);
109
+ --chart-2: oklch(0.556 0 0);
110
+ --chart-3: oklch(0.439 0 0);
111
+ --chart-4: oklch(0.371 0 0);
112
+ --chart-5: oklch(0.269 0 0);
113
+ --sidebar: oklch(0.205 0 0);
114
+ --sidebar-foreground: oklch(0.985 0 0);
115
+ --sidebar-primary: oklch(0.488 0.243 264.376);
116
+ --sidebar-primary-foreground: oklch(0.985 0 0);
117
+ --sidebar-accent: oklch(0.269 0 0);
118
+ --sidebar-accent-foreground: oklch(0.985 0 0);
119
+ --sidebar-border: oklch(1 0 0 / 10%);
120
+ --sidebar-ring: oklch(0.556 0 0);
121
+ }
122
+
123
+ @layer base {
124
+ * {
125
+ @apply border-border outline-ring/50;
126
+ }
127
+ body {
128
+ @apply bg-background text-foreground;
129
+ }
130
+ html {
131
+ @apply font-sans antialiased;
132
+ }
133
+ }
134
+
135
+ @layer utilities {
136
+ .bmj-glass {
137
+ @apply bg-background/60 backdrop-blur-md border border-border/50;
138
+ }
139
+
140
+ .bmj-card-hover {
141
+ @apply transition-all duration-300 hover:shadow-lg hover:shadow-primary/5 hover:-translate-y-1;
142
+ }
143
+
144
+ .bmj-gradient-text {
145
+ @apply bg-clip-text text-transparent bg-linear-to-br from-foreground to-foreground/60;
146
+ }
147
+
148
+ .scrollbar-hide {
149
+ -ms-overflow-style: none;
150
+ scrollbar-width: none;
151
+ }
152
+ .scrollbar-hide::-webkit-scrollbar {
153
+ display: none;
154
+ }
155
+ }
package/src/index.ts ADDED
@@ -0,0 +1,7 @@
1
+ import { AppSidebar } from "./components/bmj-ui";
2
+ import { ChartCard } from "./components/bmj-ui";
3
+ import { DashboardLayout } from "./components/bmj-ui";
4
+ import { StatCard } from "./components/bmj-ui";
5
+ import { Topbar } from "./components/bmj-ui";
6
+
7
+ export { AppSidebar, ChartCard, DashboardLayout, StatCard, Topbar };
@@ -0,0 +1,6 @@
1
+ import { clsx, type ClassValue } from "clsx"
2
+ import { twMerge } from "tailwind-merge"
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs))
6
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "compilerOptions": {
3
+ "rootDir": "./src",
4
+ "outDir": "./dist",
5
+ "target": "es6",
6
+ "lib": ["DOM", "DOM.Iterable", "ESNext"],
7
+ "allowJs": true,
8
+ "skipLibCheck": true,
9
+ "esModuleInterop": true,
10
+ "allowSyntheticDefaultImports": true,
11
+ "strict": true,
12
+ "forceConsistentCasingInFileNames": true,
13
+ "noFallthroughCasesInSwitch": true,
14
+ "module": "node16",
15
+ "moduleResolution": "node16",
16
+ "resolveJsonModule": true,
17
+ "isolatedModules": true,
18
+ "noEmit": true,
19
+ "jsx": "react-jsx"
20
+ },
21
+ "include": ["src"]
22
+ }