Skip to content

Commit

Permalink
[pickers] Use grid for modifying the layout (#6900)
Browse files Browse the repository at this point in the history
Co-authored-by: Lukas <llukas.tyla@gmail.com>
  • Loading branch information
alexfauquette and LukasTy authored Dec 26, 2022
1 parent 7b36870 commit 6cce314
Show file tree
Hide file tree
Showing 137 changed files with 1,507 additions and 369 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ components: DateTimePickerTabs

# Custom components

<p class="description">The date picker lets users select a date from a menu.</p>
<p class="description">The date picker lets you customize sub-components.</p>

## Overriding components

Expand Down
106 changes: 106 additions & 0 deletions docs/data/date-pickers/custom-layout/AddComponent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import * as React from 'react';
import PropTypes from 'prop-types';

import Box from '@mui/material/Box';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import ListItemButton from '@mui/material/ListItemButton';
import ListItemText from '@mui/material/ListItemText';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { Unstable_StaticNextDatePicker as StaticNextDatePicker } from '@mui/x-date-pickers/StaticNextDatePicker';

import RestaurantIcon from '@mui/icons-material/Restaurant';
import {
usePickerLayout,
pickersLayoutClasses,
PickersLayoutRoot,
PickersLayoutContentWrapper,
} from '@mui/x-date-pickers/PickersLayout';

function ActionList(props) {
const { onAccept, onClear, onCancel, onSetToday } = props;
const actions = [
{ text: 'Accept', method: onAccept },
{ text: 'Clear', method: onClear },
{ text: 'Cancel', method: onCancel },
{ text: 'Today', method: onSetToday },
];

return (
<List>
{actions.map(({ text, method }) => (
<ListItem key={text} disablePadding>
<ListItemButton onClick={method}>
<ListItemText primary={text} />
</ListItemButton>
</ListItem>
))}
</List>
);
}

ActionList.propTypes = {
onAccept: PropTypes.func.isRequired,
onCancel: PropTypes.func.isRequired,
onClear: PropTypes.func.isRequired,
onSetToday: PropTypes.func.isRequired,
};

function RestaurantHeader() {
return (
<Box
sx={{
// Place the element in the grid layout
gridColumn: 1,
gridRow: 1,
// Center the icon
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
}}
>
<RestaurantIcon />
</Box>
);
}

function CustomLayout(props) {
const { toolbar, tabs, content, actionBar } = usePickerLayout(props);

return (
<PickersLayoutRoot
ownerState={props}
sx={{
[`.${pickersLayoutClasses.actionBar}`]: {
gridColumn: 1,
gridRow: 2,
},
[`.${pickersLayoutClasses.toolbar}`]: {
gridColumn: 2,
gridRow: 1,
},
}}
>
<RestaurantHeader />
{toolbar}
{actionBar}
<PickersLayoutContentWrapper className={pickersLayoutClasses.contentWrapper}>
{tabs}
{content}
</PickersLayoutContentWrapper>
</PickersLayoutRoot>
);
}
export default function AddComponent() {
return (
<LocalizationProvider dateAdapter={AdapterDayjs}>
<StaticNextDatePicker
components={{
Layout: CustomLayout,
ActionBar: ActionList,
}}
/>
</LocalizationProvider>
);
}
99 changes: 99 additions & 0 deletions docs/data/date-pickers/custom-layout/AddComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import * as React from 'react';
import { Dayjs } from 'dayjs';
import Box from '@mui/material/Box';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import ListItemButton from '@mui/material/ListItemButton';
import ListItemText from '@mui/material/ListItemText';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { Unstable_StaticNextDatePicker as StaticNextDatePicker } from '@mui/x-date-pickers/StaticNextDatePicker';
import { PickersActionBarProps } from '@mui/x-date-pickers/PickersActionBar';
import RestaurantIcon from '@mui/icons-material/Restaurant';
import {
PickersLayoutProps,
usePickerLayout,
pickersLayoutClasses,
PickersLayoutRoot,
PickersLayoutContentWrapper,
} from '@mui/x-date-pickers/PickersLayout';
import { DateView } from '@mui/x-date-pickers';

function ActionList(props: PickersActionBarProps) {
const { onAccept, onClear, onCancel, onSetToday } = props;
const actions = [
{ text: 'Accept', method: onAccept },
{ text: 'Clear', method: onClear },
{ text: 'Cancel', method: onCancel },
{ text: 'Today', method: onSetToday },
];
return (
<List>
{actions.map(({ text, method }) => (
<ListItem key={text} disablePadding>
<ListItemButton onClick={method}>
<ListItemText primary={text} />
</ListItemButton>
</ListItem>
))}
</List>
);
}

function RestaurantHeader() {
return (
<Box
sx={{
// Place the element in the grid layout
gridColumn: 1,
gridRow: 1,
// Center the icon
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
}}
>
<RestaurantIcon />
</Box>
);
}

function CustomLayout(props: PickersLayoutProps<Dayjs | null, DateView>) {
const { toolbar, tabs, content, actionBar } = usePickerLayout(props);

return (
<PickersLayoutRoot
ownerState={props}
sx={{
[`.${pickersLayoutClasses.actionBar}`]: {
gridColumn: 1,
gridRow: 2,
},
[`.${pickersLayoutClasses.toolbar}`]: {
gridColumn: 2,
gridRow: 1,
},
}}
>
<RestaurantHeader />
{toolbar}
{actionBar}
<PickersLayoutContentWrapper className={pickersLayoutClasses.contentWrapper}>
{tabs}
{content}
</PickersLayoutContentWrapper>
</PickersLayoutRoot>
);
}
export default function AddComponent() {
return (
<LocalizationProvider dateAdapter={AdapterDayjs}>
<StaticNextDatePicker
components={{
Layout: CustomLayout,
ActionBar: ActionList,
}}
/>
</LocalizationProvider>
);
}
6 changes: 6 additions & 0 deletions docs/data/date-pickers/custom-layout/AddComponent.tsx.preview
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<StaticNextDatePicker
components={{
Layout: CustomLayout,
ActionBar: ActionList,
}}
/>
135 changes: 135 additions & 0 deletions docs/data/date-pickers/custom-layout/LayoutBlocks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import * as React from 'react';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import ToggleButton from '@mui/material/ToggleButton';
import ToggleButtonGroup from '@mui/material/ToggleButtonGroup';
import Box from '@mui/material/Box';
import Stack from '@mui/material/Stack';
import Divider from '@mui/material/Divider';
import { Unstable_StaticNextDatePicker as StaticNextDatePicker } from '@mui/x-date-pickers/StaticNextDatePicker';
import { Unstable_StaticNextTimePicker as StaticNextTimePicker } from '@mui/x-date-pickers/StaticNextTimePicker';
import { Unstable_StaticNextDateTimePicker as StaticNextDateTimePicker } from '@mui/x-date-pickers/StaticNextDateTimePicker';
import { useTheme } from '@mui/material/styles';
import useMediaQuery from '@mui/material/useMediaQuery';
import { pickersLayoutClasses } from '@mui/x-date-pickers/PickersLayout';

const highlighLayout = {
sx: {
[`& .${pickersLayoutClasses.toolbar}`]: {
border: 'solid red 4px',
},
[`& .${pickersLayoutClasses.contentWrapper}`]: {
border: 'solid green 4px',
},
[`& .${pickersLayoutClasses.actionBar}`]: {
border: 'solid blue 4px',
},
},
};

export default function LayoutBlocks() {
const theme = useTheme();
const isDesktop = useMediaQuery(theme.breakpoints.up('md'));
const [currentComponent, setCurrentComponent] = React.useState('date');
const [orientation, setOrientation] = React.useState('portrait');

return (
<LocalizationProvider dateAdapter={AdapterDayjs}>
<Box
sx={{
flexGrow: 1,
width: '100%',
display: 'flex',
flexDirection: { xs: 'column', md: 'row' },
}}
>
<Box
sx={{
flexShrink: 0,
px: 3,
pb: 2,
minWidth: '150px',
}}
>
<Stack spacing={2} alignItems="center" direction="column">
<ToggleButtonGroup
size="small"
fullWidth
color="primary"
value={currentComponent}
orientation={isDesktop ? 'vertical' : 'horizontal'}
onChange={(event, value) => {
if (value !== null) {
setCurrentComponent(value);
}
}}
exclusive
>
<ToggleButton value={'date'}>date picker</ToggleButton>
<ToggleButton value={'time'}>time picker</ToggleButton>
<ToggleButton value={'date-time'}>date time picker</ToggleButton>
</ToggleButtonGroup>

<ToggleButtonGroup
size="small"
fullWidth
color="primary"
value={orientation}
orientation={isDesktop ? 'vertical' : 'horizontal'}
onChange={(event, value) => {
if (value !== null) {
setOrientation(value);
}
}}
exclusive
>
<ToggleButton value={'landscape'}>landscape</ToggleButton>
<ToggleButton value={'portrait'}>portrait</ToggleButton>
</ToggleButtonGroup>
</Stack>
</Box>
<Divider orientation={isDesktop ? 'vertical' : 'horizontal'} />
<Box
sx={{
display: 'flex',
flexDirection: 'column',
flexGrow: 999,
minWidth: 0,
p: 3,
}}
>
<Box sx={{ margin: 'auto' }}>
{currentComponent === 'date' && (
<StaticNextDatePicker
orientation={orientation}
componentsProps={{
layout: highlighLayout,
}}
/>
)}

{currentComponent === 'time' && (
<Box sx={{ position: 'relative' }}>
<StaticNextTimePicker
orientation={orientation}
componentsProps={{
layout: highlighLayout,
}}
/>
</Box>
)}

{currentComponent === 'date-time' && (
<StaticNextDateTimePicker
orientation={orientation}
componentsProps={{
layout: highlighLayout,
}}
/>
)}
</Box>
</Box>
</Box>
</LocalizationProvider>
);
}
Loading

0 comments on commit 6cce314

Please sign in to comment.