项目文件夹

文件
wehub-resource-sync bb5c75ce05
Component Security Validation / Security Audit (push) Has been cancelled
Deploy to Cloudflare Pages / deploy (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:38:58 +08:00

1 行
10 KiB
JSON

{"content": "---\nname: mui\ndescription: Material-UI v7 component library patterns including sx prop styling, theme integration, responsive design, and MUI-specific hooks. Use when working with MUI components, styling with sx prop, theme customization, or MUI utilities.\n---\n\n# MUI v7 Patterns\n\n## Purpose\n\nMaterial-UI v7 (released March 2025) patterns for component usage, styling with sx prop, theme integration, and responsive design.\n\n**Note**: MUI v7 breaking changes from v6:\n- Deep imports no longer work - use package exports field\n- `onBackdropClick` removed from Modal - use `onClose` instead\n- All components now use standardized `slots` and `slotProps` pattern\n- CSS layers support via `enableCssLayer` config (works with Tailwind v4)\n\n## When to Use This Skill\n\n- Styling components with MUI sx prop\n- Using MUI components (Box, Grid, Paper, Typography, etc.)\n- Theme customization and usage\n- Responsive design with MUI breakpoints\n- MUI-specific utilities and hooks\n\n---\n\n## Quick Start\n\n### Basic MUI Component\n\n```typescript\nimport { Box, Typography, Button, Paper } from '@mui/material';\nimport type { SxProps, Theme } from '@mui/material';\n\nconst styles: Record<string, SxProps<Theme>> = {\n container: {\n p: 2,\n display: 'flex',\n flexDirection: 'column',\n gap: 2,\n },\n header: {\n mb: 3,\n fontSize: '1.5rem',\n fontWeight: 600,\n },\n};\n\nfunction MyComponent() {\n return (\n <Paper sx={styles.container}>\n <Typography sx={styles.header}>\n Title\n </Typography>\n <Button variant=\"contained\">\n Action\n </Button>\n </Paper>\n );\n}\n```\n\n---\n\n## Styling Patterns\n\n### Inline Styles (< 100 lines)\n\nFor components with simple styling, define styles at the top:\n\n```typescript\nimport type { SxProps, Theme } from '@mui/material';\n\nconst componentStyles: Record<string, SxProps<Theme>> = {\n container: {\n p: 2,\n display: 'flex',\n flexDirection: 'column',\n },\n header: {\n mb: 2,\n color: 'primary.main',\n },\n button: {\n mt: 'auto',\n alignSelf: 'flex-end',\n },\n};\n\nfunction Component() {\n return (\n <Box sx={componentStyles.container}>\n <Typography sx={componentStyles.header}>Header</Typography>\n <Button sx={componentStyles.button}>Action</Button>\n </Box>\n );\n}\n```\n\n### Separate Styles File (>= 100 lines)\n\nFor complex components, create separate style file:\n\n```typescript\n// UserProfile.styles.ts\nimport type { SxProps, Theme } from '@mui/material';\n\nexport const userProfileStyles: Record<string, SxProps<Theme>> = {\n container: {\n p: 3,\n maxWidth: 800,\n mx: 'auto',\n },\n header: {\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'center',\n mb: 3,\n },\n // ... many more styles\n};\n\n// UserProfile.tsx\nimport { userProfileStyles as styles } from './UserProfile.styles';\n\nfunction UserProfile() {\n return <Box sx={styles.container}>...</Box>;\n}\n```\n\n---\n\n## Common Components\n\n### Layout Components\n\n```typescript\n// Box - Generic container\n<Box sx={{ p: 2, bgcolor: 'background.paper' }}>\n Content\n</Box>\n\n// Paper - Elevated surface\n<Paper elevation={2} sx={{ p: 3 }}>\n Content\n</Paper>\n\n// Container - Centered content with max-width\n<Container maxWidth=\"lg\">\n Content\n</Container>\n\n// Stack - Flex container with spacing\n<Stack spacing={2} direction=\"row\">\n <Item />\n <Item />\n</Stack>\n```\n\n### Grid System\n\n```typescript\nimport { Grid } from '@mui/material';\n\n// 12-column grid\n<Grid container spacing={2}>\n <Grid item xs={12} md={6}>\n Left half\n </Grid>\n <Grid item xs={12} md={6}>\n Right half\n </Grid>\n</Grid>\n\n// Responsive grid\n<Grid container spacing={3}>\n <Grid item xs={12} sm={6} md={4} lg={3}>\n Card\n </Grid>\n {/* Repeat for more cards */}\n</Grid>\n```\n\n### Typography\n\n```typescript\n<Typography variant=\"h1\">Heading 1</Typography>\n<Typography variant=\"h2\">Heading 2</Typography>\n<Typography variant=\"body1\">Body text</Typography>\n<Typography variant=\"caption\">Small text</Typography>\n\n// With custom styling\n<Typography\n variant=\"h4\"\n sx={{\n color: 'primary.main',\n fontWeight: 600,\n mb: 2,\n }}\n>\n Custom Heading\n</Typography>\n```\n\n### Buttons\n\n```typescript\n// Variants\n<Button variant=\"contained\">Contained</Button>\n<Button variant=\"outlined\">Outlined</Button>\n<Button variant=\"text\">Text</Button>\n\n// Colors\n<Button variant=\"contained\" color=\"primary\">Primary</Button>\n<Button variant=\"contained\" color=\"secondary\">Secondary</Button>\n<Button variant=\"contained\" color=\"error\">Error</Button>\n\n// With icons\nimport { Add as AddIcon } from '@mui/icons-material';\n\n<Button startIcon={<AddIcon />}>Add Item</Button>\n```\n\n---\n\n## Theme Integration\n\n### Using Theme Values\n\n```typescript\nimport { useTheme } from '@mui/material';\n\nfunction Component() {\n const theme = useTheme();\n\n return (\n <Box\n sx={{\n p: 2,\n bgcolor: theme.palette.primary.main,\n color: theme.palette.primary.contrastText,\n borderRadius: theme.shape.borderRadius,\n }}\n >\n Themed box\n </Box>\n );\n}\n```\n\n### Theme in sx Prop\n\n```typescript\n<Box\n sx={{\n // Access theme in sx\n color: 'primary.main', // theme.palette.primary.main\n bgcolor: 'background.paper', // theme.palette.background.paper\n p: 2, // theme.spacing(2)\n borderRadius: 1, // theme.shape.borderRadius\n }}\n>\n Content\n</Box>\n\n// Callback for advanced usage\n<Box\n sx={(theme) => ({\n color: theme.palette.primary.main,\n '&:hover': {\n color: theme.palette.primary.dark,\n },\n })}\n>\n Hover me\n</Box>\n```\n\n---\n\n## Responsive Design\n\n### Breakpoints\n\n```typescript\n// Mobile-first responsive values\n<Box\n sx={{\n width: {\n xs: '100%', // 0-600px\n sm: '80%', // 600-900px\n md: '60%', // 900-1200px\n lg: '40%', // 1200-1536px\n xl: '30%', // 1536px+\n },\n }}\n>\n Responsive width\n</Box>\n\n// Responsive display\n<Box\n sx={{\n display: {\n xs: 'none', // Hidden on mobile\n md: 'block', // Visible on desktop\n },\n }}\n>\n Desktop only\n</Box>\n```\n\n### Responsive Typography\n\n```typescript\n<Typography\n sx={{\n fontSize: {\n xs: '1rem',\n md: '1.5rem',\n lg: '2rem',\n },\n lineHeight: {\n xs: 1.5,\n md: 1.75,\n },\n }}\n>\n Responsive text\n</Typography>\n```\n\n---\n\n## Forms\n\n```typescript\nimport { TextField, Stack, Button } from '@mui/material';\n\n<Box component=\"form\" onSubmit={handleSubmit}>\n <Stack spacing={2}>\n <TextField\n label=\"Email\"\n type=\"email\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n fullWidth\n required\n error={!!errors.email}\n helperText={errors.email}\n />\n <Button type=\"submit\" variant=\"contained\">Submit</Button>\n </Stack>\n</Box>\n```\n\n---\n\n## Common Patterns\n\n### Card Component\n\n```typescript\nimport { Card, CardContent, CardActions, Typography, Button } from '@mui/material';\n\n<Card>\n <CardContent>\n <Typography variant=\"h5\" component=\"div\">\n Title\n </Typography>\n <Typography variant=\"body2\" color=\"text.secondary\">\n Description\n </Typography>\n </CardContent>\n <CardActions>\n <Button size=\"small\">Learn More</Button>\n </CardActions>\n</Card>\n```\n\n### Dialog/Modal\n\n```typescript\nimport { Dialog, DialogTitle, DialogContent, DialogActions, Button } from '@mui/material';\n\n<Dialog open={open} onClose={handleClose}>\n <DialogTitle>Confirm Action</DialogTitle>\n <DialogContent>\n Are you sure you want to proceed?\n </DialogContent>\n <DialogActions>\n <Button onClick={handleClose}>Cancel</Button>\n <Button onClick={handleConfirm} variant=\"contained\">\n Confirm\n </Button>\n </DialogActions>\n</Dialog>\n```\n\n### Loading States\n\n```typescript\nimport { CircularProgress, Skeleton } from '@mui/material';\n\n// Spinner\n<Box sx={{ display: 'flex', justifyContent: 'center', p: 3 }}>\n <CircularProgress />\n</Box>\n\n// Skeleton\n<Stack spacing={1}>\n <Skeleton variant=\"text\" width=\"60%\" />\n <Skeleton variant=\"rectangular\" height={200} />\n <Skeleton variant=\"text\" width=\"40%\" />\n</Stack>\n```\n\n---\n\n## MUI-Specific Hooks\n\n### useMuiSnackbar\n\n```typescript\nimport { useMuiSnackbar } from '@/hooks/useMuiSnackbar';\n\nfunction Component() {\n const { showSuccess, showError, showInfo } = useMuiSnackbar();\n\n const handleSave = async () => {\n try {\n await saveData();\n showSuccess('Saved successfully');\n } catch (error) {\n showError('Failed to save');\n }\n };\n\n return <Button onClick={handleSave}>Save</Button>;\n}\n```\n\n---\n\n## Icons\n\n```typescript\nimport { Add as AddIcon, Delete as DeleteIcon } from '@mui/icons-material';\nimport { Button, IconButton } from '@mui/material';\n\n<Button startIcon={<AddIcon />}>Add</Button>\n<IconButton onClick={handleDelete}><DeleteIcon /></IconButton>\n```\n\n---\n\n## Best Practices\n\n### 1. Type Your sx Props\n\n```typescript\nimport type { SxProps, Theme } from '@mui/material';\n\n// ✅ Good\nconst styles: Record<string, SxProps<Theme>> = {\n container: { p: 2 },\n};\n\n// ❌ Avoid\nconst styles = {\n container: { p: 2 }, // No type safety\n};\n```\n\n### 2. Use Theme Tokens\n\n```typescript\n// ✅ Good: Use theme tokens\n<Box sx={{ color: 'primary.main', p: 2 }} />\n\n// ❌ Avoid: Hardcoded values\n<Box sx={{ color: '#1976d2', padding: '16px' }} />\n```\n\n### 3. Consistent Spacing\n\n```typescript\n// ✅ Good: Use spacing scale\n<Box sx={{ p: 2, mb: 3, mt: 1 }} />\n\n// ❌ Avoid: Random pixel values\n<Box sx={{ padding: '17px', marginBottom: '25px' }} />\n```\n\n---\n\n## Additional Resources\n\nFor more detailed patterns, see:\n- [styling-guide.md](resources/styling-guide.md) - Advanced styling patterns\n- [component-library.md](resources/component-library.md) - Component examples\n- [theme-customization.md](resources/theme-customization.md) - Theme setup\n"}