@mhome/ui 0.1.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.
- package/README.md +188 -0
- package/dist/index.cjs.js +9 -0
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.css +2 -0
- package/dist/index.esm.js +9 -0
- package/dist/index.esm.js.map +1 -0
- package/package.json +54 -0
- package/src/common/adaptive-theme-provider.js +19 -0
- package/src/components/accordion.jsx +306 -0
- package/src/components/alert.jsx +137 -0
- package/src/components/app-bar.jsx +105 -0
- package/src/components/autocomplete.jsx +347 -0
- package/src/components/avatar.jsx +160 -0
- package/src/components/box.jsx +165 -0
- package/src/components/button.jsx +104 -0
- package/src/components/card.jsx +156 -0
- package/src/components/checkbox.jsx +63 -0
- package/src/components/chip.jsx +137 -0
- package/src/components/collapse.jsx +188 -0
- package/src/components/container.jsx +67 -0
- package/src/components/date-picker.jsx +528 -0
- package/src/components/dialog-content-text.jsx +27 -0
- package/src/components/dialog.jsx +584 -0
- package/src/components/divider.jsx +192 -0
- package/src/components/drawer.jsx +255 -0
- package/src/components/form-control-label.jsx +89 -0
- package/src/components/form-group.jsx +32 -0
- package/src/components/form-label.jsx +54 -0
- package/src/components/grid.jsx +135 -0
- package/src/components/icon-button.jsx +101 -0
- package/src/components/index.js +78 -0
- package/src/components/input-adornment.jsx +43 -0
- package/src/components/input-label.jsx +55 -0
- package/src/components/list.jsx +239 -0
- package/src/components/menu.jsx +370 -0
- package/src/components/paper.jsx +173 -0
- package/src/components/radio-group.jsx +76 -0
- package/src/components/radio.jsx +108 -0
- package/src/components/select.jsx +308 -0
- package/src/components/slider.jsx +382 -0
- package/src/components/stack.jsx +110 -0
- package/src/components/table.jsx +243 -0
- package/src/components/tabs.jsx +363 -0
- package/src/components/text-field.jsx +289 -0
- package/src/components/toggle-button.jsx +209 -0
- package/src/components/toolbar.jsx +48 -0
- package/src/components/tooltip.jsx +127 -0
- package/src/components/typography.jsx +77 -0
- package/src/global-state.js +29 -0
- package/src/index.css +110 -0
- package/src/index.js +6 -0
- package/src/lib/useMediaQuery.js +37 -0
- package/src/lib/utils.js +113 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { cva } from "class-variance-authority";
|
|
3
|
+
import { cn } from "../lib/utils";
|
|
4
|
+
|
|
5
|
+
const typographyVariants = cva("", {
|
|
6
|
+
variants: {
|
|
7
|
+
variant: {
|
|
8
|
+
h1: "scroll-m-20 text-4xl font-extralight tracking-tight lg:text-5xl",
|
|
9
|
+
h2: "scroll-m-20 border-b pb-2 text-3xl font-semibold tracking-tight first:mt-0",
|
|
10
|
+
h3: "scroll-m-20 text-2xl font-semibold tracking-tight",
|
|
11
|
+
h4: "scroll-m-20 text-xl font-semibold tracking-tight",
|
|
12
|
+
h5: "scroll-m-20 text-lg font-semibold tracking-tight",
|
|
13
|
+
h6: "scroll-m-20 text-base font-semibold tracking-tight",
|
|
14
|
+
p: "leading-7 [&:not(:first-child)]:mt-6",
|
|
15
|
+
blockquote: "mt-6 border-l-2 pl-6 italic",
|
|
16
|
+
list: "my-6 ml-6 list-disc [&>li]:mt-2",
|
|
17
|
+
inlineCode:
|
|
18
|
+
"relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm font-semibold",
|
|
19
|
+
lead: "text-xl text-muted-foreground",
|
|
20
|
+
largeText: "text-lg font-semibold",
|
|
21
|
+
smallText: "text-sm font-medium leading-none",
|
|
22
|
+
mutedText: "text-sm text-muted-foreground",
|
|
23
|
+
// MUI compatibility variants
|
|
24
|
+
body1: "text-base leading-normal",
|
|
25
|
+
body2: "text-sm leading-normal",
|
|
26
|
+
subtitle1: "text-base font-normal leading-normal",
|
|
27
|
+
subtitle2: "text-sm font-medium leading-normal",
|
|
28
|
+
caption: "text-xs leading-normal",
|
|
29
|
+
overline: "text-xs font-normal uppercase leading-normal tracking-wide",
|
|
30
|
+
},
|
|
31
|
+
color: {
|
|
32
|
+
default: "text-foreground",
|
|
33
|
+
primary: "text-primary",
|
|
34
|
+
secondary: "text-secondary-foreground",
|
|
35
|
+
muted: "text-muted-foreground",
|
|
36
|
+
destructive: "text-destructive",
|
|
37
|
+
error: "text-destructive",
|
|
38
|
+
inherit: "text-inherit",
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
defaultVariants: {
|
|
42
|
+
variant: "body1",
|
|
43
|
+
color: "default",
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const Typography = React.forwardRef(
|
|
48
|
+
(
|
|
49
|
+
{ className, variant = "body1", component, style, color, ...props },
|
|
50
|
+
ref
|
|
51
|
+
) => {
|
|
52
|
+
// Map MUI color props to shadcn colors
|
|
53
|
+
const mappedColor =
|
|
54
|
+
color === "text.secondary" || color === "textSecondary"
|
|
55
|
+
? "muted"
|
|
56
|
+
: color === "text.primary" || color === "textPrimary"
|
|
57
|
+
? "default"
|
|
58
|
+
: color;
|
|
59
|
+
|
|
60
|
+
const Component = component || (variant.startsWith("h") ? variant : "p");
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<Component
|
|
64
|
+
ref={ref}
|
|
65
|
+
className={cn(
|
|
66
|
+
typographyVariants({ variant, color: mappedColor }),
|
|
67
|
+
className
|
|
68
|
+
)}
|
|
69
|
+
style={style}
|
|
70
|
+
{...props}
|
|
71
|
+
/>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
);
|
|
75
|
+
Typography.displayName = "Typography";
|
|
76
|
+
|
|
77
|
+
export { Typography, typographyVariants };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Simplified version for examples project
|
|
2
|
+
// In the real project, this would use Recoil for state management
|
|
3
|
+
// For examples, we'll use a simple React context or just return default values
|
|
4
|
+
|
|
5
|
+
import React from "react";
|
|
6
|
+
|
|
7
|
+
// Create a simple context for background type
|
|
8
|
+
const BackgroundTypeContext = React.createContext("solid");
|
|
9
|
+
|
|
10
|
+
export const BackgroundTypeProvider = ({ children, value = "solid" }) => {
|
|
11
|
+
return (
|
|
12
|
+
<BackgroundTypeContext.Provider value={value}>
|
|
13
|
+
{children}
|
|
14
|
+
</BackgroundTypeContext.Provider>
|
|
15
|
+
);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// Mock Recoil atom for background type
|
|
19
|
+
export const backgroundTypeState = {
|
|
20
|
+
key: "backgroundType",
|
|
21
|
+
default: "solid",
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// Mock useRecoilValue hook
|
|
25
|
+
export const useRecoilValue = (atom) => {
|
|
26
|
+
const context = React.useContext(BackgroundTypeContext);
|
|
27
|
+
return context || atom.default || "solid";
|
|
28
|
+
};
|
|
29
|
+
|
package/src/index.css
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/* Tailwind CSS will be imported here */
|
|
2
|
+
@tailwind base;
|
|
3
|
+
@tailwind components;
|
|
4
|
+
@tailwind utilities;
|
|
5
|
+
|
|
6
|
+
@layer base {
|
|
7
|
+
:root {
|
|
8
|
+
--background: 0 0% 100%;
|
|
9
|
+
--foreground: 222.2 84% 4.9%;
|
|
10
|
+
--card: 0 0% 100%;
|
|
11
|
+
--card-foreground: 222.2 84% 4.9%;
|
|
12
|
+
--popover: 0 0% 100%;
|
|
13
|
+
--popover-foreground: 222.2 84% 4.9%;
|
|
14
|
+
--primary: 221.2 83.2% 53.3%;
|
|
15
|
+
--primary-foreground: 210 40% 98%;
|
|
16
|
+
--secondary: 210 40% 96.1%;
|
|
17
|
+
--secondary-foreground: 222.2 47.4% 11.2%;
|
|
18
|
+
--muted: 210 40% 96.1%;
|
|
19
|
+
--muted-foreground: 215.4 16.3% 46.9%;
|
|
20
|
+
--accent: 210 40% 96.1%;
|
|
21
|
+
--accent-foreground: 222.2 47.4% 11.2%;
|
|
22
|
+
--destructive: 0 84.2% 60.2%;
|
|
23
|
+
--destructive-foreground: 210 40% 98%;
|
|
24
|
+
--success: 142.1 76.2% 36.3%;
|
|
25
|
+
--success-foreground: 210 40% 98%;
|
|
26
|
+
--warning: 38.9 92% 50%;
|
|
27
|
+
--warning-foreground: 210 40% 98%;
|
|
28
|
+
--info: 199.1 89.1% 48.2%;
|
|
29
|
+
--info-foreground: 210 40% 98%;
|
|
30
|
+
--border: 214.3 31.8% 91.4%;
|
|
31
|
+
--input: 214.3 31.8% 91.4%;
|
|
32
|
+
--ring: 222.2 84% 4.9%;
|
|
33
|
+
--radius: 0.5rem;
|
|
34
|
+
|
|
35
|
+
/* Z-index variables */
|
|
36
|
+
--z-index-mobile-stepper: 1000;
|
|
37
|
+
--z-index-fab: 1050;
|
|
38
|
+
--z-index-speed-dial: 1050;
|
|
39
|
+
--z-index-app-bar: 1100;
|
|
40
|
+
--z-index-drawer: 1200;
|
|
41
|
+
--z-index-modal: 1300;
|
|
42
|
+
--z-index-snackbar: 1400;
|
|
43
|
+
--z-index-tooltip: 1500;
|
|
44
|
+
--z-index-automation-drawer: 1200;
|
|
45
|
+
--z-index-automation-input: 1300;
|
|
46
|
+
--z-index-important-toast: 1400;
|
|
47
|
+
--z-index-dashboard-input: 1300;
|
|
48
|
+
--z-index-dashboard-drag: 1300;
|
|
49
|
+
--z-index-snackbar-input: 1400;
|
|
50
|
+
|
|
51
|
+
/* Background level colors (simplified) */
|
|
52
|
+
--color-background-logo1: #ffffff;
|
|
53
|
+
--color-background-logo2: #000000;
|
|
54
|
+
--color-background-l0: hsl(var(--background));
|
|
55
|
+
--color-background-l1: hsl(var(--card));
|
|
56
|
+
--color-background-l2: hsl(var(--muted));
|
|
57
|
+
--color-background-l3: hsl(var(--accent));
|
|
58
|
+
--color-background-l4: hsl(var(--muted));
|
|
59
|
+
--color-background-l5: hsl(var(--muted));
|
|
60
|
+
--color-background-l6: hsl(var(--muted));
|
|
61
|
+
--color-background-c0: hsl(var(--background));
|
|
62
|
+
--color-background-c1: hsl(var(--card));
|
|
63
|
+
--color-background-c2: hsl(var(--muted));
|
|
64
|
+
--color-background-c3: hsl(var(--accent));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.dark {
|
|
68
|
+
--background: 222.2 84% 4.9%;
|
|
69
|
+
--foreground: 210 40% 98%;
|
|
70
|
+
--card: 222.2 84% 4.9%;
|
|
71
|
+
--card-foreground: 210 40% 98%;
|
|
72
|
+
--popover: 222.2 84% 4.9%;
|
|
73
|
+
--popover-foreground: 210 40% 98%;
|
|
74
|
+
--primary: 221.2 83.2% 53.3%;
|
|
75
|
+
--primary-foreground: 210 40% 98%;
|
|
76
|
+
--secondary: 217.2 32.6% 17.5%;
|
|
77
|
+
--secondary-foreground: 210 40% 98%;
|
|
78
|
+
--muted: 217.2 32.6% 17.5%;
|
|
79
|
+
--muted-foreground: 215 20.2% 65.1%;
|
|
80
|
+
--accent: 217.2 32.6% 17.5%;
|
|
81
|
+
--accent-foreground: 210 40% 98%;
|
|
82
|
+
--destructive: 0 62.8% 30.6%;
|
|
83
|
+
--destructive-foreground: 210 40% 98%;
|
|
84
|
+
--success: 142.1 70.6% 45.3%;
|
|
85
|
+
--success-foreground: 210 40% 98%;
|
|
86
|
+
--warning: 38.9 92% 50%;
|
|
87
|
+
--warning-foreground: 210 40% 98%;
|
|
88
|
+
--info: 199.1 89.1% 48.2%;
|
|
89
|
+
--info-foreground: 210 40% 98%;
|
|
90
|
+
--border: 217.2 32.6% 17.5%;
|
|
91
|
+
--input: 217.2 32.6% 17.5%;
|
|
92
|
+
--ring: 212.7 26.8% 83.9%;
|
|
93
|
+
|
|
94
|
+
/* Background level colors for dark mode */
|
|
95
|
+
--color-background-logo1: #000000;
|
|
96
|
+
--color-background-logo2: #ffffff;
|
|
97
|
+
--color-background-l0: hsl(var(--background));
|
|
98
|
+
--color-background-l1: hsl(var(--card));
|
|
99
|
+
--color-background-l2: hsl(var(--muted));
|
|
100
|
+
--color-background-l3: hsl(var(--accent));
|
|
101
|
+
--color-background-l4: hsl(var(--muted));
|
|
102
|
+
--color-background-l5: hsl(var(--muted));
|
|
103
|
+
--color-background-l6: hsl(var(--muted));
|
|
104
|
+
--color-background-c0: hsl(var(--background));
|
|
105
|
+
--color-background-c1: hsl(var(--card));
|
|
106
|
+
--color-background-c2: hsl(var(--muted));
|
|
107
|
+
--color-background-c3: hsl(var(--accent));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
package/src/index.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { useState, useEffect } from "react";
|
|
2
|
+
|
|
3
|
+
// Simplified useMediaQuery hook to replace @mui/material's useMediaQuery
|
|
4
|
+
export const useMediaQuery = (query) => {
|
|
5
|
+
const [matches, setMatches] = useState(false);
|
|
6
|
+
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
// Extract media query from MUI format or use directly
|
|
9
|
+
let mediaQueryString = query;
|
|
10
|
+
|
|
11
|
+
// Handle MUI format: "@media (max-width:599px)"
|
|
12
|
+
if (query.startsWith("@media")) {
|
|
13
|
+
mediaQueryString = query.replace("@media", "").trim();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const mediaQuery = window.matchMedia(mediaQueryString);
|
|
17
|
+
|
|
18
|
+
// Set initial value
|
|
19
|
+
setMatches(mediaQuery.matches);
|
|
20
|
+
|
|
21
|
+
// Create event listener
|
|
22
|
+
const handler = (event) => {
|
|
23
|
+
setMatches(event.matches);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// Add listener
|
|
27
|
+
mediaQuery.addEventListener("change", handler);
|
|
28
|
+
|
|
29
|
+
// Cleanup
|
|
30
|
+
return () => {
|
|
31
|
+
mediaQuery.removeEventListener("change", handler);
|
|
32
|
+
};
|
|
33
|
+
}, [query]);
|
|
34
|
+
|
|
35
|
+
return matches;
|
|
36
|
+
};
|
|
37
|
+
|
package/src/lib/utils.js
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { clsx } from "clsx";
|
|
3
|
+
import { twMerge } from "tailwind-merge";
|
|
4
|
+
|
|
5
|
+
export function cn(...inputs) {
|
|
6
|
+
return twMerge(clsx(inputs));
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// Convert MUI spacing unit to pixels (MUI spacing unit = 8px)
|
|
10
|
+
export function spacingToPx(value) {
|
|
11
|
+
if (typeof value === "number") {
|
|
12
|
+
return `${value * 8}px`;
|
|
13
|
+
}
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Helper function to convert MUI sx prop to style object
|
|
18
|
+
export const convertSxToStyle = (sx) => {
|
|
19
|
+
if (!sx) return {};
|
|
20
|
+
const style = {};
|
|
21
|
+
for (const key in sx) {
|
|
22
|
+
if (Object.prototype.hasOwnProperty.call(sx, key)) {
|
|
23
|
+
const value = sx[key];
|
|
24
|
+
// Handle spacing values
|
|
25
|
+
if (
|
|
26
|
+
typeof value === "number" &&
|
|
27
|
+
[
|
|
28
|
+
"p",
|
|
29
|
+
"px",
|
|
30
|
+
"py",
|
|
31
|
+
"pt",
|
|
32
|
+
"pb",
|
|
33
|
+
"pl",
|
|
34
|
+
"pr",
|
|
35
|
+
"m",
|
|
36
|
+
"mx",
|
|
37
|
+
"my",
|
|
38
|
+
"mt",
|
|
39
|
+
"mb",
|
|
40
|
+
"ml",
|
|
41
|
+
"mr",
|
|
42
|
+
"gap",
|
|
43
|
+
].includes(key)
|
|
44
|
+
) {
|
|
45
|
+
const cssProp = {
|
|
46
|
+
p: "padding",
|
|
47
|
+
px: ["paddingLeft", "paddingRight"],
|
|
48
|
+
py: ["paddingTop", "paddingBottom"],
|
|
49
|
+
pt: "paddingTop",
|
|
50
|
+
pb: "paddingBottom",
|
|
51
|
+
pl: "paddingLeft",
|
|
52
|
+
pr: "paddingRight",
|
|
53
|
+
m: "margin",
|
|
54
|
+
mx: ["marginLeft", "marginRight"],
|
|
55
|
+
my: ["marginTop", "marginBottom"],
|
|
56
|
+
mt: "marginTop",
|
|
57
|
+
mb: "marginBottom",
|
|
58
|
+
ml: "marginLeft",
|
|
59
|
+
mr: "marginRight",
|
|
60
|
+
gap: "gap",
|
|
61
|
+
}[key];
|
|
62
|
+
|
|
63
|
+
if (Array.isArray(cssProp)) {
|
|
64
|
+
cssProp.forEach((prop) => (style[prop] = spacingToPx(value)));
|
|
65
|
+
} else {
|
|
66
|
+
style[cssProp] = spacingToPx(value);
|
|
67
|
+
}
|
|
68
|
+
} else if (key === "bgcolor") {
|
|
69
|
+
// Handle bgcolor - convert theme paths to CSS variables
|
|
70
|
+
if (typeof value === "string" && value.includes(".")) {
|
|
71
|
+
const bgcolorMap = {
|
|
72
|
+
"background.paper": "hsl(var(--card))",
|
|
73
|
+
"background.default": "hsl(var(--background))",
|
|
74
|
+
"background.card": "hsl(var(--card))",
|
|
75
|
+
};
|
|
76
|
+
style.backgroundColor = bgcolorMap[value] || value;
|
|
77
|
+
} else {
|
|
78
|
+
style.backgroundColor = value;
|
|
79
|
+
}
|
|
80
|
+
} else {
|
|
81
|
+
style[key] = value;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return style;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// Hook to detect dark mode by checking document class
|
|
89
|
+
export const useIsDarkMode = () => {
|
|
90
|
+
const [isDark, setIsDark] = React.useState(() => {
|
|
91
|
+
if (typeof document !== "undefined") {
|
|
92
|
+
return document.documentElement.classList.contains("dark");
|
|
93
|
+
}
|
|
94
|
+
return false;
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
React.useEffect(() => {
|
|
98
|
+
if (typeof document === "undefined") return;
|
|
99
|
+
|
|
100
|
+
const observer = new MutationObserver(() => {
|
|
101
|
+
setIsDark(document.documentElement.classList.contains("dark"));
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
observer.observe(document.documentElement, {
|
|
105
|
+
attributes: true,
|
|
106
|
+
attributeFilter: ["class"],
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
return () => observer.disconnect();
|
|
110
|
+
}, []);
|
|
111
|
+
|
|
112
|
+
return isDark ? "dark" : "light";
|
|
113
|
+
};
|