mirror of
https://github.com/aminnairi/dotfiles.git
synced 2026-09-14 11:02:13 +02:00
configuration for the material ui skill using opencode
This commit is contained in:
@@ -0,0 +1,442 @@
|
|||||||
|
---
|
||||||
|
name: material-ui
|
||||||
|
description: Material-UI (MUI) v7 React component library - components, theming, customization, best practices
|
||||||
|
metadata:
|
||||||
|
language: typescript
|
||||||
|
audience: developers
|
||||||
|
---
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Material-UI (MUI) v7 is the latest version of the popular React component library implementing Google's Material Design. Use this skill when working with MUI components.
|
||||||
|
|
||||||
|
**Current Version:** v7.3.9
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install @mui/material @emotion/react @emotion/styled
|
||||||
|
```
|
||||||
|
|
||||||
|
### Peer Dependencies
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||||
|
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Icons
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install @mui/icons-material
|
||||||
|
```
|
||||||
|
|
||||||
|
### Roboto Font
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install @fontsource/roboto
|
||||||
|
```
|
||||||
|
|
||||||
|
Import in entry point:
|
||||||
|
```tsx
|
||||||
|
import '@fontsource/roboto/300.css';
|
||||||
|
import '@fontsource/roboto/400.css';
|
||||||
|
import '@fontsource/roboto/500.css';
|
||||||
|
import '@fontsource/roboto/700.css';
|
||||||
|
```
|
||||||
|
|
||||||
|
### React 18 and Below
|
||||||
|
|
||||||
|
If using React 18 or below, set `react-is` override:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"overrides": {
|
||||||
|
"react-is": "^18.3.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quickstart
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import Button from '@mui/material/Button';
|
||||||
|
|
||||||
|
export default function App() {
|
||||||
|
return <Button variant="contained">Hello World</Button>;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Required Globals
|
||||||
|
|
||||||
|
Add to your app:
|
||||||
|
```tsx
|
||||||
|
import { CssBaseline, ThemeProvider } from '@mui/material';
|
||||||
|
```
|
||||||
|
|
||||||
|
Viewport meta tag:
|
||||||
|
```html
|
||||||
|
<meta name="viewport" content="initial-scale=1, width=device-width" />
|
||||||
|
```
|
||||||
|
|
||||||
|
## Theming
|
||||||
|
|
||||||
|
### Create Theme
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { createTheme } from '@mui/material/styles';
|
||||||
|
|
||||||
|
const theme = createTheme({
|
||||||
|
palette: {
|
||||||
|
mode: 'dark',
|
||||||
|
primary: { main: '#1976d2' },
|
||||||
|
secondary: { main: '#dc004e' },
|
||||||
|
},
|
||||||
|
typography: {
|
||||||
|
fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif',
|
||||||
|
},
|
||||||
|
spacing: 8,
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Apply Theme
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { ThemeProvider, CssBaseline } from '@mui/material';
|
||||||
|
|
||||||
|
function App({ children }) {
|
||||||
|
return (
|
||||||
|
<ThemeProvider theme={theme}>
|
||||||
|
<CssBaseline />
|
||||||
|
{children}
|
||||||
|
</ThemeProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Dark Mode with CSS Variables
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
const theme = createTheme({
|
||||||
|
cssVariables: {
|
||||||
|
colorSchemeSelector: 'class',
|
||||||
|
},
|
||||||
|
colorSchemes: {
|
||||||
|
light: true,
|
||||||
|
dark: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Use `theme.vars.*` for CSS variables:
|
||||||
|
```tsx
|
||||||
|
const StyledDiv = styled('div')(({ theme }) => ({
|
||||||
|
color: theme.vars.palette.text.primary,
|
||||||
|
}));
|
||||||
|
```
|
||||||
|
|
||||||
|
### Color Scheme with useColorScheme
|
||||||
|
|
||||||
|
MUI v7 provides `useColorScheme` hook to manage color modes (light/dark/system) without explicit state management. Pair with a custom `useMode` hook for cleaner separation of concerns.
|
||||||
|
|
||||||
|
**1. Create the theme with color schemes:**
|
||||||
|
```tsx
|
||||||
|
import { createTheme } from '@mui/material/styles';
|
||||||
|
|
||||||
|
const theme = createTheme({
|
||||||
|
cssVariables: {
|
||||||
|
colorSchemeSelector: 'class',
|
||||||
|
},
|
||||||
|
colorSchemes: {
|
||||||
|
light: true,
|
||||||
|
dark: true,
|
||||||
|
},
|
||||||
|
palette: {
|
||||||
|
primary: { main: '#1976d2' },
|
||||||
|
secondary: { main: '#dc004e' },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
**2. Wrap your app with ThemeProvider:**
|
||||||
|
```tsx
|
||||||
|
import { ThemeProvider, CssBaseline } from '@mui/material';
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
return (
|
||||||
|
<ThemeProvider theme={theme}>
|
||||||
|
<CssBaseline />
|
||||||
|
<YourApp />
|
||||||
|
</ThemeProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**3. Create a useMode hook for cleaner access:**
|
||||||
|
```tsx
|
||||||
|
// hooks/useMode.ts
|
||||||
|
import { useColorScheme } from '@mui/material/styles';
|
||||||
|
|
||||||
|
type Mode = 'light' | 'dark' | 'system';
|
||||||
|
|
||||||
|
export function useMode() {
|
||||||
|
const { mode, setMode, systemMode } = useColorScheme();
|
||||||
|
|
||||||
|
return {
|
||||||
|
mode: mode === 'system' ? systemMode : mode,
|
||||||
|
modeRaw: mode,
|
||||||
|
setMode,
|
||||||
|
isDark: (mode === 'system' ? systemMode : mode) === 'dark',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**4. Use in your TopBar component:**
|
||||||
|
```tsx
|
||||||
|
import { AppBar, Toolbar, Typography, IconButton } from '@mui/material';
|
||||||
|
import { useMode } from './hooks/useMode';
|
||||||
|
import LightMode from '@mui/icons-material/LightMode';
|
||||||
|
import DarkMode from '@mui/icons-material/DarkMode';
|
||||||
|
import SettingsBrightness from '@mui/icons-material/SettingsBrightness';
|
||||||
|
|
||||||
|
function TopBar() {
|
||||||
|
const { modeRaw, setMode } = useMode();
|
||||||
|
|
||||||
|
const cycleMode = () => {
|
||||||
|
const modes: Array<'light' | 'dark' | 'system'> = ['light', 'dark', 'system'];
|
||||||
|
const currentIndex = modes.indexOf(modeRaw);
|
||||||
|
setMode(modes[(currentIndex + 1) % modes.length]);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AppBar position="static">
|
||||||
|
<Toolbar>
|
||||||
|
<Typography variant="h6" component="div" sx={{ flexGrow: 1 }}>
|
||||||
|
My App
|
||||||
|
</Typography>
|
||||||
|
<IconButton color="inherit" onClick={cycleMode}>
|
||||||
|
{modeRaw === 'dark' ? <LightMode /> : modeRaw === 'light' ? <DarkMode /> : <SettingsBrightness />}
|
||||||
|
</IconButton>
|
||||||
|
</Toolbar>
|
||||||
|
</AppBar>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**5. Use in any component:**
|
||||||
|
```tsx
|
||||||
|
import { useMode } from './hooks/useMode';
|
||||||
|
import { Box, Typography } from '@mui/material';
|
||||||
|
|
||||||
|
function Dashboard() {
|
||||||
|
const { isDark, mode } = useMode();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box sx={{ bgcolor: isDark ? 'grey.900' : 'grey.100', p: 2 }}>
|
||||||
|
<Typography>Current mode: {mode}</Typography>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Customization
|
||||||
|
|
||||||
|
### 1. One-off: sx Prop
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
<Button sx={{ width: 300, bgcolor: 'success.main' }}>
|
||||||
|
Custom
|
||||||
|
</Button>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Nested Styles
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
<Slider sx={{ '& .MuiSlider-thumb': { borderRadius: 1 } }} />
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Reusable: styled()
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import Slider, { SliderProps } from '@mui/material/Slider';
|
||||||
|
import { styled } from '@mui/material/styles';
|
||||||
|
|
||||||
|
const SuccessSlider = styled(Slider)<SliderProps>(({ theme }) => ({
|
||||||
|
color: theme.palette.success.main,
|
||||||
|
}));
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Dynamic Props
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
interface CustomSliderProps extends SliderProps {
|
||||||
|
success?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const StyledSlider = styled(Slider, {
|
||||||
|
shouldForwardProp: (prop) => prop !== 'success',
|
||||||
|
})<CustomSliderProps>(({ success, theme }) => ({
|
||||||
|
...(success && { color: theme.palette.success.main }),
|
||||||
|
}));
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Global Theme Overrides
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
const theme = createTheme({
|
||||||
|
components: {
|
||||||
|
MuiButton: {
|
||||||
|
defaultProps: { disableElevation: true },
|
||||||
|
styleOverrides: {
|
||||||
|
root: { textTransform: 'none' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Component Patterns
|
||||||
|
|
||||||
|
### Slot Props (MUI v7 Standard)
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
<Accordion
|
||||||
|
slots={{ transition: CustomTransition }}
|
||||||
|
slotProps={{ transition: { unmountOnExit: true } }}
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Responsive Design
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
<Box sx={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: { xs: 'column', md: 'row' },
|
||||||
|
gap: { xs: 1, md: 2 },
|
||||||
|
}} />
|
||||||
|
```
|
||||||
|
|
||||||
|
### Grid (v2 - now just Grid)
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import Grid from '@mui/material/Grid';
|
||||||
|
|
||||||
|
<Grid container spacing={2}>
|
||||||
|
<Grid item xs={12} md={6}>Content</Grid>
|
||||||
|
</Grid>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Stack (Preferred over Box for Simple Layouts)
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
<Stack direction="row" spacing={2}>
|
||||||
|
<Button>One</Button>
|
||||||
|
<Button>Two</Button>
|
||||||
|
</Stack>
|
||||||
|
```
|
||||||
|
|
||||||
|
## State Classes
|
||||||
|
|
||||||
|
Use for hover, focus, disabled, selected states:
|
||||||
|
- `.Mui-active`, `.Mui-checked`, `.Mui-disabled`, `.Mui-error`, `.Mui-expanded`, `.Mui-focusVisible`, `.Mui-focused`, `.Mui-readOnly`, `.Mui-required`, `.Mui-selected`
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
<Button disabled className="CustomButton">
|
||||||
|
// Style: .CustomButton.Mui-disabled { ... }
|
||||||
|
```
|
||||||
|
|
||||||
|
## Migration to v7
|
||||||
|
|
||||||
|
### Key Changes
|
||||||
|
|
||||||
|
1. **Grid2 → Grid**: Use `import Grid from '@mui/material/Grid'`
|
||||||
|
2. **Lab components**: Import from `@mui/material` not `@mui/lab`
|
||||||
|
3. **createMuiTheme → createTheme**
|
||||||
|
4. **InputLabel size="normal" → size="medium"**
|
||||||
|
5. **Deep imports removed**: Use `import { createTheme } from '@mui/material/styles'`
|
||||||
|
6. **Hidden component removed**: Use `sx` prop or `useMediaQuery`
|
||||||
|
|
||||||
|
### Codemods
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx @mui/codemod v7.0.0/grid-props <path>
|
||||||
|
npx @mui/codemod v7.0.0/lab-removed-components <path>
|
||||||
|
npx @mui/codemod v7.0.0/input-label-size-normal-medium <path>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Icons
|
||||||
|
|
||||||
|
Import individually for tree-shaking:
|
||||||
|
```tsx
|
||||||
|
import Home from '@mui/icons-material/Home';
|
||||||
|
import Search from '@mui/icons-material/Search';
|
||||||
|
```
|
||||||
|
|
||||||
|
Use `sx` for sizing:
|
||||||
|
```tsx
|
||||||
|
<Home sx={{ fontSize: 24, color: 'primary.main' }} />
|
||||||
|
```
|
||||||
|
|
||||||
|
## Common Components
|
||||||
|
|
||||||
|
| Component | Use Case |
|
||||||
|
|-----------|----------|
|
||||||
|
| Box | Generic wrapper |
|
||||||
|
| Container | Page layout |
|
||||||
|
| Stack | Simple layouts |
|
||||||
|
| Grid | Complex layouts |
|
||||||
|
| Button | Actions |
|
||||||
|
| TextField | Form inputs |
|
||||||
|
| Card | Content containers |
|
||||||
|
| AppBar | Navigation headers |
|
||||||
|
| Drawer | Side navigation |
|
||||||
|
| Dialog | Modals |
|
||||||
|
| Table | Data grids |
|
||||||
|
| Chip | Tags/labels |
|
||||||
|
| Typography | Text styling |
|
||||||
|
| Avatar | User images |
|
||||||
|
| Alert | Notifications |
|
||||||
|
| Skeleton | Loading states |
|
||||||
|
| Menu | Dropdown menus |
|
||||||
|
| Tabs | Tab navigation |
|
||||||
|
| Stepper | Multi-step forms |
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. **Use Theme** - Define colors, typography, spacing globally
|
||||||
|
2. **Use sx for One-off** - Quick style overrides
|
||||||
|
3. **Use styled() for Reusable** - Create custom components
|
||||||
|
4. **Use Stack** - Prefer over Box for simple layouts
|
||||||
|
5. **Use Grid (v2)** - For complex responsive layouts
|
||||||
|
6. **Use CSS Variables** - For better dev tools and dark mode
|
||||||
|
7. **Use Slot Props** - MUI v7 standard for component customization
|
||||||
|
8. **TypeScript** - MUI v7 requires TypeScript 4.9+
|
||||||
|
9. **Test** - Use `@mui/internal/test-utils` for testing
|
||||||
|
10. **Top Bar with Color Scheme Switch** - Use AppBar with Toolbar, Typography for title, and useColorScheme hook for theme toggle
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { AppBar, Toolbar, Typography, IconButton } from '@mui/material';
|
||||||
|
import { useColorScheme } from '@mui/material/styles';
|
||||||
|
import LightMode from '@mui/icons-material/LightMode';
|
||||||
|
import DarkMode from '@mui/icons-material/DarkMode';
|
||||||
|
|
||||||
|
function TopBar() {
|
||||||
|
const { mode, setMode } = useColorScheme();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AppBar position="static">
|
||||||
|
<Toolbar>
|
||||||
|
<Typography variant="h6" component="div" sx={{ flexGrow: 1 }}>
|
||||||
|
My App
|
||||||
|
</Typography>
|
||||||
|
<IconButton color="inherit" onClick={() => setMode(mode === 'dark' ? 'light' : 'dark')}>
|
||||||
|
{mode === 'dark' ? <LightMode /> : <DarkMode />}
|
||||||
|
</IconButton>
|
||||||
|
</Toolbar>
|
||||||
|
</AppBar>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user