init project
Some checks failed
No response / noResponse (push) Has been cancelled
CI / Continuous releases (push) Has been cancelled
CI / test-dev (macos-latest) (push) Has been cancelled
CI / test-dev (ubuntu-latest) (push) Has been cancelled
CI / test-dev (windows-latest) (push) Has been cancelled
Maintenance / main (push) Has been cancelled
Scorecards supply-chain security / Scorecards analysis (push) Has been cancelled
CodeQL / Analyze (push) Has been cancelled

This commit is contained in:
how2ice
2025-12-12 14:26:25 +09:00
commit 005cf56baf
43188 changed files with 1079531 additions and 0 deletions

View File

@@ -0,0 +1,56 @@
# Visual regression testing
Visual regression tests are split into two parts:
1. The rendered UI (short: fixture)
2. Instrumentation of that UI
## Rendered UI
The composition of all tests happens in `./index.js`.
The rendered UI is either:
1. located inside a separate file in `./fixtures` and written as a React component.
Here is an [example](https://github.com/mui/material-ui/blob/814fb60bbd8e500517b2307b6a297a638838ca89/test/regressions/tests/Menu/SimpleMenuList.js#L6-L16) with the `Menu` component.
2. a demo from `docs/data`
By default all demos are included.
We exclude demos if they are redundant or flaky etc.
The logic for this exclusion is handled (like the composition) in `./index.js`
If you introduce new behavior, prefer adding a demo to the documentation to solve documentation and testing with one file.
If you're adding a new test prefer a new component instead of editing existing files since that might unknowingly alter existing tests.
## Instrumentation
### Manual
`pnpm test:regressions:dev` will build all fixtures and render an overview page that lists all fixtures.
This can be used to debug individual fixtures.
By default, a devtools-like view is shown that can be disabled by appending `#no-dev` to the URL, for example `http://localhost:5001/docs-customization-typography/CustomResponsiveFontSizes#no-dev` or forced by appending `#dev` to the URL, for example `http://localhost:5001/docs-customization-typography/CustomResponsiveFontSizes#dev`.
### Automatic
We're using [`playwright`](https://playwright.dev) to iterate over each fixture and take a screenshot.
It allows catching regressions like this one:
![before](/test/docs-regressions-before.png)
![diff](/test/docs-regressions-diff.png)
Screenshots are saved in `./screenshots/$BROWSER_NAME/`.
Each test tests only a single fixture.
A fixture can be loaded with `await renderFixture(fixturePath)`, for example `renderFixture('FocusTrap/OpenFocusTrap')`.
## Commands
For development `pnpm test:regressions:dev` and `pnpm test:regressions:run --watch` in separate terminals is recommended.
| command | description |
| :----------------------------- | :-------------------------------------------------------------------------------------------------------------------- |
| `pnpm test:regressions` | Full run |
| `pnpm test:regressions:dev` | Prepares the fixtures to be able to test in watchmode |
| `pnpm test:regressions:run` | Runs the tests (requires `pnpm test:regressions:dev` or `pnpm test:regressions:build`+`pnpm test:regressions:server`) |
| `pnpm test:regressions:build` | Builds the vite bundle for viewing the fixtures |
| `pnpm test:regressions:server` | Serves the fixture bundle. |

View File

@@ -0,0 +1,100 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import Box from '@mui/material/Box';
import GlobalStyles from '@mui/material/GlobalStyles';
import JoyBox from '@mui/joy/Box';
import { CssVarsProvider } from '@mui/joy/styles';
function TestViewer(props) {
const { children, path } = props;
// We're simulating `act(() => ReactDOM.render(children))`
// In the end children passive effects should've been flushed.
// React doesn't have any such guarantee outside of `act()` so we're approximating it.
const [ready, setReady] = React.useState(false);
React.useEffect(() => {
function handleFontsEvent(event) {
if (event.type === 'loading') {
setReady(false);
} else if (event.type === 'loadingdone') {
// Don't know if there could be multiple loaded events after we started loading multiple times.
// So make sure we're only ready if fonts are actually ready.
if (document.fonts.status === 'loaded') {
setReady(true);
}
}
}
document.fonts.addEventListener('loading', handleFontsEvent);
document.fonts.addEventListener('loadingdone', handleFontsEvent);
// In case the child triggered font fetching we're not ready yet.
// The fonts event handler will mark the test as ready on `loadingdone`
if (document.fonts.status === 'loaded') {
setReady(true);
}
return () => {
document.fonts.removeEventListener('loading', handleFontsEvent);
document.fonts.removeEventListener('loadingdone', handleFontsEvent);
};
}, []);
const viewerBoxSx = {
display: 'block',
p: 1,
};
return (
<React.Fragment>
<GlobalStyles
styles={{
html: {
WebkitFontSmoothing: 'antialiased', // Antialiasing.
MozOsxFontSmoothing: 'grayscale', // Antialiasing.
// Do the opposite of the docs in order to help catching issues.
boxSizing: 'content-box',
},
'*, *::before, *::after': {
boxSizing: 'inherit',
// Disable transitions to avoid flaky screenshots
transition: 'none !important',
animation: 'none !important',
},
body: {
margin: 0,
overflowX: 'hidden',
},
}}
/>
{path.startsWith('/docs-joy') ? (
<CssVarsProvider>
<JoyBox
aria-busy={!ready}
data-testid="testcase"
data-testpath={path}
sx={{ bgcolor: 'background.body', ...viewerBoxSx }}
>
{children}
</JoyBox>
</CssVarsProvider>
) : (
<Box
aria-busy={!ready}
data-testid="testcase"
data-testpath={path}
sx={{ bgcolor: 'background.default', ...viewerBoxSx }}
>
{children}
</Box>
)}
</React.Fragment>
);
}
TestViewer.propTypes = {
children: PropTypes.node.isRequired,
path: PropTypes.string.isRequired,
};
export default TestViewer;

View File

@@ -0,0 +1,21 @@
import * as React from 'react';
import Button from '@mui/material/Button';
import Typography from '@mui/material/Typography';
import Alert from '@mui/material/Alert';
import { Box } from '@mui/material';
export default function MultilineAlertWithAction() {
return (
<Box sx={{ width: 500 }}>
<Alert
action={
<Button color="inherit" size="small">
UNDO
</Button>
}
>
<Typography as="div">{'a'.repeat(500)}</Typography>
</Alert>
</Box>
);
}

View File

@@ -0,0 +1,19 @@
import * as React from 'react';
import Button from '@mui/material/Button';
import Typography from '@mui/material/Typography';
import Alert from '@mui/material/Alert';
export default function MultilineAlertWithAction() {
return (
<Alert
action={
<Button color="inherit" size="small">
UNDO
</Button>
}
>
<Typography as="div">This is the first line.</Typography>
<Typography as="div">This is the second line.</Typography>
</Alert>
);
}

View File

@@ -0,0 +1,32 @@
import * as React from 'react';
import { AppBar, Typography } from '@mui/material';
import { ThemeProvider, createTheme } from '@mui/material/styles';
const darkTheme = createTheme({
palette: {
mode: 'dark',
},
});
export default function Demo() {
return (
<div style={{ backgroundColor: '#ffefd5' }}>
<AppBar position="static">
<Typography>Light | Default</Typography>
</AppBar>
<ThemeProvider theme={darkTheme}>
<AppBar position="static">
<Typography>Dark | Default</Typography>
</AppBar>
</ThemeProvider>
<AppBar position="static" color="transparent">
<Typography>Light | Transparent</Typography>
</AppBar>
<ThemeProvider theme={darkTheme}>
<AppBar position="static" color="transparent">
<Typography>Dark | Transparent</Typography>
</AppBar>
</ThemeProvider>
</div>
);
}

View File

@@ -0,0 +1,14 @@
import * as React from 'react';
import { CssVarsProvider } from '@mui/joy/styles';
import AspectRatio from '@mui/joy/AspectRatio';
import Box from '@mui/joy/Box';
export default function VariantColorJoy() {
return (
<CssVarsProvider>
<Box sx={{ p: 2, bgcolor: 'red' }}>
<AspectRatio sx={{ borderRadius: 'xl', minWidth: 200 }} />
</Box>
</CssVarsProvider>
);
}

View File

@@ -0,0 +1,21 @@
import * as React from 'react';
import Autocomplete from '@mui/material/Autocomplete';
import TextField from '@mui/material/TextField';
export default function Demo() {
return (
<div style={{ width: 300 }}>
<Autocomplete
options={[]}
renderInput={(params) => (
<TextField
{...params}
variant="filled"
hiddenLabel
placeholder="Filled variant with hiddenLabel"
/>
)}
/>
</div>
);
}

View File

@@ -0,0 +1,109 @@
import * as React from 'react';
import Stack from '@mui/material/Stack';
import Chip from '@mui/material/Chip';
import Autocomplete from '@mui/material/Autocomplete';
import TextField from '@mui/material/TextField';
const movies = [
{
title: 'The Lord of the Rings: The Two Towers',
year: 2002,
},
];
export default function Sizes() {
return (
<Stack spacing={2} sx={{ width: 300 }}>
<Autocomplete
id="size-small-outlined"
size="small"
options={movies}
getOptionLabel={(option) => option.title}
defaultValue={movies[0]}
disableClearable
renderInput={(params) => <TextField {...params} label="Movie" placeholder="Favorites" />}
/>
<Autocomplete
multiple
id="size-small-outlined-multi"
size="small"
options={movies}
getOptionLabel={(option) => option.title}
defaultValue={[movies[0]]}
disableClearable
renderInput={(params) => <TextField {...params} label="Movie" placeholder="Favorites" />}
/>
<Autocomplete
id="size-small-outlined"
size="small"
options={movies}
getOptionLabel={(option) => option.title}
defaultValue={movies[0]}
renderInput={(params) => <TextField {...params} label="Movie" placeholder="Favorites" />}
/>
<Autocomplete
multiple
id="size-small-outlined-multi"
size="small"
options={movies}
getOptionLabel={(option) => option.title}
defaultValue={[movies[0]]}
renderInput={(params) => <TextField {...params} label="Movie" placeholder="Favorites" />}
/>
<Autocomplete
id="size-small-standard"
size="small"
options={movies}
getOptionLabel={(option) => option.title}
defaultValue={movies[0]}
disableClearable
renderInput={(params) => (
<TextField {...params} variant="standard" label="Movies" placeholder="Favorites" />
)}
/>
<Autocomplete
multiple
id="size-small-standard-multi"
size="small"
options={movies}
getOptionLabel={(option) => option.title}
defaultValue={[movies[0]]}
disableClearable
renderInput={(params) => (
<TextField {...params} variant="standard" label="Movies" placeholder="Favorites" />
)}
/>
<Autocomplete
id="size-small-filled"
size="small"
options={movies}
getOptionLabel={(option) => option.title}
defaultValue={movies[0]}
disableClearable
renderInput={(params) => (
<TextField {...params} variant="filled" label="Movies" placeholder="Favorites" />
)}
/>
<Autocomplete
multiple
id="size-small-filled-multi"
size="small"
options={movies}
getOptionLabel={(option) => option.title}
defaultValue={[movies[0]]}
disableClearable
renderTags={(value, getTagProps) =>
value.map((option, index) => {
const { key, ...other } = getTagProps({ index });
return (
<Chip key={key} variant="outlined" label={option.title} size="small" {...other} />
);
})
}
renderInput={(params) => (
<TextField {...params} variant="filled" label="Movies" placeholder="Favorites" />
)}
/>
</Stack>
);
}

View File

@@ -0,0 +1,49 @@
import * as React from 'react';
import Autocomplete from '@mui/material/Autocomplete';
import SvgIcon from '@mui/material/SvgIcon';
import TextField from '@mui/material/TextField';
const movies = [
{
label: 'The Lord of the Rings: The Two Towers',
year: 2002,
},
];
export default function SmallAutocompleteWithStartAdornment() {
return (
<Autocomplete
options={movies}
value={movies[0]}
sx={{ width: 120, mt: 2 }}
renderInput={(params) => (
<TextField
{...params}
label="Autocomplete"
slotProps={{
input: {
...params.InputProps,
startAdornment: (
<SvgIcon>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={1.5}
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M4.5 12a7.5 7.5 0 0015 0m-15 0a7.5 7.5 0 1115 0m-15 0H3m16.5 0H21m-1.5 0H12m-8.457 3.077l1.41-.513m14.095-5.13l1.41-.513M5.106 17.785l1.15-.964m11.49-9.642l1.149-.964M7.501 19.795l.75-1.3m7.5-12.99l.75-1.3m-6.063 16.658l.26-1.477m2.605-14.772l.26-1.477m0 17.726l-.26-1.477M10.698 4.614l-.26-1.477M16.5 19.794l-.75-1.299M7.5 4.205L12 12m6.894 5.785l-1.149-.964M6.256 7.178l-1.15-.964m15.352 8.864l-1.41-.513M4.954 9.435l-1.41-.514M12.002 12l-3.75 6.495"
/>
</svg>
</SvgIcon>
),
},
}}
/>
)}
/>
);
}

View File

@@ -0,0 +1,16 @@
import * as React from 'react';
import TextField from '@mui/material/TextField';
import Autocomplete from '@mui/material/Autocomplete';
export default function StandardAutocomplete() {
return (
<div style={{ width: 300 }}>
<Autocomplete
options={[]}
renderInput={(params) => (
<TextField {...params} label="Standard autocomplete" variant="standard" />
)}
/>
</div>
);
}

View File

@@ -0,0 +1,18 @@
import * as React from 'react';
import TextField from '@mui/material/TextField';
import Autocomplete from '@mui/material/Autocomplete';
export default function StandardAutocomplete() {
return (
<div style={{ height: 220 }}>
<Autocomplete
multiple
limitTags={2}
options={['One', 'Two', 'Three']}
defaultValue={['One', 'Two', 'Three']}
renderInput={(params) => <TextField {...params} />}
sx={{ width: 300 }}
/>
</div>
);
}

View File

@@ -0,0 +1,206 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import TextField from '@mui/material/TextField';
import Autocomplete, { autocompleteClasses } from '@mui/material/Autocomplete';
import useMediaQuery from '@mui/material/useMediaQuery';
import ListSubheader from '@mui/material/ListSubheader';
import Popper from '@mui/material/Popper';
import { useTheme, styled } from '@mui/material/styles';
import { List, useListRef } from 'react-window';
import Typography from '@mui/material/Typography';
const LISTBOX_PADDING = 8; // px
function RowComponent({ index, itemData, style }) {
const dataSet = itemData[index];
const inlineStyle = {
...style,
top: (style.top ?? 0) + LISTBOX_PADDING,
};
if ('group' in dataSet) {
return (
<ListSubheader key={dataSet.key} component="div" style={inlineStyle}>
{dataSet.group}
</ListSubheader>
);
}
const { key, ...optionProps } = dataSet[0];
return (
<Typography key={key} component="li" {...optionProps} noWrap style={inlineStyle}>
{`#${dataSet[2] + 1} - ${dataSet[1]}`}
</Typography>
);
}
// Adapter for react-window v2
RowComponent.propTypes = {
index: PropTypes.number.isRequired,
itemData: PropTypes.arrayOf(
PropTypes.oneOfType([
PropTypes.arrayOf(
PropTypes.oneOfType([PropTypes.element, PropTypes.number, PropTypes.string]).isRequired,
),
PropTypes.shape({
children: PropTypes.node,
group: PropTypes.string.isRequired,
key: PropTypes.number.isRequired,
}),
]).isRequired,
).isRequired,
style: PropTypes.object.isRequired,
};
const ListboxComponent = React.forwardRef(function ListboxComponent(props, ref) {
const { children, internalListRef, onItemsBuilt, ...other } = props;
const itemData = [];
const optionIndexMap = React.useMemo(() => new Map(), []);
children.forEach((item) => {
itemData.push(item);
if ('children' in item && Array.isArray(item.children)) {
itemData.push(...item.children);
}
});
// Map option values to their indices in the flattened array
itemData.forEach((item, index) => {
if (Array.isArray(item) && item[1]) {
optionIndexMap.set(item[1], index);
}
});
React.useEffect(() => {
if (onItemsBuilt) {
onItemsBuilt(optionIndexMap);
}
}, [onItemsBuilt, optionIndexMap]);
const theme = useTheme();
const smUp = useMediaQuery(theme.breakpoints.up('sm'), {
noSsr: true,
});
const itemCount = itemData.length;
const itemSize = smUp ? 36 : 48;
const getChildSize = (child) => {
if (child.hasOwnProperty('group')) {
return 48;
}
return itemSize;
};
const getHeight = () => {
if (itemCount > 8) {
return 8 * itemSize;
}
return itemData.map(getChildSize).reduce((a, b) => a + b, 0);
};
// Separate className for List, other props for wrapper div (ARIA, handlers)
const { className, style, ...otherProps } = other;
return (
<div ref={ref} {...otherProps}>
<List
className={className}
listRef={internalListRef}
key={itemCount}
rowCount={itemCount}
rowHeight={(index) => getChildSize(itemData[index])}
rowComponent={RowComponent}
rowProps={{ itemData }}
style={{
height: getHeight() + 2 * LISTBOX_PADDING,
width: '100%',
}}
overscanCount={5}
tagName="ul"
/>
</div>
);
});
ListboxComponent.propTypes = {
children: PropTypes.node,
className: PropTypes.string,
internalListRef: PropTypes.oneOfType([
PropTypes.func,
PropTypes.shape({
current: PropTypes.shape({
element: PropTypes.object,
scrollToRow: PropTypes.func.isRequired,
}),
}),
]),
onItemsBuilt: PropTypes.func.isRequired,
style: PropTypes.object,
};
const StyledPopper = styled(Popper)({
[`& .${autocompleteClasses.listbox}`]: {
boxSizing: 'border-box',
'& ul': {
padding: 0,
margin: 0,
},
},
});
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
const OPTIONS = [...Array(100).keys()]
.map(
(number) =>
`${characters[number % characters.length].repeat(10)}${Math.floor(number / characters.length)}`,
)
.sort((a, b) => a.toUpperCase().localeCompare(b.toUpperCase()));
export default function Virtualize() {
// Use react-window v2's useListRef hook for imperative API access
const internalListRef = useListRef(null);
const optionIndexMapRef = React.useRef(new Map());
const handleItemsBuilt = React.useCallback((optionIndexMap) => {
optionIndexMapRef.current = optionIndexMap;
}, []);
// Handle keyboard navigation by scrolling to highlighted option
const handleHighlightChange = (event, option) => {
if (option && internalListRef.current) {
const index = optionIndexMapRef.current.get(option);
if (index !== undefined) {
internalListRef.current.scrollToRow({ index, align: 'auto' });
}
}
};
return (
<div style={{ height: 400 }}>
<Autocomplete
disableCloseOnSelect
sx={{ width: 300 }}
disableListWrap
options={OPTIONS}
groupBy={(option) => option[0].toUpperCase()}
renderInput={(params) => <TextField {...params} label="100 options" />}
renderOption={(props, option, state) => [props, option, state.index]}
renderGroup={(params) => params}
onHighlightChange={handleHighlightChange}
slots={{
popper: StyledPopper,
}}
slotProps={{
listbox: {
component: ListboxComponent,
internalListRef,
onItemsBuilt: handleItemsBuilt,
},
}}
/>
</div>
);
}

View File

@@ -0,0 +1,27 @@
import * as React from 'react';
import { ClassNames } from '@emotion/react';
import Button from '@mui/material/Button';
export default function EmotionCompat() {
return (
<ClassNames>
{({ css }) => (
<React.Fragment>
<Button color="primary" classes={{ root: css({ color: 'pink' }) }}>
This text should be pink
</Button>
<Button
color="primary"
className={css({ color: 'red' })}
classes={{ root: css({ color: 'pink' }) }}
>
This text should be red
</Button>
<Button color="primary" classes={{ text: css({ color: 'pink' }) }}>
This text should be pink
</Button>
</React.Fragment>
)}
</ClassNames>
);
}

View File

@@ -0,0 +1,24 @@
import * as React from 'react';
import Fab from '@mui/material/Fab';
import IconButton from '@mui/material/IconButton';
import DeleteIcon from '@mui/icons-material/Delete';
import Icon from '@mui/material/Icon';
export default function FontSvgIcons() {
return (
<div>
<Fab color="primary">
<DeleteIcon />
</Fab>
<Fab color="primary">
<Icon>delete_icon</Icon>
</Fab>
<IconButton>
<DeleteIcon />
</IconButton>
<IconButton>
<Icon>delete_icon</Icon>
</IconButton>
</div>
);
}

View File

@@ -0,0 +1,56 @@
import * as React from 'react';
import Button from '@mui/material/Button';
import FormControlLabel from '@mui/material/FormControlLabel';
import Switch from '@mui/material/Switch';
import SaveIcon from '@mui/icons-material/Save';
import SendIcon from '@mui/icons-material/Send';
export default function FullWidthLoadingButtonsTransition() {
const [loading, setLoading] = React.useState(true);
function handleClick() {
setLoading(true);
}
return (
<div>
<FormControlLabel
sx={{
display: 'block',
}}
control={
<Switch
checked={loading}
onChange={() => setLoading(!loading)}
name="loading"
color="primary"
/>
}
label="Loading"
/>
<Button onClick={handleClick} loading={loading} variant="outlined" fullWidth>
Fetch data
</Button>
<Button
onClick={handleClick}
endIcon={<SendIcon />}
loading={loading}
loadingPosition="end"
variant="contained"
fullWidth
>
Send
</Button>
<Button
color="secondary"
onClick={handleClick}
loading={loading}
loadingPosition="start"
startIcon={<SaveIcon />}
variant="contained"
fullWidth
>
Save
</Button>
</div>
);
}

View File

@@ -0,0 +1,26 @@
import * as React from 'react';
import Button from '@mui/material/Button';
import Icon from '@mui/material/Icon';
import SendIcon from '@mui/icons-material/Send';
export default function IconLabelButtons() {
return (
<div>
<Button variant="contained" color="secondary" startIcon={<SendIcon />}>
Send
</Button>
<Button variant="contained" endIcon={<Icon>send</Icon>}>
Send
</Button>
<Button variant="contained" disabled color="secondary" startIcon={<SendIcon />}>
Send
</Button>
<Button variant="contained" size="small" startIcon={<SendIcon />}>
Send
</Button>
<Button variant="contained" size="large" startIcon={<SendIcon />}>
Send
</Button>
</div>
);
}

View File

@@ -0,0 +1,53 @@
import * as React from 'react';
import { createTheme, ThemeProvider } from '@mui/material/styles';
import Button from '@mui/material/Button';
import Box from '@mui/material/Box';
const darkTheme = createTheme({
palette: {
mode: 'dark',
},
});
const theme = createTheme({});
export default function MulticoloredButton() {
return (
<React.Fragment>
<ThemeProvider theme={theme}>
<Box
sx={{
display: 'flex',
width: '100%',
alignItems: 'center',
justifyContent: 'center',
bgcolor: 'background.default',
color: 'text.primary',
p: 3,
}}
>
<Button variant="contained" color="inherit">
Button
</Button>
</Box>
</ThemeProvider>
<ThemeProvider theme={darkTheme}>
<Box
sx={{
display: 'flex',
width: '100%',
alignItems: 'center',
justifyContent: 'center',
bgcolor: 'background.default',
color: 'text.primary',
p: 3,
}}
>
<Button variant="contained" color="inherit">
Button
</Button>
</Box>
</ThemeProvider>
</React.Fragment>
);
}

View File

@@ -0,0 +1,14 @@
import * as React from 'react';
import Button from '@mui/material/Button';
export default function MultilineButton() {
return (
<Button variant="contained" style={{ width: 400 }}>
{[
'Contained buttons are rectangular-shaped buttons.',
'They may be used inline.',
'They lift and display ink reactions on press.',
].join(' ')}
</Button>
);
}

View File

@@ -0,0 +1,49 @@
import * as React from 'react';
import Button from '@mui/material/Button';
import ButtonGroup from '@mui/material/ButtonGroup';
import Stack from '@mui/material/Stack';
import Tooltip from '@mui/material/Tooltip';
export default function DifferentChildren() {
const falsyCondition = 1 === 2;
return (
<Stack spacing={2}>
{/* It has one button with href which is rendered as anchor tag */}
<ButtonGroup variant="contained">
<Button href="##">Button 1</Button>
<Button>Button 2</Button>
<Button>Button 3</Button>
</ButtonGroup>
{/* With tooltip */}
<ButtonGroup>
<Tooltip title="tooltip">
<Button>Enabled</Button>
</Tooltip>
<Tooltip title="tooltip">
<span>
<Button disabled>Disabled</Button>
</span>
</Tooltip>
<Tooltip title="tooltip">
<span>
<Button disabled>Disabled</Button>
</span>
</Tooltip>
</ButtonGroup>
{/* Single button */}
<ButtonGroup>
<Button>Single Button</Button>
</ButtonGroup>
{/* Conditional elements */}
<ButtonGroup>
<Button>One</Button>
<Button>Two</Button>
{falsyCondition ? <Button>Three</Button> : undefined}
</ButtonGroup>
</Stack>
);
}

View File

@@ -0,0 +1,45 @@
import * as React from 'react';
import Button from '@mui/material/Button';
import Box from '@mui/material/Box';
import ButtonGroup from '@mui/material/ButtonGroup';
const buttons = [
<Button key="one">One</Button>,
<Button key="two">Two</Button>,
<Button key="three">Three</Button>,
];
export default function DisabledButtonGroup() {
return (
<Box
sx={{
display: 'flex',
alignItems: 'center',
'& > *': {
m: 1,
},
}}
>
{/* variant="text" */}
<ButtonGroup
color="error"
orientation="horizontal"
aria-label="horizontal text button group"
variant="text"
disabled
>
{buttons}
</ButtonGroup>
{/* variant="text" */}
<ButtonGroup
color="error"
orientation="vertical"
aria-label="vertical text button group"
variant="text"
disabled
>
{buttons}
</ButtonGroup>
</Box>
);
}

View File

@@ -0,0 +1,20 @@
import * as React from 'react';
import { CssVarsProvider } from '@mui/joy/styles';
import Box from '@mui/joy/Box';
import Button from '@mui/joy/Button';
export default function VariantColorJoy() {
return (
<CssVarsProvider>
<Box sx={{ display: 'grid', gap: '1rem', gridTemplateColumns: 'repeat(4, min-content)' }}>
{['plain', 'outlined', 'soft', 'solid'].map((variant) => {
return ['primary', 'neutral', 'danger', 'info', 'success', 'warning'].map((color) => (
<Button key={`${variant}-${color}`} variant={variant} color={color}>
{color}
</Button>
));
})}
</Box>
</CssVarsProvider>
);
}

View File

@@ -0,0 +1,16 @@
import * as React from 'react';
import { CssVarsProvider } from '@mui/joy/styles';
import Box from '@mui/joy/Box';
import CircularProgress from '@mui/joy/CircularProgress';
import Typography from '@mui/joy/Typography';
export default function CircularProgressFlexItem() {
return (
<CssVarsProvider>
<Box sx={{ display: 'flex', width: 200, gap: 2 }}>
<CircularProgress determinate value={50} />
<Typography>Hello World, this is a very long sentence.</Typography>
</Box>
</CssVarsProvider>
);
}

View File

@@ -0,0 +1,25 @@
import * as React from 'react';
import { CssVarsProvider } from '@mui/joy/styles';
import Box from '@mui/joy/Box';
import CssBaseline from '@mui/joy/CssBaseline';
export default function JoyCssBaseline() {
return (
<CssVarsProvider>
<CssBaseline />
<Box sx={{ p: 2, display: 'flex', flexDirection: 'column', gap: 2 }}>
<Box sx={{ width: 300, height: 100, overflow: 'scroll', bgcolor: 'background.level1' }}>
{/* The scrollbar should be light */}
<Box sx={{ height: 1000 }} />
</Box>
<Box
data-joy-color-scheme="dark"
sx={{ width: 300, height: 100, overflow: 'scroll', bgcolor: 'background.level1' }}
>
{/* The scrollbar should be dark */}
<Box sx={{ height: 1000 }} />
</Box>
</Box>
</CssVarsProvider>
);
}

View File

@@ -0,0 +1,32 @@
import * as React from 'react';
import { CssVarsProvider, extendTheme } from '@mui/joy/styles';
import colors from '@mui/joy/colors';
import Box from '@mui/joy/Box';
import ScopedCssBaseline from '@mui/joy/ScopedCssBaseline';
const theme = extendTheme({
colorSchemes: {
forest: {
palette: {
mode: 'dark',
background: {
body: colors.green[200],
},
},
},
},
});
export default function JoyScopedCssBaseline() {
return (
<CssVarsProvider theme={theme}>
<ScopedCssBaseline
data-joy-color-scheme="forest"
sx={{ width: 300, height: 100, overflow: 'scroll', bgcolor: 'background.body' }}
>
{/* The scrollbar should be dark */}
<Box sx={{ height: 1000 }} />
</ScopedCssBaseline>
</CssVarsProvider>
);
}

View File

@@ -0,0 +1,31 @@
import * as React from 'react';
import { CssVarsProvider, extendTheme } from '@mui/material/styles';
import Box from '@mui/material/Box';
import CssBaseline from '@mui/material/CssBaseline';
const theme = extendTheme({
colorSchemes: { light: true, dark: true },
colorSchemeSelector: '[data-mui-color-scheme="%s"]',
disableCssColorScheme: true,
});
export default function MaterialCssBaseline() {
return (
<CssVarsProvider theme={theme}>
<CssBaseline enableColorScheme />
<Box sx={{ p: 2, display: 'flex', flexDirection: 'column', gap: 2 }}>
<Box sx={{ width: 300, height: 100, overflow: 'scroll', bgcolor: 'background.paper' }}>
{/* The scrollbar should be light */}
<Box sx={{ height: 1000 }} />
</Box>
<Box
data-mui-color-scheme="dark"
sx={{ width: 300, height: 100, overflow: 'scroll', bgcolor: 'background.paper' }}
>
{/* The scrollbar should be dark */}
<Box sx={{ height: 1000 }} />
</Box>
</Box>
</CssVarsProvider>
);
}

View File

@@ -0,0 +1,39 @@
import * as React from 'react';
import { CssVarsProvider, extendTheme, createTheme } from '@mui/material/styles';
import { cyan } from '@mui/material/colors';
import Box from '@mui/material/Box';
import ScopedCssBaseline from '@mui/material/ScopedCssBaseline';
const ocean = createTheme({
palette: {
mode: 'dark',
background: {
paper: cyan[200],
},
},
});
const theme = extendTheme({
colorSchemeSelector: '[data-mui-color-scheme="%s"]',
disableCssColorScheme: true,
colorSchemes: {
ocean: {
palette: ocean.palette,
},
},
});
export default function MaterialScopedCssBaseline() {
return (
<CssVarsProvider theme={theme}>
<ScopedCssBaseline
enableColorScheme
data-mui-color-scheme="ocean"
sx={{ width: 300, height: 100, overflow: 'scroll', bgcolor: 'background.paper' }}
>
{/* The scrollbar should be dark */}
<Box sx={{ height: 1000 }} />
</ScopedCssBaseline>
</CssVarsProvider>
);
}

View File

@@ -0,0 +1,39 @@
import * as React from 'react';
import { unstable_createCssVarsProvider as createCssVarsProvider, createBox } from '@mui/system';
import { createCssVarsTheme } from '@mui/system/cssVars';
const Box = createBox();
const { CssVarsProvider } = createCssVarsProvider({
theme: createCssVarsTheme({
colorSchemes: {
light: {
background: {
default: '#fff',
},
},
},
}),
defaultColorScheme: {
light: 'light',
dark: 'dark',
},
});
export default function ColorSchemeSelector() {
return (
<CssVarsProvider>
<Box
sx={(theme) => ({
p: 2,
color: '#fff',
[theme.getColorSchemeSelector('light')]: {
bgcolor: '#000',
},
})}
>
Background should be #000.
</Box>
</CssVarsProvider>
);
}

View File

@@ -0,0 +1,21 @@
import * as React from 'react';
import { CssVarsProvider, extendTheme } from '@mui/joy/styles';
import Box from '@mui/joy/Box';
import Button from '@mui/joy/Button';
// All buttons should look the same, otherwise, it means that multiple instances with different prefixes do not work.
export default function VariantColorJoy() {
return (
<Box sx={{ display: 'flex', gap: 2 }}>
<CssVarsProvider>
<Button>Button</Button>
</CssVarsProvider>
<CssVarsProvider theme={extendTheme({ cssVarPrefix: 'foo' })}>
<Button>Button</Button>
</CssVarsProvider>
<CssVarsProvider theme={extendTheme({ cssVarPrefix: 'bar' })}>
<Button>Button</Button>
</CssVarsProvider>
</Box>
);
}

View File

@@ -0,0 +1,46 @@
import * as React from 'react';
import {
unstable_createCssVarsProvider as createCssVarsProvider,
unstable_createCssVarsTheme as createCssVarsTheme,
} from '@mui/system';
const { CssVarsProvider, useColorScheme } = createCssVarsProvider({
theme: createCssVarsTheme({
colorSchemes: {
// test that styles order injection does not matter (dark comes before light).
dark: {
background: {
default: '#000',
},
},
light: {
background: {
default: '#e5e5e5',
},
},
},
}),
defaultColorScheme: {
light: 'light',
dark: 'dark',
},
});
function DarkMode() {
const { setMode } = useColorScheme();
React.useEffect(() => {
setMode('dark');
}, [setMode]);
return null;
}
export default function DarkModeSpecificity() {
return (
<CssVarsProvider>
<DarkMode />
<div style={{ background: 'var(--background-default)', color: '#888', padding: '1rem' }}>
Background should be #000.
</div>
</CssVarsProvider>
);
}

View File

@@ -0,0 +1,54 @@
import * as React from 'react';
import {
unstable_createCssVarsProvider as createCssVarsProvider,
unstable_createCssVarsTheme as createCssVarsTheme,
} from '@mui/system';
const { CssVarsProvider } = createCssVarsProvider({
theme: createCssVarsTheme({
colorSchemes: {
light: {
background: {
default: 'red',
},
},
dark: {
background: {
default: 'blue',
},
},
},
}),
defaultColorScheme: {
light: 'light',
dark: 'dark',
},
});
export default function ForceColorSchemes() {
return (
<CssVarsProvider>
<div
data-color-scheme="dark"
style={{
background: 'var(--background-default)',
color: 'white',
padding: '1rem',
}}
>
Background should be blue.
<div
data-color-scheme="light"
style={{
background: 'var(--background-default)',
height: 40,
color: 'white',
padding: '1rem',
}}
>
Background should be red.
</div>
</div>
</CssVarsProvider>
);
}

View File

@@ -0,0 +1,81 @@
import * as React from 'react';
import {
unstable_createCssVarsProvider as createCssVarsProvider,
unstable_createCssVarsTheme as createCssVarsTheme,
} from '@mui/system';
const { CssVarsProvider, useColorScheme } = createCssVarsProvider({
theme: createCssVarsTheme({
colorSchemes: {
light: {
background: {
default: 'red',
},
},
dark: {
background: {
default: 'blue',
},
},
},
}),
defaultColorScheme: {
light: 'light',
dark: 'dark',
},
});
const nestedTheme = createCssVarsTheme({
cssVarPrefix: 'nested',
colorSchemeSelector: '[data-nested-color-scheme="%s"]',
colorSchemes: {
light: {
background: {
default: 'yellow',
},
},
dark: {
background: {
default: 'cyan',
},
},
},
});
function DarkMode() {
const { setMode } = useColorScheme();
React.useEffect(() => {
setMode('dark');
}, [setMode]);
return null;
}
export default function IndependentCssVarsProviders() {
return (
<CssVarsProvider>
<div
style={{
background: 'var(--background-default)',
color: 'white',
padding: '1rem',
}}
>
Background should be red.
{/* If `disableNestedContext` is true, the upper CssVarsProvider should be independent */}
<CssVarsProvider theme={nestedTheme} disableNestedContext>
<DarkMode />
<div
style={{
background: 'var(--nested-background-default)',
height: 40,
color: '#000',
padding: '1rem',
}}
>
Background should be cyan.
</div>
</CssVarsProvider>
</div>
</CssVarsProvider>
);
}

View File

@@ -0,0 +1,41 @@
import * as React from 'react';
import {
ThemeProvider,
createTheme,
StyledEngineProvider,
useColorScheme,
} from '@mui/material/styles';
import Box from '@mui/material/Box';
const theme = createTheme({
colorSchemes: { dark: true },
cssVariables: { colorSchemeSelector: '.regression-inject-first-%s' },
});
function AutoDark() {
const { setMode } = useColorScheme();
React.useEffect(() => {
setMode('dark');
}, [setMode]);
return null;
}
export default function InjectFirstWithThemeVars() {
return (
<StyledEngineProvider injectFirst>
<ThemeProvider theme={theme} modeStorageKey="regression-inject-first">
<AutoDark />
<Box
sx={{
border: 2,
borderColor: 'divider',
backgroundColor: 'background.default',
width: 100,
height: 100,
m: 1,
}}
/>
</ThemeProvider>
</StyledEngineProvider>
);
}

View File

@@ -0,0 +1,41 @@
import * as React from 'react';
import { CssVarsProvider, extendTheme } from '@mui/material/styles';
import AppBar from '@mui/material/AppBar';
import Box from '@mui/material/Box';
import Paper from '@mui/material/Paper';
import Toolbar from '@mui/material/Toolbar';
const theme = extendTheme({ colorSchemes: { dark: true }, colorSchemeSelector: '.mode-%s' });
export default function MaterialUIDefaultDark() {
const [, rerender] = React.useState(false);
React.useEffect(() => {
// Trigger rerender to ensure that the UI does not change after the first render.
// To catch bug like https://github.com/mui/material-ui/issues/36452
rerender(true);
}, []);
return (
<CssVarsProvider theme={theme}>
<Box
sx={{
display: 'grid',
gridTemplateColumns: 'repeat(auto-fill, minmax(256px, 1fr))',
gridAutoRows: 'minmax(160px, auto)',
gap: 2,
'& > div': {
placeSelf: 'center',
},
}}
>
<AppBar position="static" color="secondary" elevation={12}>
<Toolbar>The color should be `palette.AppBar.darkBg`</Toolbar>
</AppBar>
<Box sx={{ bgcolor: '#121212', p: 4 }}>
<Paper elevation={24} sx={{ bgcolor: '#121212', p: 2, color: '#fff' }}>
You should see overlay.
</Paper>
</Box>
</Box>
</CssVarsProvider>
);
}

View File

@@ -0,0 +1,44 @@
import * as React from 'react';
import { CssVarsProvider, extendTheme, useColorScheme } from '@mui/material/styles';
import AppBar from '@mui/material/AppBar';
import Box from '@mui/material/Box';
import Paper from '@mui/material/Paper';
import Toolbar from '@mui/material/Toolbar';
function LightMode() {
const { setMode } = useColorScheme();
React.useEffect(() => {
setMode('light');
}, [setMode]);
return null;
}
const theme = extendTheme({ defaultColorScheme: 'dark', colorSchemeSelector: '.mode-%s' });
export default function MaterialUIDefaultDark() {
return (
<CssVarsProvider theme={theme}>
<LightMode />
<Box
sx={{
display: 'grid',
gridTemplateColumns: 'repeat(auto-fill, minmax(256px, 1fr))',
gridAutoRows: 'minmax(160px, auto)',
gap: 2,
'& > div': {
placeSelf: 'center',
},
}}
>
<AppBar position="static" color="secondary" elevation={12}>
<Toolbar>The color should be secondary.</Toolbar>
</AppBar>
<Box sx={{ bgcolor: '#121212', p: 4 }}>
<Paper elevation={24} sx={{ bgcolor: '#121212', p: 2, color: '#fff' }}>
You <em>should not</em> see overlay.
</Paper>
</Box>
</Box>
</CssVarsProvider>
);
}

View File

@@ -0,0 +1,93 @@
import * as React from 'react';
import {
unstable_createCssVarsProvider as createCssVarsProvider,
unstable_createCssVarsTheme as createCssVarsTheme,
} from '@mui/system';
const { CssVarsProvider } = createCssVarsProvider({
theme: createCssVarsTheme({
colorSchemes: {
light: {
background: {
default: 'red',
},
},
dark: {
background: {
default: 'blue',
},
},
},
}),
defaultColorScheme: {
light: 'light',
dark: 'dark',
},
});
const nestedTheme = createCssVarsTheme({
cssVarPrefix: 'nested',
colorSchemes: {
light: {
background: {
default: 'yellow',
},
},
dark: {
background: {
default: 'tomato',
},
},
},
});
export default function NestedCssVarsProviders() {
return (
<CssVarsProvider>
<div
data-color-scheme="light"
style={{
background: 'var(--background-default)',
color: 'white',
padding: '1rem',
}}
>
Background should be red.
<CssVarsProvider theme={nestedTheme}>
<div
style={{
background: 'var(--nested-background-default)',
height: 40,
color: '#000',
padding: '1rem',
}}
>
Background should be yellow.
</div>
</CssVarsProvider>
</div>
<div
data-color-scheme="dark"
style={{
background: 'var(--background-default)',
color: 'white',
padding: '1rem',
}}
>
Background should be blue.
<CssVarsProvider theme={nestedTheme} disableStyleSheetGeneration>
<div
style={{
background: 'var(--nested-background-default)',
height: 40,
color: '#000',
padding: '1rem',
}}
>
Background should be tomato.
</div>
</CssVarsProvider>
</div>
</CssVarsProvider>
);
}

View File

@@ -0,0 +1,30 @@
import * as React from 'react';
import DialogActions from '@mui/material/DialogActions';
import DialogContent from '@mui/material/DialogContent';
import DialogContentText from '@mui/material/DialogContentText';
import DialogTitle from '@mui/material/DialogTitle';
import Paper from '@mui/material/Paper';
import Button from '@mui/material/Button';
export default function AlertDialog() {
return (
<Paper
elevation={8}
style={{
width: 300,
}}
>
<DialogTitle>{"Use Google's location service?"}</DialogTitle>
<DialogContent>
<DialogContentText>
Let Google help apps determine location. This means sending anonymous location data to
Google, even when no apps are running.
</DialogContentText>
</DialogContent>
<DialogActions>
<Button color="primary">Disagree</Button>
<Button color="primary">Agree</Button>
</DialogActions>
</Paper>
);
}

View File

@@ -0,0 +1,16 @@
import * as React from 'react';
import { StyledEngineProvider } from '@mui/material/styles';
import CssBaseline from '@mui/material/CssBaseline';
import GlobalStyles from '@mui/material/GlobalStyles';
import Typography from '@mui/material/Typography';
export default function InjectFirst() {
return (
<StyledEngineProvider injectFirst>
<CssBaseline />
<Typography variant="h1">Hello MUI v6</Typography>
<Typography>The color should be red</Typography>
<GlobalStyles styles={() => ({ body: { color: 'red' } })} />
</StyledEngineProvider>
);
}

View File

@@ -0,0 +1,79 @@
/* eslint-disable */
import * as React from 'react';
import { styled } from '@mui/material/styles';
import Box from '@mui/material/Box';
import Paper from '@mui/material/Paper';
import Grid from '@mui/material/Grid';
const Item = styled(Paper)(({ theme }) => ({
backgroundColor: '#fff',
...theme.typography.body2,
padding: theme.spacing(1),
textAlign: 'center',
color: theme.palette.text.secondary,
...theme.applyStyles('dark', {
backgroundColor: '#1A2027',
}),
}));
export default function VariableWidthGrid() {
return (
<Box sx={{ flexGrow: 1 }}>
<Grid container spacing={5}>
<Grid size="auto">
<Item>size=auto</Item>
</Grid>
<Grid size={6}>
<Item>size=6</Item>
</Grid>
<Grid size="grow">
<Item>size=grow</Item>
</Grid>
<Grid size={12} container>
<Grid size={10}>
<Item>Nested 10 under a 12</Item>
</Grid>
<Grid size={2}>
<Item>Nested 2 under a 12</Item>
</Grid>
</Grid>
<Grid size={12} container spacing={1}>
<Grid size={10}>
<Item>Nested 10 under a 12 override spacing</Item>
</Grid>
<Grid size={2}>
<Item>Nested 2 under a 12 override spacing</Item>
</Grid>
</Grid>
<Grid size={12}>
<Grid container>
{/* Container not nested in container. Does not inherit spacing */}
<Grid size={10}>
<Item>Incorrectly nested 10 under a 12</Item>
</Grid>
<Grid size={2}>
<Item>Incorrectly nested 2 under a 12</Item>
</Grid>
</Grid>
</Grid>
<Grid size={12}>
<>
<Grid container>
{/* Container not nested in container. Does not inherit spacing */}
<Grid size={10}>
<Item>Nested 10 under a 12 with fragment</Item>
</Grid>
<Grid size={2}>
<Item>Nested 2 under a 12 with fragment</Item>
</Grid>
</Grid>
</>
</Grid>
</Grid>
</Box>
);
}

View File

@@ -0,0 +1,91 @@
import * as React from 'react';
import Paper from '@mui/material/Paper';
import Box from '@mui/material/Box';
import Grid from '@mui/material/Grid';
export default function StressNestedGrid() {
return (
<Box
sx={{
width: 600,
display: 'flex',
bgcolor: 'secondary.main',
'& .MuiPaper-root': {
p: 2,
textAlign: 'center',
},
}}
>
<Grid container spacing={1}>
<Grid size={12}>
<Paper>xs=12</Paper>
</Grid>
<Grid size={6}>
<Paper>xs=6</Paper>
</Grid>
<Grid size={6}>
<Paper>xs=6</Paper>
</Grid>
<Box sx={{ p: 2, width: '100%' }}>
{/* This grid should start as a new root grid (doesn't inherit spacing from the top) */}
<Grid container spacing={3}>
<Grid size={6}>
<Paper>xs=6</Paper>
</Grid>
<Grid container size={6}>
{/* nested spacing can be override by the explicit `spacing` prop */}
<Grid container spacing={1} size={6}>
<Grid size={7}>
<Paper>xs=7</Paper>
</Grid>
<Grid size={5}>
<Paper>xs=5</Paper>
</Grid>
</Grid>
<Grid size={6}>
<Paper>xs=6</Paper>
</Grid>
</Grid>
</Grid>
</Box>
<Grid container spacing={3} size={6}>
<Grid size={6}>
<Paper>xs=6</Paper>
</Grid>
<Grid size={6}>
<Paper>xs=6</Paper>
</Grid>
</Grid>
<Grid container spacing={3} size={6}>
<Grid size={8}>
<Paper>xs=8</Paper>
</Grid>
<Grid size={4}>
<Paper>xs=4</Paper>
</Grid>
</Grid>
{/* The grids below should inherit spacing from the top */}
<Grid container size={6}>
<Grid size={4}>
<Paper>xs=4</Paper>
</Grid>
<Grid size={4}>
<Paper>xs=4</Paper>
</Grid>
<Grid size={4}>
<Paper>xs=4</Paper>
</Grid>
</Grid>
<Grid container size={6}>
<Grid size={6}>
<Paper>xs=6</Paper>
</Grid>
<Grid size={6}>
<Paper>xs=6</Paper>
</Grid>
</Grid>
</Grid>
</Box>
);
}

View File

@@ -0,0 +1,31 @@
import * as React from 'react';
import Paper from '@mui/material/Paper';
import Box from '@mui/material/Box';
import Grid from '@mui/material/Grid';
import { styled } from '@mui/material/styles';
// styled(Grid) should work with nested grids.
const StyledGrid = styled(Grid)({});
export default function StyledGridTest() {
return (
<Box sx={{ p: 3, width: 600 }}>
<Grid container spacing={4}>
<Grid size={4}>
<Paper>Item 1</Paper>
</Grid>
<StyledGrid container size={4}>
<StyledGrid size={6}>
<Paper>Item 2.1</Paper>
</StyledGrid>
<Grid size={6}>
<Paper>Item 2.2</Paper>
</Grid>
</StyledGrid>
<StyledGrid size={4}>
<Paper>Item 3</Paper>
</StyledGrid>
</Grid>
</Box>
);
}

View File

@@ -0,0 +1,55 @@
import * as React from 'react';
import Paper from '@mui/material/Paper';
import Box from '@mui/material/Box';
import Grid from '@mui/material/GridLegacy';
export default function StressGridLegacy() {
return (
<Box
sx={{
width: 400,
display: 'flex',
bgcolor: 'secondary.main',
'& .MuiPaper-root': {
p: 2,
textAlign: 'center',
},
}}
>
<Grid container spacing={3} direction="column">
<Grid container item spacing={1}>
<Grid item xs={3}>
<Paper>xs=3</Paper>
</Grid>
<Grid item xs={9}>
<Paper>xs=9</Paper>
</Grid>
</Grid>
<Grid container item spacing={1} direction="row-reverse">
<Grid item xs={3}>
<Paper>first</Paper>
</Grid>
<Grid item xs={3}>
<Paper>last</Paper>
</Grid>
</Grid>
<Grid container item spacing={1} justifyContent="space-between">
<Grid item xs={3}>
<Paper>space</Paper>
</Grid>
<Grid item xs={3}>
<Paper>between</Paper>
</Grid>
</Grid>
<Grid container item spacing={1} alignItems="stretch" direction="column-reverse">
<Grid item>
<Paper>reverse</Paper>
</Grid>
<Grid item>
<Paper>column</Paper>
</Grid>
</Grid>
</Grid>
</Box>
);
}

View File

@@ -0,0 +1,85 @@
import * as React from 'react';
import Paper from '@mui/material/Paper';
import Box from '@mui/material/Box';
import Grid from '@mui/material/GridLegacy';
export default function StressNestedGridLegacy() {
return (
<Box
sx={{
width: 600,
display: 'flex',
bgcolor: 'secondary.main',
'& .MuiPaper-root': {
p: 2,
textAlign: 'center',
},
}}
>
<Grid container spacing={1}>
<Grid item xs={12}>
<Paper>xs=12</Paper>
</Grid>
<Grid item xs={6}>
<Paper>xs=6</Paper>
</Grid>
<Grid item xs={6}>
<Paper>xs=6</Paper>
</Grid>
<Grid item container direction="column-reverse" xs={6} spacing={3}>
<Grid item xs={6}>
<Paper>xs=6</Paper>
</Grid>
<Grid item container spacing={2} xs={6}>
<Grid item container spacing={1} xs={6}>
<Grid item xs={7}>
<Paper>xs=7</Paper>
</Grid>
<Grid item xs={5}>
<Paper>xs=5</Paper>
</Grid>
</Grid>
<Grid item xs={6}>
<Paper>xs=6</Paper>
</Grid>
</Grid>
</Grid>
<Grid item container direction="column" xs={6} spacing={3}>
<Grid item xs={6}>
<Paper>xs=6</Paper>
</Grid>
<Grid item xs={6}>
<Paper>xs=6</Paper>
</Grid>
</Grid>
<Grid item container xs={6} spacing={3}>
<Grid item xs={8}>
<Paper>xs=8</Paper>
</Grid>
<Grid item xs={4}>
<Paper>xs=4</Paper>
</Grid>
</Grid>
<Grid item container xs={6} spacing={2}>
<Grid item xs={4}>
<Paper>xs=4</Paper>
</Grid>
<Grid item xs={4}>
<Paper>xs=4</Paper>
</Grid>
<Grid item xs={4}>
<Paper>xs=4</Paper>
</Grid>
</Grid>
<Grid item container xs={6} spacing={5}>
<Grid item xs={6}>
<Paper>xs=6</Paper>
</Grid>
<Grid item xs={6}>
<Paper>xs=6</Paper>
</Grid>
</Grid>
</Grid>
</Box>
);
}

View File

@@ -0,0 +1,31 @@
import * as React from 'react';
import { CssVarsProvider } from '@mui/joy/styles';
import Input from '@mui/joy/Input';
import IconButton from '@mui/joy/IconButton';
import Stack from '@mui/joy/Stack';
import VisibilityIcon from '@mui/icons-material/Visibility';
export default function VariantColorJoy() {
return (
<CssVarsProvider>
<Stack spacing={2}>
<Input
size="lg"
endDecorator={
<IconButton>
<VisibilityIcon />
</IconButton>
}
/>
<Input
size="lg"
endDecorator={
<IconButton size="sm">
<VisibilityIcon />
</IconButton>
}
/>
</Stack>
</CssVarsProvider>
);
}

View File

@@ -0,0 +1,30 @@
import * as React from 'react';
import Box from '@mui/material/Box';
import InputLabel from '@mui/material/InputLabel';
function InputLabels() {
return (
<Box
sx={{
display: 'flex',
flexDirection: 'column',
alignItems: 'flex-start',
padding: '20px', // so transform doesn't let things get cut off
}}
>
<InputLabel shrink>First Name Shrunk</InputLabel>
<InputLabel>First Name</InputLabel>
<InputLabel focused>Required</InputLabel>
<InputLabel focused required>
Focused Required
</InputLabel>
<InputLabel required>Required</InputLabel>
<InputLabel error>Error</InputLabel>
<InputLabel required error>
Required Error
</InputLabel>
</Box>
);
}
export default InputLabels;

View File

@@ -0,0 +1,27 @@
import * as React from 'react';
import Box from '@mui/material/Box';
import Input from '@mui/material/Input';
function Inputs() {
const inputRef = React.useRef();
React.useEffect(() => {
inputRef.current.focus();
}, []);
return (
<div>
<Box sx={{ display: 'flex', flexDirection: 'column', width: 200 }}>
<Input value="Hello world" sx={{ m: '10px' }} />
<Input placeholder="Placeholder" sx={{ m: '10px' }} />
<Input value="Disabled" sx={{ m: '10px' }} disabled />
<Input error value="Error" sx={{ m: '10px' }} />
<Input value="Focused" inputRef={inputRef} sx={{ m: '10px' }} />
<Input type="search" defaultValue="Hello world" />
</Box>
<Input value="Large input" sx={{ m: '10px', width: 300 }} />
</div>
);
}
export default Inputs;

View File

@@ -0,0 +1,62 @@
import * as React from 'react';
import { CssVarsProvider } from '@mui/joy/styles';
import CssBaseline from '@mui/joy/CssBaseline';
import Box from '@mui/joy/Box';
import Card from '@mui/joy/Card';
import Drawer from '@mui/joy/Drawer';
import Divider from '@mui/joy/Divider';
import List from '@mui/joy/List';
import ListItem from '@mui/joy/ListItem';
import ListItemButton from '@mui/joy/ListItemButton';
import Typography from '@mui/joy/Typography';
export default function DrawerColorInversion() {
return (
<CssVarsProvider>
<CssBaseline />
<Box sx={{ width: '100vw', height: '100vh', bgcolor: 'background.body' }} />
<Drawer open color="primary" variant="solid" invertedColors>
<Box role="presentation">
<List>
{['Inbox', 'Starred', 'Send email', 'Drafts'].map((text) => (
<ListItem key={text}>
<ListItemButton>{text}</ListItemButton>
</ListItem>
))}
</List>
<Divider />
<List>
{['All mail', 'Trash', 'Spam'].map((text) => (
<ListItem key={text}>
<ListItemButton>{text}</ListItemButton>
</ListItem>
))}
</List>
</Box>
<Card variant="soft">
<Typography level="title-lg" fontFamily="code">
1212
</Typography>
<Box sx={{ display: 'flex', gap: 2, justifyContent: 'space-between' }}>
<div>
<Typography fontSize="xs" fontFamily="code">
CARD NAME
</Typography>
<Typography level="title-sm" fontSize="sm">
JOHN DOE
</Typography>
</div>
<div>
<Typography fontSize="xs" textAlign="right" fontFamily="code">
EXPIRE
</Typography>
<Typography level="title-sm" fontSize="sm" textAlign="right">
07/25
</Typography>
</div>
</Box>
</Card>
</Drawer>
</CssVarsProvider>
);
}

View File

@@ -0,0 +1,169 @@
import * as React from 'react';
import { CssVarsProvider } from '@mui/joy/styles';
import {
CssBaseline,
Sheet,
Box,
Alert,
AspectRatio,
Avatar,
Badge,
Button,
Card,
CardContent,
CardOverflow,
Checkbox,
Chip,
ChipDelete,
CircularProgress,
Divider,
IconButton,
Input,
LinearProgress,
Link,
List,
ListDivider,
ListItem,
ListItemButton,
ListSubheader,
Option,
Radio,
Select,
Slider,
Switch,
Tab,
TabList,
Tabs,
Textarea,
Typography,
} from '@mui/joy';
const VARIANTS = ['plain', 'outlined', 'soft', 'solid'];
export default function JoyColorInversion() {
const renderComponents = (elm) => (
<Box
sx={{
display: 'flex',
flexDirection: 'column',
gap: 1,
justifyContent: 'center',
alignItems: 'center',
}}
>
{React.Children.toArray(VARIANTS.map((variant) => React.cloneElement(elm, { variant })))}
</Box>
);
const elements = (
<React.Fragment>
{renderComponents(<Alert>This is an alert.</Alert>)}
{renderComponents(
<AspectRatio sx={{ minWidth: 120 }}>
<div>Image</div>
</AspectRatio>,
)}
{renderComponents(<Avatar>MA</Avatar>)}
{renderComponents(
<Badge badgeContent={1000}>
<IconButton>😀</IconButton>
</Badge>,
)}
{renderComponents(<Button>Button</Button>)}
<Card sx={{ minWidth: 256 }}>
<AspectRatio>
<div>Image</div>
</AspectRatio>
<CardContent>Content</CardContent>
<Divider />
<CardOverflow variant="soft">
<Box sx={{ display: 'flex', py: 1.5, textAlign: 'right' }}>
<Button>Next</Button>
</Box>
</CardOverflow>
</Card>
{renderComponents(<Checkbox label="Label" />)}
{renderComponents(<Chip endDecorator={<ChipDelete />}>Chip</Chip>)}
{renderComponents(
<CircularProgress determinate value={25}>
25%
</CircularProgress>,
)}
{renderComponents(<Input placeholder="Placeholder" />)}
{renderComponents(
<LinearProgress determinate value={25} sx={{ width: '100%', flex: 'none' }} />,
)}
{renderComponents(<Link href="/">Link</Link>)}
<List variant="outlined">
<ListItem>Item 1</ListItem>
<ListDivider />
<ListItem>Item 2</ListItem>
<ListItem>Item 3</ListItem>
</List>
{renderComponents(<ListItem>Item</ListItem>)}
{renderComponents(<ListItemButton>Item</ListItemButton>)}
{renderComponents(<ListSubheader>Subheader</ListSubheader>)}
{renderComponents(
<Select placeholder="Choose one">
<Option value={0}>Option</Option>
</Select>,
)}
{renderComponents(<Radio label="Label" />)}
{renderComponents(<Slider defaultValue={50} />)}
{renderComponents(<Switch />)}
<Tabs defaultValue={0}>
<TabList variant="plain">
<Tab variant="soft">Tab 1</Tab>
<Tab>Tab 2</Tab>
<Tab>Tab 3</Tab>
</TabList>
</Tabs>
<Tabs defaultValue={0}>
<TabList variant="outlined">
<Tab variant="soft">Tab 1</Tab>
<Tab>Tab 2</Tab>
<Tab>Tab 3</Tab>
</TabList>
</Tabs>
<Tabs defaultValue={0}>
<TabList variant="soft">
<Tab variant="solid">Tab 1</Tab>
<Tab>Tab 2</Tab>
<Tab>Tab 3</Tab>
</TabList>
</Tabs>
{renderComponents(<Textarea placeholder="Placeholder" />)}
{renderComponents(<Typography>Text</Typography>)}
</React.Fragment>
);
return (
<CssVarsProvider>
<CssBaseline />
<Sheet
variant="soft"
color="primary"
invertedColors
sx={{
p: 2,
display: 'grid',
gridTemplateColumns: 'repeat(auto-fill, minmax(300px, 1fr))',
gap: 2,
}}
>
{elements}
</Sheet>
<Sheet
variant="solid"
color="primary"
invertedColors
sx={{
p: 2,
display: 'grid',
gridTemplateColumns: 'repeat(auto-fill, minmax(300px, 1fr))',
gap: 2,
}}
>
{elements}
</Sheet>
</CssVarsProvider>
);
}

View File

@@ -0,0 +1,125 @@
import * as React from 'react';
import { CssVarsProvider } from '@mui/joy/styles';
import CssBaseline from '@mui/joy/CssBaseline';
import Autocomplete from '@mui/joy/Autocomplete';
import Button from '@mui/joy/Button';
import Card from '@mui/joy/Card';
import Menu from '@mui/joy/Menu';
import MenuItem from '@mui/joy/MenuItem';
import ListDivider from '@mui/joy/ListDivider';
import Tooltip from '@mui/joy/Tooltip';
import Stack from '@mui/joy/Stack';
import Select from '@mui/joy/Select';
import Option from '@mui/joy/Option';
const films = [
{ label: 'The Shawshank Redemption', year: 1994 },
{ label: 'The Godfather', year: 1972 },
{ label: 'The Godfather: Part II', year: 1974 },
{ label: 'The Dark Knight', year: 2008 },
{ label: '12 Angry Men', year: 1957 },
{ label: "Schindler's List", year: 1993 },
{ label: 'Pulp Fiction', year: 1994 },
];
export default function ColorInversionPopup() {
const [menuButton, setMenuButton] = React.useState(null);
const [menuButton2, setMenuButton2] = React.useState(null);
return (
<CssVarsProvider>
<CssBaseline />
<Stack spacing={2}>
<Card
orientation="horizontal"
variant="solid"
color="primary"
invertedColors
sx={{
gap: 10,
minHeight: 240,
alignItems: 'flex-start',
justifyContent: 'center',
flexGrow: 1,
zIndex: 0,
}}
>
<Autocomplete
placeholder="Combo box"
options={films}
sx={{ width: 240 }}
open
slotProps={{
listbox: { disablePortal: false, sx: { maxHeight: 160 } },
}}
/>
<Button ref={(node) => setMenuButton(node)} variant="soft">
Actions
</Button>
<Menu disablePortal={false} anchorEl={menuButton} open={!!menuButton}>
<MenuItem>New tab</MenuItem>
<MenuItem>New window</MenuItem>
<ListDivider />
<MenuItem>Delete</MenuItem>
</Menu>
<Select
placeholder="Choose one"
listboxOpen
slotProps={{ listbox: { disablePortal: false } }}
>
<Option value="1">Option 1</Option>
<Option value="2">Option 2</Option>
<Option value="3">Option 3</Option>
</Select>
<Tooltip title="Bookmark" disablePortal={false} open variant="solid">
<span>test</span>
</Tooltip>
</Card>
<Card
orientation="horizontal"
variant="solid"
color="primary"
invertedColors
sx={{
gap: 10,
minHeight: 240,
alignItems: 'flex-start',
justifyContent: 'center',
flexGrow: 1,
zIndex: 0,
}}
>
<Autocomplete
placeholder="Combo box"
options={films}
sx={{ width: 240 }}
open
slotProps={{
listbox: { disablePortal: true, sx: { maxHeight: 160 } },
}}
/>
<Button ref={(node) => setMenuButton2(node)} variant="soft">
Actions
</Button>
<Menu disablePortal anchorEl={menuButton2} open={!!menuButton2}>
<MenuItem>New tab</MenuItem>
<MenuItem>New window</MenuItem>
<ListDivider />
<MenuItem>Delete</MenuItem>
</Menu>
<Select
placeholder="Choose one"
listboxOpen
slotProps={{ listbox: { disablePortal: true } }}
>
<Option value="1">Option 1</Option>
<Option value="2">Option 2</Option>
<Option value="3">Option 3</Option>
</Select>
<Tooltip title="Bookmark" disablePortal open variant="solid">
<span>test</span>
</Tooltip>
</Card>
</Stack>
</CssVarsProvider>
);
}

View File

@@ -0,0 +1,75 @@
import * as React from 'react';
import { CssVarsProvider, styled } from '@mui/joy/styles';
import { applySolidInversion } from '@mui/joy/colorInversion';
import CssBaseline from '@mui/joy/CssBaseline';
import Box from '@mui/joy/Box';
import Typography from '@mui/joy/Typography';
import SvgIcon from '@mui/joy/SvgIcon';
const Wrapper = styled('div')(
({ theme }) => ({
display: 'flex',
flexDirection: 'column',
gap: '1.5rem',
padding: '1.5rem',
borderRadius: 20,
width: 300,
maxWidth: '100%',
...theme.variants.solid.warning,
}),
applySolidInversion('warning'),
);
export default function JoyColorInversionStyled() {
return (
<CssVarsProvider>
<CssBaseline />
<Wrapper>
<Box sx={{ display: 'flex', gap: 1 }}>
<div>
<Typography level="title-lg">$4,236</Typography>
<Typography fontSize="xs" fontFamily="code">
CREDIT
</Typography>
</div>
<SvgIcon sx={{ ml: 'auto' }}>
<svg
width="50"
height="39"
viewBox="0 0 50 39"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M16.4992 2H37.5808L22.0816 24.9729H1L16.4992 2Z" fill="currentColor" />
<path
d="M17.4224 27.102L11.4192 36H33.5008L49 13.0271H32.7024L23.2064 27.102H17.4224Z"
fill="#312ECB"
/>
</svg>
</SvgIcon>
</Box>
<Typography level="title-lg" fontFamily="code">
1212
</Typography>
<Box sx={{ display: 'flex', gap: 2, justifyContent: 'space-between' }}>
<div>
<Typography fontSize="xs" fontFamily="code">
CARD NAME
</Typography>
<Typography level="title-sm" fontSize="sm">
JOHN DOE
</Typography>
</div>
<div>
<Typography fontSize="xs" textAlign="right" fontFamily="code">
EXPIRE
</Typography>
<Typography level="title-sm" fontSize="sm" textAlign="right">
07/25
</Typography>
</div>
</Box>
</Wrapper>
</CssVarsProvider>
);
}

View File

@@ -0,0 +1,15 @@
import * as React from 'react';
import LinearProgress from '@mui/material/LinearProgress';
export default function DeterminateLinearProgress() {
return (
<LinearProgress
variant="buffer"
value={60}
valueBuffer={80}
style={{
width: 150,
}}
/>
);
}

View File

@@ -0,0 +1,11 @@
import * as React from 'react';
import LinearProgress from '@mui/material/LinearProgress';
export default function DeterminateLinearProgress() {
return (
<div>
<LinearProgress variant="determinate" value={60} style={{ width: 150 }} />
<LinearProgress variant="determinate" value={60} style={{ width: 150 }} color="inherit" />
</div>
);
}

View File

@@ -0,0 +1,68 @@
import * as React from 'react';
import { createTheme, ThemeProvider } from '@mui/material/styles';
import Link from '@mui/material/Link';
export default function DeterminateLinearProgress() {
return (
<div>
<ThemeProvider
theme={createTheme({
components: {
MuiLink: {
styleOverrides: {
root: ({ ownerState, theme }) => ({
...(ownerState.color === 'secondary' && {
color: theme.palette.error.main,
}),
}),
},
variants: [
{
props: { color: 'textPrimary' },
style: ({ theme }) => ({
color: theme.palette.warning.main,
}),
},
],
},
},
})}
>
<Link href="#unknown">primary</Link>
<Link href="#unknown" color="secondary">
error
</Link>
<Link href="#unknown" color="textPrimary">
warning
</Link>
</ThemeProvider>
<ThemeProvider
theme={createTheme({
components: {
MuiLink: {
styleOverrides: {
root: {
color: '#fbca04', // orange
},
},
},
},
})}
>
<Link href="#unknown">#fbca04</Link>
<Link href="#unknown" color="#ff5252">
#ff5252
</Link>
<Link href="#unknown" sx={{ color: '#ff5252' }}>
#ff5252 (primary underline)
</Link>
<Link href="#unknown" sx={(theme) => ({ color: theme.palette.secondary.main })}>
secondary
</Link>
<Link href="#unknown" sx={{ color: (theme) => theme.palette.error.main }}>
error
</Link>
</ThemeProvider>
</div>
);
}

View File

@@ -0,0 +1,26 @@
import * as React from 'react';
import Avatar from '@mui/joy/Avatar';
import Box from '@mui/joy/Box';
import Card from '@mui/joy/Card';
import Link, { linkClasses } from '@mui/joy/Link';
import Typography from '@mui/joy/Typography';
export default function LinkCard() {
return (
<Box sx={{ p: 2 }}>
<Card variant="outlined" sx={{ display: 'flex', gap: 2 }}>
<Avatar size="lg" src="/static/images/avatar/1.jpg" />
<Link
overlay
href="#introduction"
underline="none"
className={linkClasses.focusVisible}
sx={{ display: 'flex', flexDirection: 'column', alignItems: 'start' }}
>
<Typography level="body-md">Joy UI</Typography>
<Typography level="body-sm">Components that spark joy!</Typography>
</Link>
</Card>
</Box>
);
}

View File

@@ -0,0 +1,78 @@
import * as React from 'react';
import Box from '@mui/joy/Box';
import List from '@mui/joy/List';
import ListItem from '@mui/joy/ListItem';
import ListDivider from '@mui/joy/ListDivider';
import ListItemButton from '@mui/joy/ListItemButton';
export default function Flexibility() {
return (
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
<List sx={{ maxWidth: 100, maxHeight: 100, overflow: 'scroll' }}>
<ListItem>This is a very long text that should scale by its content.</ListItem>
<ListItem>Item 2</ListItem>
<ListItem>Item 3</ListItem>
<ListItem>Item 4 </ListItem>
</List>
<List component="nav" sx={{ maxWidth: 100, maxHeight: 100, overflow: 'scroll' }}>
<ListItemButton>This is a very long text that should scale by its content.</ListItemButton>
<ListItemButton>Item 2</ListItemButton>
<ListItemButton>Item 3</ListItemButton>
<ListItemButton>Item 4 </ListItemButton>
</List>
<List sx={{ maxWidth: 100, maxHeight: 100, overflow: 'scroll' }}>
<ListItem>
<ListItemButton>
This is a very long text that should scale by its content.
</ListItemButton>
</ListItem>
<ListItem>
<ListItemButton>Item 2</ListItemButton>
</ListItem>
<ListItem>
<ListItemButton>Item 3</ListItemButton>
</ListItem>
<ListItem>
<ListItemButton>Item 4</ListItemButton>
</ListItem>
</List>
<List role="menubar" orientation="horizontal">
<ListItem role="none">
<ListItemButton
variant="solid"
color="primary"
role="menuitem"
component="a"
href="#horizontal-list"
aria-label="Home"
>
Home
</ListItemButton>
</ListItem>
<ListDivider />
<ListItem role="none">
<ListItemButton variant="soft" role="menuitem" component="a" href="#horizontal-list">
Products
</ListItemButton>
</ListItem>
<ListDivider />
<ListItem role="none">
<ListItemButton variant="soft" role="menuitem" component="a" href="#horizontal-list">
Blog
</ListItemButton>
</ListItem>
<ListItem role="none" sx={{ marginInlineStart: 'auto' }}>
<ListItemButton
variant="soft"
role="menuitem"
component="a"
href="#horizontal-list"
aria-label="Profile"
>
Account
</ListItemButton>
</ListItem>
</List>
</Box>
);
}

View File

@@ -0,0 +1,70 @@
import * as React from 'react';
import { CssVarsProvider } from '@mui/joy/styles';
import List from '@mui/joy/List';
import ListItem from '@mui/joy/ListItem';
import ListItemButton from '@mui/joy/ListItemButton';
export default function NestedVariables() {
return (
<CssVarsProvider>
<List
sx={(theme) => ({
...theme.variants.outlined.neutral,
bgcolor: 'background.level3',
'--List-radius': '16px',
'--List-padding': '8px',
'--List-gap': '4px',
'& > li [role="button"]': {
bgcolor: 'background.surface',
},
})}
>
<ListItem>
<ListItemButton>Item 1</ListItemButton>
</ListItem>
<ListItem nested>
<ListItem>
<ListItemButton>Item 2</ListItemButton>
</ListItem>
<List
sx={{
'& > li [role="button"]': {
bgcolor: 'background.level2',
},
}}
>
<ListItem>
<ListItemButton>Item 2.1</ListItemButton>
</ListItem>
<ListItem>
<ListItemButton>Item 2.2</ListItemButton>
</ListItem>
<ListItem nested>
<ListItemButton>Item 2.3</ListItemButton>
<List
sx={{
'& > li [role="button"]': {
bgcolor: 'background.level1',
},
}}
>
<ListItem>
<ListItemButton>Item 2.3.1</ListItemButton>
</ListItem>
<ListItem>
<ListItemButton>Item 2.3.2</ListItemButton>
</ListItem>
<ListItem>
<ListItemButton>Item 2.3.3</ListItemButton>
</ListItem>
</List>
</ListItem>
</List>
</ListItem>
<ListItem>
<ListItemButton>Item 3</ListItemButton>
</ListItem>
</List>
</CssVarsProvider>
);
}

View File

@@ -0,0 +1,12 @@
import * as React from 'react';
import ListSubheader from '@mui/material/ListSubheader';
export default function SimpleListSubheader() {
return (
<div>
<ListSubheader>Title</ListSubheader>
<ListSubheader color="primary">Title</ListSubheader>
<ListSubheader inset>Title</ListSubheader>
</div>
);
}

View File

@@ -0,0 +1,32 @@
import * as React from 'react';
import Box from '@mui/material/Box';
import { styled } from '@mui/material/styles';
import Paper from '@mui/material/Paper';
import Masonry from '@mui/lab/Masonry';
const heights = [150, 30, 90, 70, 110, 150, 130, 80, 50, 90, 100, 150, 30, 50, 80];
const Item = styled(Paper)(({ theme }) => ({
backgroundColor: '#fff',
...theme.typography.body2,
padding: theme.spacing(0.5),
textAlign: 'center',
color: theme.palette.text.secondary,
...theme.applyStyles('dark', {
backgroundColor: '#1A2027',
}),
}));
export default function EmSpacingValue() {
return (
<Box sx={{ width: 500, minHeight: 393 }}>
<Masonry columns={4} spacing={'2rem'}>
{heights.map((height, index) => (
<Item key={index} sx={{ height }}>
{index + 1}
</Item>
))}
</Masonry>
</Box>
);
}

View File

@@ -0,0 +1,40 @@
import * as React from 'react';
import Box from '@mui/material/Box';
import { styled } from '@mui/material/styles';
import Paper from '@mui/material/Paper';
import Masonry from '@mui/lab/Masonry';
const heights = [
150, 30, 90, 70, 110, 150, 130, 80, 50, 90, 100, 150, 30, 50, 80, 150, 30, 90, 70, 110, 150, 130,
80, 50, 90, 100, 150, 30, 50, 80, 150, 30, 90, 70, 110, 150, 130, 80, 50, 90, 100, 150, 30, 50,
80, 150, 30, 90, 70, 110, 150, 130, 80, 50, 90, 100, 150, 30, 50, 80, 150, 30, 90, 70, 110, 150,
130, 80, 50, 90, 100, 150, 30, 50, 80, 150, 30, 90, 70, 110, 150, 130, 80, 50, 90, 100, 150, 30,
50, 80, 150, 30, 90, 70, 110, 150, 130, 80, 50, 90, 100, 150, 30, 50, 80, 150, 30, 90, 70, 110,
150, 130, 80, 50, 90, 100, 150, 30, 50, 80, 150, 30, 90, 70, 110, 150, 130, 80, 50, 90, 100, 150,
30, 50, 80, 150, 30, 90, 70, 110, 150, 130, 80, 50, 90, 100, 150, 30, 50, 80, 150, 30, 90, 70,
110, 150, 130, 80, 50, 90, 100, 150, 30, 50, 80, 150, 30, 90, 70, 110, 150, 130, 80, 50, 90, 100,
150, 30, 50, 80,
];
const Item = styled(Paper)(({ theme }) => ({
...theme.typography.body2,
color: theme.palette.text.secondary,
border: '1px solid black',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}));
export default function HeavyMasonry() {
return (
<Box sx={{ width: 500, minHeight: 393 }}>
<Masonry columns={3} spacing={1}>
{heights.map((height, index) => (
<Item key={index} sx={{ height }}>
{index + 1}
</Item>
))}
</Masonry>
</Box>
);
}

View File

@@ -0,0 +1,30 @@
import * as React from 'react';
import Box from '@mui/material/Box';
import { styled } from '@mui/material/styles';
import Paper from '@mui/material/Paper';
import Masonry from '@mui/lab/Masonry';
const heights = [150, 30];
const Item = styled(Paper)(({ theme }) => ({
...theme.typography.body2,
color: theme.palette.text.secondary,
border: '1px solid black',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}));
export default function HeavyMasonry() {
return (
<Box sx={{ width: 500, minHeight: 393 }}>
<Masonry columns={4} spacing={1}>
{heights.map((height, index) => (
<Item key={index} sx={{ height }}>
{index + 1}
</Item>
))}
</Masonry>
</Box>
);
}

View File

@@ -0,0 +1,32 @@
import * as React from 'react';
import Box from '@mui/material/Box';
import { styled } from '@mui/material/styles';
import Paper from '@mui/material/Paper';
import Masonry from '@mui/lab/Masonry';
const heights = [150, 30, 90, 70, 110, 150, 130, 80, 50, 90, 100, 150, 30, 50, 80];
const Item = styled(Paper)(({ theme }) => ({
backgroundColor: '#fff',
...theme.typography.body2,
padding: theme.spacing(0.5),
textAlign: 'center',
color: theme.palette.text.secondary,
...theme.applyStyles('dark', {
backgroundColor: '#1A2027',
}),
}));
export default function RemSpacingValue() {
return (
<Box sx={{ width: 500, minHeight: 393 }}>
<Masonry columns={4} spacing={'2rem'}>
{heights.map((height, index) => (
<Item key={index} sx={{ height }}>
{index + 1}
</Item>
))}
</Masonry>
</Box>
);
}

View File

@@ -0,0 +1,43 @@
import * as React from 'react';
import Paper from '@mui/material/Paper';
import Divider from '@mui/material/Divider';
import MenuList from '@mui/material/MenuList';
import MenuItem from '@mui/material/MenuItem';
import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText';
import Check from '@mui/icons-material/Check';
export default function DenseMenu() {
return (
<Paper sx={{ width: 320 }}>
<MenuList dense>
<MenuItem>
<ListItemText inset>Single</ListItemText>
</MenuItem>
<MenuItem>
<ListItemText inset>1.15</ListItemText>
</MenuItem>
<MenuItem>
<ListItemText inset>Double</ListItemText>
</MenuItem>
<MenuItem>
<ListItemIcon>
<Check />
</ListItemIcon>
Custom: 1.2
</MenuItem>
<Divider />
<MenuItem>
<ListItemText>Add space before paragraph</ListItemText>
</MenuItem>
<MenuItem>
<ListItemText>Add space after paragraph</ListItemText>
</MenuItem>
<Divider />
<MenuItem>
<ListItemText>Custom spacing...</ListItemText>
</MenuItem>
</MenuList>
</Paper>
);
}

View File

@@ -0,0 +1,75 @@
import * as React from 'react';
import IconButton from '@mui/material/IconButton';
import Box from '@mui/material/Box';
import Menu from '@mui/material/Menu';
import MenuItem from '@mui/material/MenuItem';
import MoreVertIcon from '@mui/icons-material/MoreVert';
const options = [
'None',
'Atria',
'Callisto',
'Dione',
'Ganymede',
'Hangouts Call',
'Luna',
'Oberon',
'Phobos',
'Pyxis',
'Sedna',
'Titania',
'Triton',
'Umbriel',
];
const ITEM_HEIGHT = 48;
class LongMenu extends React.Component {
buttonRef = React.createRef();
state = {
anchorEl: null,
};
componentDidMount() {
this.setState({ anchorEl: this.buttonRef.current });
}
render() {
const { anchorEl } = this.state;
const open = Boolean(anchorEl);
return (
<Box sx={{ m: '200px 0 200px', background: 'papayawhip', p: '0 100px' }}>
<IconButton
ref={this.buttonRef}
aria-label="more"
aria-owns={open ? 'long-menu' : undefined}
aria-haspopup="true"
onClick={this.handleClick}
>
<MoreVertIcon />
</IconButton>
<Menu
id="long-menu"
anchorEl={anchorEl}
open={open}
PaperProps={{
style: {
maxHeight: ITEM_HEIGHT * 4.5,
width: 200,
},
}}
>
{options.map((option) => (
<MenuItem key={option} selected={option === 'Pyxis'}>
{option}
</MenuItem>
))}
</Menu>
</Box>
);
}
}
export default LongMenu;

View File

@@ -0,0 +1,55 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import Grid from '@mui/material/Grid';
import Button from '@mui/material/Button';
import Menu from '@mui/material/Menu';
import MenuItem from '@mui/material/MenuItem';
import { styled } from '@mui/material/styles';
const MenuItemStyled = styled(MenuItem)({
'&.Mui-focusVisible': { border: '3px dashed black' },
'&.Mui-selected': { border: '3px dotted black' },
'&.Mui-focusVisible.Mui-selected': { border: '3px solid black' },
});
/**
* Item 1 or 2 can be pre-selected to check alignment between anchorEl and menuitem
*/
function SimpleMenu({ selectedItem, ...props }) {
const [anchorEl, setAnchorEl] = React.useState(null);
return (
<Grid>
<Button
style={{
// give the anchor enough space so that the menu can align the selected item
margin: '80px 0',
}}
ref={setAnchorEl}
>
open button
</Button>
<Menu anchorEl={anchorEl} open={Boolean(anchorEl)} transitionDuration={0} {...props}>
{null}
<MenuItemStyled selected={selectedItem === 1}>Item 1</MenuItemStyled>
<MenuItemStyled selected={selectedItem === 2}>Item 2</MenuItemStyled>
<MenuItemStyled>Item 3</MenuItemStyled>
</Menu>
</Grid>
);
}
SimpleMenu.propTypes = { selectedItem: PropTypes.number };
export default function MenuContentAnchors() {
return (
<Grid container>
<SimpleMenu variant="selectedMenu" />
<SimpleMenu variant="menu" />
<SimpleMenu selectedItem={1} variant="selectedMenu" />
<SimpleMenu selectedItem={1} variant="menu" />
<SimpleMenu selectedItem={2} variant="selectedMenu" />
<SimpleMenu selectedItem={2} variant="menu" />
</Grid>
);
}

View File

@@ -0,0 +1,16 @@
import * as React from 'react';
import Paper from '@mui/material/Paper';
import MenuList from '@mui/material/MenuList';
import MenuItem from '@mui/material/MenuItem';
export default function SimpleMenuList() {
return (
<Paper elevation={8}>
<MenuList>
<MenuItem>Profile</MenuItem>
<MenuItem selected>My Account</MenuItem>
<MenuItem>Logout</MenuItem>
</MenuList>
</Paper>
);
}

View File

@@ -0,0 +1,31 @@
import * as React from 'react';
import Radio from '@mui/material/Radio';
export default function RadioDisabledState() {
const [selectedValue, setSelectedValue] = React.useState('a');
const handleChange = (event) => {
setSelectedValue(event.target.value);
};
return (
<div>
<Radio
disabled
checked={selectedValue === 'a'}
onChange={handleChange}
value="a"
name="radio-buttons"
inputProps={{ 'aria-label': 'A' }}
/>
<Radio
disabled
checked={selectedValue === 'b'}
onChange={handleChange}
value="b"
name="radio-buttons"
inputProps={{ 'aria-label': 'B' }}
/>
</div>
);
}

View File

@@ -0,0 +1,12 @@
import * as React from 'react';
import Radio from '@mui/material/Radio';
import RadioButtonUncheckedIcon from '@mui/icons-material/RadioButtonUnchecked';
export default function RadioIconSizeSmall() {
return (
<div>
<Radio size="small" />
<Radio size="small" icon={<RadioButtonUncheckedIcon />} />
</div>
);
}

View File

@@ -0,0 +1,6 @@
import * as React from 'react';
import Rating from '@mui/material/Rating';
export default function FocusVisibleRating() {
return <Rating name="no-value" value={null} />;
}

View File

@@ -0,0 +1,6 @@
import * as React from 'react';
import Rating from '@mui/material/Rating';
export default function FocusVisibleRating() {
return <Rating name="no-value-precise" precision={0.5} value={0.5} />;
}

View File

@@ -0,0 +1,43 @@
import * as React from 'react';
import OutlinedInput from '@mui/material/OutlinedInput';
import InputLabel from '@mui/material/InputLabel';
import MenuItem from '@mui/material/MenuItem';
import FormHelperText from '@mui/material/FormHelperText';
import FormControl from '@mui/material/FormControl';
import Select from '@mui/material/Select';
export default function SelectAlignment() {
return (
<div>
<FormControl>
<InputLabel htmlFor="age1">Age</InputLabel>
<Select
value=""
label="Age"
id="age1"
fullWidth
input={<OutlinedInput name="age1" label="year" id="age1" />}
>
<MenuItem value="">
<em>None</em>
</MenuItem>
<MenuItem value={10}>Ten</MenuItem>
</Select>
</FormControl>
<FormControl>
<InputLabel htmlFor="age2">year</InputLabel>
<Select value={10} input={<OutlinedInput label="year" name="year" id="age2" />}>
<MenuItem value="">
<em>None</em>
</MenuItem>
<MenuItem value={10}>Ten</MenuItem>
</Select>
</FormControl>
<FormControl>
<InputLabel htmlFor="name-input">Name</InputLabel>
<OutlinedInput id="name-input" />
<FormHelperText>Alignment with an input</FormHelperText>
</FormControl>
</div>
);
}

View File

@@ -0,0 +1,29 @@
import * as React from 'react';
import MenuItem from '@mui/material/MenuItem';
import Select from '@mui/material/Select';
import Chip from '@mui/material/Chip';
const values = ['I', 'Do not', 'Overflow'];
export default function SelectChips() {
return (
<Select
multiple
value={values}
style={{ maxWidth: 100 }}
renderValue={(selected) => (
<div style={{ display: 'flex', flexWrap: 'wrap' }}>
{selected.map((value) => (
<Chip key={value} label={value} style={{ margin: 2 }} />
))}
</div>
)}
>
{values.map((value) => (
<MenuItem key={value} value={value}>
{value}
</MenuItem>
))}
</Select>
);
}

View File

@@ -0,0 +1,12 @@
import * as React from 'react';
import MenuItem from '@mui/material/MenuItem';
import Select from '@mui/material/Select';
export default function SelectMissingValue() {
return (
<Select value={0}>
<MenuItem value={0} />
<MenuItem value={10}>Ten</MenuItem>
</Select>
);
}

View File

@@ -0,0 +1,14 @@
import * as React from 'react';
import MenuItem from '@mui/material/MenuItem';
import Select from '@mui/material/Select';
export default function SelectOverflow() {
return (
<Select value={10} style={{ maxWidth: 100 }}>
<MenuItem value="">
<em>None</em>
</MenuItem>
<MenuItem value={10}>Tennnnnnn</MenuItem>
</Select>
);
}

View File

@@ -0,0 +1,84 @@
import * as React from 'react';
import Box from '@mui/joy/Box';
import Select from '@mui/joy/Select';
import Option, { optionClasses } from '@mui/joy/Option';
import Chip from '@mui/joy/Chip';
import List from '@mui/joy/List';
import ListItemDecorator, { listItemDecoratorClasses } from '@mui/joy/ListItemDecorator';
import ListDivider from '@mui/joy/ListDivider';
import ListItem from '@mui/joy/ListItem';
import Typography from '@mui/joy/Typography';
import Check from '@mui/icons-material/Check';
export default function SelectGroupedOptions() {
const group = {
Land: ['Cat', 'Dog', 'Tiger', 'Reindeer', 'Raccoon'],
Water: ['Dolphin', 'Flounder', 'Eel'],
Air: ['Falcon', 'Winged Horse', 'Owl'],
};
const colors = {
Land: 'neutral',
Water: 'primary',
Air: 'success',
};
return (
<Box sx={{ minHeight: 300 }}>
<Select
placeholder="Choose your animal"
defaultListboxOpen
slotProps={{
listbox: {
component: 'div',
sx: {
maxHeight: 240,
overflow: 'auto',
'--List-padding': '0px',
'--ListItem-radius': '0px',
},
},
}}
sx={{ width: 240 }}
>
{Object.entries(group).map(([name, animals], index) => (
<React.Fragment key={name}>
{index !== 0 && <ListDivider role="none" />}
<List
aria-labelledby={`select-group-${name}`}
sx={{ '--ListItemDecorator-size': '28px' }}
>
<ListItem id={`select-group-${name}`} sticky>
<Typography level="body-xs" textTransform="uppercase">
{name} ({animals.length})
</Typography>
</ListItem>
{animals.map((anim) => (
<Option
key={anim}
value={anim}
label={
<React.Fragment>
<Chip size="sm" color={colors[name]} sx={{ borderRadius: 'xs', mr: 1 }}>
{name}
</Chip>{' '}
{anim}
</React.Fragment>
}
sx={{
[`&.${optionClasses.selected} .${listItemDecoratorClasses.root}`]: {
opacity: 1,
},
}}
>
<ListItemDecorator sx={{ opacity: 0 }}>
<Check />
</ListItemDecorator>
{anim}
</Option>
))}
</List>
</React.Fragment>
))}
</Select>
</Box>
);
}

View File

@@ -0,0 +1,18 @@
import * as React from 'react';
import { CssVarsProvider } from '@mui/joy/styles';
import Box from '@mui/joy/Box';
import Select from '@mui/joy/Select';
import Option from '@mui/joy/Option';
export default function ListboxMinWidth() {
return (
<CssVarsProvider>
<Box sx={{ display: 'flex' }}>
<Select defaultListboxOpen placeholder="None">
<Option value="short">Short option</Option>
<Option value="long">A very long option</Option>
</Select>
</Box>
</CssVarsProvider>
);
}

View File

@@ -0,0 +1,25 @@
import * as React from 'react';
import CssBaseline from '@mui/material/CssBaseline';
import Typography from '@mui/material/Typography';
import Avatar from '@mui/material/Avatar';
import Skeleton from '@mui/material/Skeleton';
export default function SkeletonChildren() {
return (
<React.Fragment>
<CssBaseline />
<div style={{ alignItems: 'center', display: 'flex', width: '200px' }}>
<div style={{ margin: '8px' }}>
<Skeleton variant="circular">
<Avatar />
</Skeleton>
</div>
<div style={{ width: '100%' }}>
<Skeleton width="100%">
<Typography>.</Typography>
</Skeleton>
</div>
</div>
</React.Fragment>
);
}

View File

@@ -0,0 +1,10 @@
import * as React from 'react';
import Slider from '@mui/material/Slider';
export default function SimpleDisabledSlider() {
return (
<div style={{ width: 300, paddingTop: 50 }}>
<Slider defaultValue={30} valueLabelDisplay="on" disabled />
</div>
);
}

View File

@@ -0,0 +1,22 @@
import * as React from 'react';
import Box from '@mui/material/Box';
import Snackbar from '@mui/material/Snackbar';
export default function PositionedSnackbar() {
return (
<Box dir="ltr" sx={{ width: window?.innerWidth, height: '100vh' }}>
<Snackbar
key="left"
anchorOrigin={{ horizontal: 'left', vertical: 'bottom' }}
message="Snackbar should show left (LTR)"
open
/>
<Snackbar
key="right"
anchorOrigin={{ horizontal: 'right', vertical: 'top' }}
message="Snackbar should show right (LTR)"
open
/>
</Box>
);
}

View File

@@ -0,0 +1,42 @@
import * as React from 'react';
import Box from '@mui/material/Box';
import { prefixer } from 'stylis';
import rtlPlugin from '@mui/stylis-plugin-rtl';
import { StyleSheetManager } from 'styled-components';
import { CacheProvider } from '@emotion/react';
import { createTheme, ThemeProvider } from '@mui/material/styles';
import createCache from '@emotion/cache';
import Snackbar from '@mui/material/Snackbar';
// Create rtl cache
const cacheRtl = createCache({
key: 'muirtl',
stylisPlugins: [prefixer, rtlPlugin],
});
const theme = createTheme({ direction: 'rtl' });
export default function PositionedSnackbar() {
return (
<StyleSheetManager stylisPlugins={[rtlPlugin]}>
<CacheProvider value={cacheRtl}>
<ThemeProvider theme={theme}>
<Box dir="rtl" sx={{ width: window?.innerWidth, height: '100vh' }}>
<Snackbar
key="left"
anchorOrigin={{ horizontal: 'left', vertical: 'bottom' }}
message="Snackbar should show right (RTL)"
open
/>
<Snackbar
key="right"
anchorOrigin={{ horizontal: 'right', vertical: 'top' }}
message="Snackbar should show left (RTL)"
open
/>
</Box>
</ThemeProvider>
</CacheProvider>
</StyleSheetManager>
);
}

View File

@@ -0,0 +1,55 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import Avatar from '@mui/material/Avatar';
import Box from '@mui/material/Box';
import SpeedDial from '@mui/material/SpeedDial';
import SpeedDialIcon from '@mui/material/SpeedDialIcon';
import SpeedDialAction from '@mui/material/SpeedDialAction';
function SimpleSpeedDial(props) {
const tooltipPlacement = {
up: 'left',
right: 'top',
down: 'right',
left: 'bottom',
};
return (
<SpeedDial icon={<SpeedDialIcon />} open {...props}>
{['A', 'B', 'C'].map((name) => (
<SpeedDialAction
key={name}
icon={<Avatar>{name}</Avatar>}
tooltipOpen
tooltipPlacement={tooltipPlacement[props.direction]}
tooltipTitle={'Tooltip'}
/>
))}
</SpeedDial>
);
}
SimpleSpeedDial.propTypes = {
direction: PropTypes.string.isRequired,
};
function Directions() {
return (
<Box sx={{ position: 'relative', height: 360, width: 400 }}>
{['up', 'down'].map((direction) => (
<SimpleSpeedDial
sx={{
position: 'absolute',
...(direction === 'up' && { bottom: 0, right: 0 }),
...(direction === 'down' && { top: 0, left: 0 }),
}}
key={direction}
ariaLabel={direction}
direction={direction}
/>
))}
</Box>
);
}
export default Directions;

View File

@@ -0,0 +1,17 @@
import * as React from 'react';
import StepIcon from '@mui/material/StepIcon';
import GlobalStyles from '@mui/material/GlobalStyles';
export default function BiggerStepIconREM() {
return (
<React.Fragment>
<GlobalStyles
styles={{
html: { fontSize: '24px' },
}}
/>
<StepIcon completed icon={1} />
<StepIcon icon={2} />
</React.Fragment>
);
}

View File

@@ -0,0 +1,21 @@
import * as React from 'react';
import Box from '@mui/material/Box';
import Stepper from '@mui/material/Stepper';
import Step from '@mui/material/Step';
import StepLabel from '@mui/material/StepLabel';
const steps = ['Select master blaster campaign settings', 'Create an ad group', 'Create an ad'];
export default function AlternativeLabelOptionalText() {
return (
<Box sx={{ width: '100%' }}>
<Stepper activeStep={1} alternativeLabel>
{steps.map((label) => (
<Step key={label} expanded>
<StepLabel optional="optional">{label}</StepLabel>
</Step>
))}
</Stepper>
</Box>
);
}

View File

@@ -0,0 +1,24 @@
import * as React from 'react';
import Stepper from '@mui/material/Stepper';
import Step from '@mui/material/Step';
import StepLabel from '@mui/material/StepLabel';
function TestIcon() {
return <div style={{ border: '1px solid red' }}>should not shrink</div>;
}
const steps = ['Step 1', 'Step 2'];
export default function NoShrinkIcon() {
return (
<Stepper sx={{ width: 200 }}>
{steps.map((label) => (
<Step key={label}>
<StepLabel StepIconComponent={TestIcon} sx={{ width: '1px' }}>
{label}
</StepLabel>
</Step>
))}
</Stepper>
);
}

View File

@@ -0,0 +1,27 @@
import * as React from 'react';
import { createTheme, ThemeProvider } from '@mui/material/styles';
import SvgIcon from '@mui/material/SvgIcon';
function FavoriteRounded(props) {
return (
<SvgIcon {...props}>
<path d="M13.35 20.13c-.76.69-1.93.69-2.69-.01l-.11-.1C5.3 15.27 1.87 12.16 2 8.28c.06-1.7.93-3.33 2.34-4.29 2.64-1.8 5.9-.96 7.66 1.1 1.76-2.06 5.02-2.91 7.66-1.1 1.41.96 2.28 2.59 2.34 4.29.14 3.88-3.3 6.99-8.55 11.76l-.1.09z" />
</SvgIcon>
);
}
export default function CustomColorSvgIcon() {
const theme = createTheme({
palette: {
custom: { main: '#ec407a' },
},
});
return (
<ThemeProvider theme={theme}>
<FavoriteRounded fontSize="large" />
<FavoriteRounded fontSize="large" color="secondary" />
<FavoriteRounded fontSize="large" color="custom" />
</ThemeProvider>
);
}

View File

@@ -0,0 +1,20 @@
import * as React from 'react';
import { CssVarsProvider } from '@mui/joy/styles';
import Box from '@mui/joy/Box';
import Switch from '@mui/joy/Switch';
export default function SwitchJoy() {
return (
<CssVarsProvider>
<Box sx={{ display: 'grid', gap: '1rem', gridTemplateColumns: 'repeat(4, min-content)' }}>
<Switch />
<Switch defaultChecked />
<Switch defaultChecked color="success" />
<Switch variant="outlined" />
<Switch variant="outlined" defaultChecked />
<Switch variant="soft" />
<Switch variant="soft" defaultChecked />
</Box>
</CssVarsProvider>
);
}

View File

@@ -0,0 +1,64 @@
import * as React from 'react';
import Box from '@mui/material/Box';
import Checkbox from '@mui/material/Checkbox';
import Table from '@mui/material/Table';
import TableBody from '@mui/material/TableBody';
import TableCell from '@mui/material/TableCell';
import TableHead from '@mui/material/TableHead';
import TableRow from '@mui/material/TableRow';
import Paper from '@mui/material/Paper';
let id = 0;
function createData(name, calories, fat, carbs, protein) {
id += 1;
return { id, name, calories, fat, carbs, protein };
}
const rows = [
createData('Frozen yoghurt', 159, 6.0, 24, 4.0),
createData('Ice cream sandwich', 237, 9.0, 37, 4.3),
createData('Eclair', 262, 16.0, 24, 6.0),
createData('Cupcake', 305, 3.7, 67, 4.3),
createData('Gingerbread', 356, 16.0, 49, 3.9),
];
function DenseCheckboxTable() {
return (
<Box sx={{ width: '100%' }}>
<Paper sx={{ mt: 3, width: '100%', overflowX: 'auto', mb: 2 }}>
<Table sx={{ minWidth: 650 }} size="small">
<TableHead>
<TableRow>
<TableCell padding="checkbox">
<Checkbox />
</TableCell>
<TableCell padding="none">Dessert (100g serving)</TableCell>
<TableCell align="right">Calories</TableCell>
<TableCell align="right">Fat&nbsp;(g)</TableCell>
<TableCell align="right">Carbs&nbsp;(g)</TableCell>
<TableCell align="right">Protein&nbsp;(g)</TableCell>
</TableRow>
</TableHead>
<TableBody>
{rows.map((row) => (
<TableRow key={row.id}>
<TableCell padding="checkbox">
<Checkbox />
</TableCell>
<TableCell padding="none" component="th" scope="row">
{row.name}
</TableCell>
<TableCell align="right">{row.calories}</TableCell>
<TableCell align="right">{row.fat}</TableCell>
<TableCell align="right">{row.carbs}</TableCell>
<TableCell align="right">{row.protein}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</Paper>
</Box>
);
}
export default DenseCheckboxTable;

View File

@@ -0,0 +1,36 @@
import * as React from 'react';
import { prefixer } from 'stylis';
import rtlPlugin from '@mui/stylis-plugin-rtl';
import { CacheProvider } from '@emotion/react';
import createCache from '@emotion/cache';
import { StyleSheetManager } from 'styled-components';
import { ThemeProvider, createTheme } from '@mui/material/styles';
import Box from '@mui/material/Box';
import Tabs from '@mui/material/Tabs';
import Tab from '@mui/material/Tab';
// Create rtl cache
const cacheRtl = createCache({
key: 'muirtl',
stylisPlugins: [prefixer, rtlPlugin],
});
export default function RTLVerticalTabs() {
return (
<StyleSheetManager stylisPlugins={[rtlPlugin]}>
<CacheProvider value={cacheRtl}>
<ThemeProvider theme={createTheme({ direction: 'rtl' })}>
<Box dir="rtl" sx={{ height: 200, display: 'flex' }}>
<Tabs value={2} variant="scrollable" scrollButtons orientation="vertical">
<Tab label="Tab A" />
<Tab label="Tab B" />
<Tab label="Tab C" />
<Tab label="Tab D" />
<Tab label="Tab E" />
</Tabs>
</Box>
</ThemeProvider>
</CacheProvider>
</StyleSheetManager>
);
}

View File

@@ -0,0 +1,55 @@
import * as React from 'react';
import TextField from '@mui/material/TextField';
import Visibility from '@mui/icons-material/Visibility';
import InputAdornment from '@mui/material/InputAdornment';
export default function BaselineAlignTextField() {
return (
<div>
<div
style={{
display: 'flex',
flexDirection: 'row',
alignItems: 'baseline',
}}
>
Base
<TextField
label="label"
placeholder="placeholder"
variant="standard"
InputProps={{
startAdornment: (
<InputAdornment position="start">
<Visibility />
</InputAdornment>
),
}}
/>
Base
</div>
<div
style={{
display: 'flex',
flexDirection: 'row',
alignItems: 'baseline',
}}
>
Base
<TextField
label="label"
placeholder="placeholder"
variant="standard"
InputProps={{
endAdornment: (
<InputAdornment position="end">
<Visibility />
</InputAdornment>
),
}}
/>
Base
</div>
</div>
);
}

View File

@@ -0,0 +1,16 @@
import * as React from 'react';
import TextField from '@mui/material/TextField';
// TextField shouldn't overflow the red bordered container
export default function ConstrainedTextField() {
return (
<div
style={{
width: 100,
border: '1px solid red',
}}
>
<TextField label="Outlined" variant="outlined" />
</div>
);
}

View File

@@ -0,0 +1,17 @@
import * as React from 'react';
import TextField from '@mui/material/TextField';
import InputAdornment from '@mui/material/InputAdornment';
export default function FilledHiddenLabelInputAdornment() {
return (
<TextField
hiddenLabel
id="filled-hidden-label"
defaultValue="Value"
variant="filled"
InputProps={{
startAdornment: <InputAdornment position="start">kg</InputAdornment>,
}}
/>
);
}

View File

@@ -0,0 +1,26 @@
import * as React from 'react';
import TextField from '@mui/material/TextField';
export default function FilledMultilineHiddenLabelTextField() {
return (
<div>
<TextField
variant="filled"
defaultValue="Multiline Default Value"
multiline
rows={1}
hiddenLabel
/>
<TextField variant="filled" defaultValue="Default Value" hiddenLabel />
<TextField
variant="filled"
defaultValue="Multiline Default Value"
multiline
rows={1}
hiddenLabel
size="small"
/>
<TextField variant="filled" defaultValue="Default Value" hiddenLabel size="small" />
</div>
);
}

View File

@@ -0,0 +1,11 @@
import * as React from 'react';
import TextField from '@mui/material/TextField';
export default function MultilineTextField() {
return (
<div>
<TextField label="multiline small" multiline size="small" />
<TextField label="singleline small" size="small" />
</div>
);
}

View File

@@ -0,0 +1,16 @@
import * as React from 'react';
import TextField from '@mui/material/TextField';
export default function OutlinedHiddenRequiredIndicator() {
return (
<TextField
label="Name"
variant="outlined"
required
InputLabelProps={{
shrink: true,
required: false,
}}
/>
);
}

View File

@@ -0,0 +1,49 @@
import * as React from 'react';
import Input from '@mui/material/Input';
function Textarea() {
const [value, setValue] = React.useState(
`Hey, sorry for being late to respond. Here is a codesandbox. It actually happens when I reduce the font-size of the input. Try adding some text or paste a long paragraph and you will the bottom margin being increased. It works fine with the default font-size.`,
);
const handleChange = (event) => {
setValue(event.target.value);
};
return (
<div>
<Input
sx={{
width: 200,
'& .MuiInput-input': {
fontSize: 13,
boxSizing: 'border-box',
border: '10px solid black',
},
}}
multiline
value={value}
onChange={handleChange}
/>
<Input
sx={{
width: 200,
'& .MuiInput-input': { fontSize: 13, boxSizing: 'content-box', padding: '10px' },
}}
multiline
value={value}
onChange={handleChange}
/>
<Input style={{ width: 200 }} multiline placeholder="rows" rows={3} />
<Input style={{ width: 200 }} multiline value={value} onChange={handleChange} maxRows={4} />
<Input style={{ width: 200 }} multiline placeholder="long placeholder long placeholder" />
<Input
style={{ width: 200 }}
multiline
defaultValue="long default value long default value"
/>
</div>
);
}
export default Textarea;

View File

@@ -0,0 +1,25 @@
import * as React from 'react';
import Input from '@mui/material/Input';
export default function TextareaAutosize() {
const [value, setValue] = React.useState('');
const handleChange = (event) => {
setValue(event.target.value);
};
return (
<Input
style={{ width: 200 }}
multiline
minRows={4}
onChange={handleChange}
value={value}
slotProps={{
input: {
'data-testid': 'input',
},
}}
/>
);
}

View File

@@ -0,0 +1,46 @@
import * as React from 'react';
import ToggleButton from '@mui/material/ToggleButton';
import ToggleButtonGroup from '@mui/material/ToggleButtonGroup';
import Stack from '@mui/material/Stack';
import Tooltip from '@mui/material/Tooltip';
export default function DifferentChildren() {
const falsyCondition = 1 === 2;
return (
<Stack spacing={2}>
{/* With tooltip */}
<ToggleButtonGroup value="one">
<Tooltip title="tooltip">
<ToggleButton value="one">One</ToggleButton>
</Tooltip>
<Tooltip title="tooltip">
<span>
<ToggleButton value="two" disabled>
Two
</ToggleButton>
</span>
</Tooltip>
<Tooltip title="tooltip">
<span>
<ToggleButton value="three" disabled>
Three
</ToggleButton>
</span>
</Tooltip>
</ToggleButtonGroup>
{/* Single button */}
<ToggleButtonGroup value="one">
<ToggleButton value="one">One</ToggleButton>
</ToggleButtonGroup>
{/* Conditional elements */}
<ToggleButtonGroup value="one">
<ToggleButton value="one">One</ToggleButton>
<ToggleButton value="two">Two</ToggleButton>
{falsyCondition ? <ToggleButton value="three">Three</ToggleButton> : undefined}
</ToggleButtonGroup>
</Stack>
);
}

View File

@@ -0,0 +1,73 @@
import * as React from 'react';
import Box from '@mui/material/Box';
import Grid from '@mui/material/Grid';
import Button from '@mui/material/Button';
import Tooltip from '@mui/material/Tooltip';
// Used /docs/data/material/components/tooltips/PositionedTooltips.js as inspiration.
function PositionedTooltips() {
return (
<Box sx={{ width: 400, padding: '50px 70px' }}>
<Grid container justifyContent="center">
<Grid>
<Tooltip open arrow title="Add" placement="top-start">
<Button>top-start</Button>
</Tooltip>
<Tooltip open arrow title="Add" placement="top">
<Button>top</Button>
</Tooltip>
<Tooltip open arrow title="Add" placement="top-end">
<Button>top-end</Button>
</Tooltip>
</Grid>
</Grid>
<Grid container justifyContent="center">
<Grid size={6}>
<Tooltip open arrow title="Add" placement="left-start">
<Button>left-start</Button>
</Tooltip>
<br />
<Tooltip open arrow title="Add" placement="left">
<Button>left</Button>
</Tooltip>
<br />
<Tooltip open arrow title="Add" placement="left-end">
<Button>left-end</Button>
</Tooltip>
</Grid>
<Grid container alignItems="flex-end" direction="column" size={6}>
<Grid>
<Tooltip open arrow title="Add" placement="right-start">
<Button>right-start</Button>
</Tooltip>
</Grid>
<Grid>
<Tooltip open arrow title="Add" placement="right">
<Button>right</Button>
</Tooltip>
</Grid>
<Grid>
<Tooltip open arrow title="Add" placement="right-end">
<Button>right-end</Button>
</Tooltip>
</Grid>
</Grid>
</Grid>
<Grid container justifyContent="center">
<Grid>
<Tooltip open arrow title="Add" placement="bottom-start">
<Button>bottom-start</Button>
</Tooltip>
<Tooltip open arrow title="Add" placement="bottom">
<Button>bottom</Button>
</Tooltip>
<Tooltip open arrow title="Add" placement="bottom-end">
<Button>bottom-end</Button>
</Tooltip>
</Grid>
</Grid>
</Box>
);
}
export default PositionedTooltips;

View File

@@ -0,0 +1,90 @@
import * as React from 'react';
import Box from '@mui/material/Box';
import Grid from '@mui/material/Grid';
import Button from '@mui/material/Button';
import Tooltip from '@mui/material/Tooltip';
import { prefixer } from 'stylis';
import rtlPlugin from '@mui/stylis-plugin-rtl';
import { StyleSheetManager } from 'styled-components';
import { CacheProvider } from '@emotion/react';
import { createTheme, ThemeProvider } from '@mui/material/styles';
import createCache from '@emotion/cache';
// Create rtl cache
const cacheRtl = createCache({
key: 'muirtl',
stylisPlugins: [prefixer, rtlPlugin],
});
const theme = createTheme({ direction: 'rtl' });
export default function PositionedTooltipsRtl() {
return (
<StyleSheetManager stylisPlugins={[rtlPlugin]}>
<CacheProvider value={cacheRtl}>
<ThemeProvider theme={theme}>
<Box sx={{ width: 500, margin: 10 }} dir="rtl">
<Grid container justifyContent="center">
<Grid>
<Tooltip title="Add" arrow open placement="top-start">
<Button>top-start</Button>
</Tooltip>
<Tooltip title="Add" arrow open placement="top">
<Button>top</Button>
</Tooltip>
<Tooltip title="Add" arrow open placement="top-end">
<Button>top-end</Button>
</Tooltip>
</Grid>
</Grid>
<Grid container justifyContent="center">
<Grid size={6}>
<Tooltip title="Add" arrow open placement="left-start">
<Button>left-start</Button>
</Tooltip>
<br />
<Tooltip title="Add" arrow open placement="left">
<Button>left</Button>
</Tooltip>
<br />
<Tooltip title="Add" arrow open placement="left-end">
<Button>left-end</Button>
</Tooltip>
</Grid>
<Grid container alignItems="flex-end" direction="column" size={6}>
<Grid>
<Tooltip title="Add" arrow open placement="right-start">
<Button>right-start</Button>
</Tooltip>
</Grid>
<Grid>
<Tooltip title="Add" arrow open placement="right">
<Button>right</Button>
</Tooltip>
</Grid>
<Grid>
<Tooltip title="Add" arrow open placement="right-end">
<Button>right-end</Button>
</Tooltip>
</Grid>
</Grid>
</Grid>
<Grid container justifyContent="center">
<Grid>
<Tooltip title="Add" arrow open placement="bottom-start">
<Button>bottom-start</Button>
</Tooltip>
<Tooltip title="Add" arrow open placement="bottom">
<Button>bottom</Button>
</Tooltip>
<Tooltip title="Add" arrow open placement="bottom-end">
<Button>bottom-end</Button>
</Tooltip>
</Grid>
</Grid>
</Box>
</ThemeProvider>
</CacheProvider>
</StyleSheetManager>
);
}

View File

@@ -0,0 +1,42 @@
import * as React from 'react';
import { CssVarsProvider } from '@mui/joy/styles';
import Box from '@mui/joy/Box';
import Typography from '@mui/joy/Typography';
import Link from '@mui/joy/Link';
export default function DecoratorAlignItemsStart() {
return (
<CssVarsProvider>
<Typography startDecorator="✅" alignItems="flex-start" sx={{ width: 160 }}>
Hello World, this is a very long sentence.
</Typography>
<Typography
startDecorator={
<Box
component="span"
sx={{ bgcolor: 'tomato', width: '1.25em', height: '1.25em', borderRadius: '50%' }}
/>
}
alignItems="flex-start"
sx={{ width: 160 }}
>
Hello World, this is a very long sentence.
</Typography>
<Link href="/" startDecorator="✅" sx={{ width: 160, alignItems: 'flex-start' }}>
Hello World, this is a very long sentence.
</Link>
<Link
href="/"
startDecorator={
<Box
component="span"
sx={{ bgcolor: 'tomato', width: '1.25em', height: '1.25em', borderRadius: '50%' }}
/>
}
sx={{ width: 160, alignItems: 'flex-start' }}
>
Hello World, this is a very long sentence.
</Link>
</CssVarsProvider>
);
}

View File

@@ -0,0 +1,34 @@
import * as React from 'react';
import { styled } from '@mui/material/styles';
const Child = styled('div', {
target: 'child', // simulate a class name from @emotion/babel-plugin
})({
color: 'blue',
});
const Parent = styled('div')`
${Child} {
color: red;
}
`;
const Parent2 = styled('div')({
[Child]: {
color: 'red',
},
});
export default function ComponentSelector() {
return (
<div>
<Child>I am blue.</Child>
<Parent>
<Child>I am red (literal).</Child>
</Parent>
<Parent2>
<Child>I am red (object).</Child>
</Parent2>
</div>
);
}

View File

@@ -0,0 +1,19 @@
<!doctype html>
<html>
<head>
<title>Visual regression tests</title>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1, width=device-width" />
<style>
body {
background-color: white;
}
</style>
</head>
<body>
<div id="test-viewer"></div>
<div id="react-root"></div>
<script type="module" src="/index.jsx"></script>
</body>
</html>

Some files were not shown because too many files have changed in this diff Show More