I’m working on a Week picker based on MUI X official documentation :
https://mui.com/x/react-date-pickers/date-calendar/#week-picker
This works quite well, except that the input displays the click date as the value. In my case, I’d like the input to display the week number of the year with the year as the value. I don’t know if this is possible, as the input props expects a date.
What I want : week 43 – 2023
Current component code
import * as React from 'react';
import { useState } from 'react';
import { isSameWeek } from 'date-fns';
import { styled } from '@mui/material/styles';
import { DatePicker } from '@mui/x-date-pickers';
import { PickersDay, PickersDayProps } from '@mui/x-date-pickers/PickersDay';
import { useTheme } from '@mui/material/styles';
interface CustomPickerDayProps extends PickersDayProps<Date> {
isSelected: boolean;
isHovered: boolean;
}
const CustomPickersDay = styled(PickersDay, {
shouldForwardProp: (prop) => prop !== 'isSelected' && prop !== 'isHovered',
})<CustomPickerDayProps>(({ theme, isSelected, isHovered, day }) => ({
borderRadius: 0,
...(isSelected && {
backgroundColor: theme.palette.primary.main,
color: theme.palette.primary.contrastText,
'&:hover, &:focus': {
backgroundColor: theme.palette.primary.main,
},
}),
...(isHovered && {
backgroundColor: theme.palette.primary[theme.palette.mode],
'&:hover, &:focus': {
backgroundColor: theme.palette.primary[theme.palette.mode],
},
}),
...(day.getDay() === 1 && {
borderTopLeftRadius: '50%',
borderBottomLeftRadius: '50%',
}),
...(day.getDay() === 0 && {
borderTopRightRadius: '50%',
borderBottomRightRadius: '50%',
}),
})) as React.ComponentType<CustomPickerDayProps>;
const isInSameWeek = (dayA: Date, dayB: Date | null | undefined) => {
if (dayB == null) {
return false;
}
return isSameWeek(dayA, dayB, { weekStartsOn: 1 });
};
function Day(
props: PickersDayProps<Date> & {
selectedDay?: Date | null;
hoveredDay?: Date | null;
},
) {
const { day, selectedDay, hoveredDay, ...other } = props;
return (
<CustomPickersDay
{...other}
day={day}
sx={{ px: 2.5 }}
disableMargin
selected={false}
isSelected={isInSameWeek(day, selectedDay)}
isHovered={isInSameWeek(day, hoveredDay)}
/>
);
}
export default function WeekCalendar({ onChange }: { onChange: (newValue: Date | null) => void }) {
const [hoveredDay, setHoveredDay] = useState<Date | null>(null);
const [value, setValue] = useState<Date | null>(new Date('2022-04-17'));
const theme = useTheme();
const handleDateChange = (newValue: Date | null) => {
setValue(newValue);
onChange(newValue);
};
return (
<DatePicker
value={value}
onChange={handleDateChange}
showDaysOutsideCurrentMonth
displayWeekNumber
slots={{ day: Day }}
slotProps={{
day: (ownerState) =>
({
selectedDay: value,
hoveredDay,
onPointerEnter: () => setHoveredDay(ownerState.day),
onPointerLeave: () => setHoveredDay(null),
} as any),
}}
sx={{
marginTop: '12px',
marginRight: '20px',
'& .MuiInputBase-input': {
padding: '5px',
color: theme.palette.text.secondary,
fontSize: '14px',
},
'& .MuiSvgIcon-root': {
color: theme.palette.text.secondary,
width: '20px',
}
}}
/>
);
}
As an alternative approach, I’ve tried using format and the “w” option, which according to date-fns should give the number of the week in the year, but it doesn’t work.
If you have any ideas, I’d love to hear from you.