diff --git a/sources/opencode/skills/material-ui/SKILL.md b/sources/opencode/skills/material-ui/SKILL.md new file mode 100644 index 0000000..996e2bd --- /dev/null +++ b/sources/opencode/skills/material-ui/SKILL.md @@ -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 ; +} +``` + +## Required Globals + +Add to your app: +```tsx +import { CssBaseline, ThemeProvider } from '@mui/material'; +``` + +Viewport meta tag: +```html + +``` + +## 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 ( + + + {children} + + ); +} +``` + +### 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 ( + + + + + ); +} +``` + +**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 ( + + + + My App + + + {modeRaw === 'dark' ? : modeRaw === 'light' ? : } + + + + ); +} +``` + +**5. Use in any component:** +```tsx +import { useMode } from './hooks/useMode'; +import { Box, Typography } from '@mui/material'; + +function Dashboard() { + const { isDark, mode } = useMode(); + + return ( + + Current mode: {mode} + + ); +} +``` + +## Customization + +### 1. One-off: sx Prop + +```tsx + +``` + +### 2. Nested Styles + +```tsx + +``` + +### 3. Reusable: styled() + +```tsx +import Slider, { SliderProps } from '@mui/material/Slider'; +import { styled } from '@mui/material/styles'; + +const SuccessSlider = styled(Slider)(({ theme }) => ({ + color: theme.palette.success.main, +})); +``` + +### 4. Dynamic Props + +```tsx +interface CustomSliderProps extends SliderProps { + success?: boolean; +} + +const StyledSlider = styled(Slider, { + shouldForwardProp: (prop) => prop !== 'success', +})(({ 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 + +``` + +### Responsive Design + +```tsx + +``` + +### Grid (v2 - now just Grid) + +```tsx +import Grid from '@mui/material/Grid'; + + + Content + +``` + +### Stack (Preferred over Box for Simple Layouts) + +```tsx + + + + +``` + +## 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 +