Redesign DatePicker (#108)
This commit is contained in:
@ -1,6 +1,6 @@
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import React, { ReactElement, forwardRef, useState } from 'react';
|
import React, { ReactElement, forwardRef, useState } from 'react';
|
||||||
import ReactDatePicker from 'react-datepicker';
|
import ReactDatePicker, { CalendarContainerProps } from 'react-datepicker';
|
||||||
|
|
||||||
import 'react-datepicker/dist/react-datepicker.css';
|
import 'react-datepicker/dist/react-datepicker.css';
|
||||||
|
|
||||||
@ -9,12 +9,17 @@ export type DatePickerProps = {
|
|||||||
date: Date;
|
date: Date;
|
||||||
onChangeHandler: (date: Date) => void;
|
onChangeHandler: (date: Date) => void;
|
||||||
customInput?: ReactElement;
|
customInput?: ReactElement;
|
||||||
|
customContainer?(props: CalendarContainerProps): React.ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
const StyledContainer = styled.div`
|
||||||
& .react-datepicker {
|
& .react-datepicker {
|
||||||
border-color: ${(props) => props.theme.primaryBorder};
|
border-color: ${(props) => props.theme.primaryBorder};
|
||||||
|
background: transparent;
|
||||||
font-family: 'Inter';
|
font-family: 'Inter';
|
||||||
|
font-size: ${(props) => props.theme.fontSizeMedium};
|
||||||
|
border: none;
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
& .react-datepicker__triangle::after {
|
& .react-datepicker__triangle::after {
|
||||||
@ -25,17 +30,150 @@ const StyledContainer = styled.div`
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Header
|
||||||
|
|
||||||
& .react-datepicker__header {
|
& .react-datepicker__header {
|
||||||
background-color: ${(props) => props.theme.primaryBackground};
|
background: transparent;
|
||||||
border-bottom-color: ${(props) => props.theme.primaryBorder};
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .react-datepicker__header__dropdown {
|
||||||
|
display: flex;
|
||||||
|
margin-left: ${(props) => props.theme.spacing(1)};
|
||||||
|
margin-bottom: ${(props) => props.theme.spacing(1)};
|
||||||
|
}
|
||||||
|
|
||||||
|
& .react-datepicker__month-dropdown-container,
|
||||||
|
& .react-datepicker__year-dropdown-container {
|
||||||
|
text-align: left;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin-left: ${(props) => props.theme.spacing(1)};
|
||||||
|
margin-right: 0;
|
||||||
|
padding: ${(props) => props.theme.spacing(2)};
|
||||||
|
padding-right: ${(props) => props.theme.spacing(4)};
|
||||||
|
background-color: ${(props) => props.theme.tertiaryBackground};
|
||||||
|
}
|
||||||
|
|
||||||
|
& .react-datepicker__month-read-view--down-arrow,
|
||||||
|
& .react-datepicker__year-read-view--down-arrow {
|
||||||
|
height: 5px;
|
||||||
|
width: 5px;
|
||||||
|
border-width: 1px 1px 0 0;
|
||||||
|
border-color: ${(props) => props.theme.text40};
|
||||||
|
top: 3px;
|
||||||
|
right: -6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .react-datepicker__year-read-view,
|
||||||
|
& .react-datepicker__month-read-view {
|
||||||
|
padding-right: ${(props) => props.theme.spacing(2)};
|
||||||
|
}
|
||||||
|
|
||||||
|
& .react-datepicker__month-dropdown-container {
|
||||||
|
width: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .react-datepicker__year-dropdown-container {
|
||||||
|
width: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .react-datepicker__month-dropdown {
|
||||||
|
left: ${(props) => props.theme.spacing(2)};
|
||||||
|
top: ${(props) => props.theme.spacing(2)};
|
||||||
|
width: calc(80px + ${(props) => props.theme.spacing(6)});
|
||||||
|
border: ${(props) => props.theme.primaryBorder};
|
||||||
|
}
|
||||||
|
|
||||||
|
& .react-datepicker__year-dropdown {
|
||||||
|
left: calc(${(props) => props.theme.spacing(9)} + 80px);
|
||||||
|
top: ${(props) => props.theme.spacing(2)};
|
||||||
|
width: calc(50px + ${(props) => props.theme.spacing(6)});
|
||||||
|
border: ${(props) => props.theme.primaryBorder};
|
||||||
|
}
|
||||||
|
|
||||||
|
& .react-datepicker__navigation--years {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .react-datepicker__month-option--selected,
|
||||||
|
& .react-datepicker__year-option--selected {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .react-datepicker__year-option,
|
||||||
|
& .react-datepicker__month-option {
|
||||||
|
line-height: 32px;
|
||||||
|
text-align: left;
|
||||||
|
padding-left: ${(props) => props.theme.spacing(2)};
|
||||||
|
width: calc(100% - ${(props) => props.theme.spacing(2)});
|
||||||
|
background-color: ${(props) => props.theme.tertiaryBackground};
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: ${(props) => props.theme.text100};
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& .react-datepicker__current-month {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .react-datepicker__day-name {
|
||||||
|
color: ${(props) => props.theme.text60};
|
||||||
|
width: 34px;
|
||||||
|
height: 40px;
|
||||||
|
line-height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Days
|
||||||
|
|
||||||
|
& .react-datepicker__month {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .react-datepicker__day {
|
||||||
|
width: 34px;
|
||||||
|
height: 34px;
|
||||||
|
line-height: 34px;
|
||||||
}
|
}
|
||||||
|
|
||||||
& .react-datepicker__day--selected {
|
& .react-datepicker__day--selected {
|
||||||
background-color: ${(props) => props.theme.blue};
|
background-color: ${(props) => props.theme.blue};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
& .react-datepicker__navigation--previous {
|
||||||
|
right: 44px;
|
||||||
|
top: 12px;
|
||||||
|
left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .react-datepicker__navigation--next {
|
||||||
|
right: 6px;
|
||||||
|
top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .react-datepicker__navigation-icon::before {
|
||||||
|
height: 7px;
|
||||||
|
width: 7px;
|
||||||
|
border-width: 1px 1px 0 0;
|
||||||
|
border-color: ${(props) => props.theme.text40};
|
||||||
|
}
|
||||||
|
|
||||||
|
& .react-datepicker__day--outside-month {
|
||||||
|
color: ${(props) => props.theme.text40};
|
||||||
|
}
|
||||||
|
|
||||||
|
& .react-datepicker__day--keyboard-selected {
|
||||||
|
background-color: inherit;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
function DatePicker({ date, onChangeHandler, customInput }: DatePickerProps) {
|
function DatePicker({
|
||||||
|
date,
|
||||||
|
onChangeHandler,
|
||||||
|
customInput,
|
||||||
|
customContainer,
|
||||||
|
}: DatePickerProps) {
|
||||||
const [startDate, setStartDate] = useState(date);
|
const [startDate, setStartDate] = useState(date);
|
||||||
|
|
||||||
type DivProps = React.HTMLProps<HTMLDivElement>;
|
type DivProps = React.HTMLProps<HTMLDivElement>;
|
||||||
@ -58,11 +196,14 @@ function DatePicker({ date, onChangeHandler, customInput }: DatePickerProps) {
|
|||||||
<ReactDatePicker
|
<ReactDatePicker
|
||||||
open={true}
|
open={true}
|
||||||
selected={startDate}
|
selected={startDate}
|
||||||
|
showMonthDropdown
|
||||||
|
showYearDropdown
|
||||||
onChange={(date: Date) => {
|
onChange={(date: Date) => {
|
||||||
setStartDate(date);
|
setStartDate(date);
|
||||||
onChangeHandler(date);
|
onChangeHandler(date);
|
||||||
}}
|
}}
|
||||||
customInput={customInput ? customInput : <DefaultDateDisplay />}
|
customInput={customInput ? customInput : <DefaultDateDisplay />}
|
||||||
|
calendarContainer={customContainer ? customContainer : undefined}
|
||||||
/>
|
/>
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -2,6 +2,8 @@ import styled from '@emotion/styled';
|
|||||||
import { forwardRef, useState } from 'react';
|
import { forwardRef, useState } from 'react';
|
||||||
import EditableCellWrapper from './EditableCellWrapper';
|
import EditableCellWrapper from './EditableCellWrapper';
|
||||||
import DatePicker from '../../form/DatePicker';
|
import DatePicker from '../../form/DatePicker';
|
||||||
|
import { CalendarContainer } from 'react-datepicker';
|
||||||
|
import { modalBackground } from '../../../layout/styles/themes';
|
||||||
|
|
||||||
export type EditableDateProps = {
|
export type EditableDateProps = {
|
||||||
value: Date;
|
value: Date;
|
||||||
@ -13,6 +15,21 @@ const StyledContainer = styled.div`
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export type StyledCalendarContainerProps = {
|
||||||
|
editModeHorizontalAlign?: 'left' | 'right';
|
||||||
|
};
|
||||||
|
|
||||||
|
const StyledCalendarContainer = styled.div<StyledCalendarContainerProps>`
|
||||||
|
position: absolute;
|
||||||
|
border: 1px solid ${(props) => props.theme.primaryBorder};
|
||||||
|
border-radius: 8px;
|
||||||
|
width: 280px;
|
||||||
|
box-shadow: 0px 3px 12px rgba(0, 0, 0, 0.09);
|
||||||
|
z-index: 1;
|
||||||
|
left: -10px;
|
||||||
|
${modalBackground};
|
||||||
|
`;
|
||||||
function EditableDate({
|
function EditableDate({
|
||||||
value,
|
value,
|
||||||
changeHandler,
|
changeHandler,
|
||||||
@ -36,6 +53,24 @@ function EditableDate({
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
interface DatePickerContainerProps {
|
||||||
|
className?: string;
|
||||||
|
children: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DatePickerContainer = ({
|
||||||
|
className,
|
||||||
|
children,
|
||||||
|
}: DatePickerContainerProps) => {
|
||||||
|
return (
|
||||||
|
<StyledCalendarContainer>
|
||||||
|
<CalendarContainer className={className}>
|
||||||
|
<div style={{ position: 'relative' }}>{children}</div>
|
||||||
|
</CalendarContainer>
|
||||||
|
</StyledCalendarContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<EditableCellWrapper
|
<EditableCellWrapper
|
||||||
isEditMode={isEditMode}
|
isEditMode={isEditMode}
|
||||||
@ -51,6 +86,7 @@ function EditableDate({
|
|||||||
setInputValue(date);
|
setInputValue(date);
|
||||||
}}
|
}}
|
||||||
customInput={<DateDisplay />}
|
customInput={<DateDisplay />}
|
||||||
|
customContainer={DatePickerContainer}
|
||||||
/>
|
/>
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,7 +27,7 @@ const lightThemeSpecific = {
|
|||||||
purpleBackground: '#e0e0ff',
|
purpleBackground: '#e0e0ff',
|
||||||
yellowBackground: '#fff2e7',
|
yellowBackground: '#fff2e7',
|
||||||
|
|
||||||
secondaryBackgroundSmallTransparency: 'rgba(252, 252, 252, 0.8)',
|
secondaryBackgroundSmallTransparency: 'rgba(252, 252, 252, 0.97)',
|
||||||
|
|
||||||
primaryBorder: 'rgba(0, 0, 0, 0.08)',
|
primaryBorder: 'rgba(0, 0, 0, 0.08)',
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ const darkThemeSpecific: typeof lightThemeSpecific = {
|
|||||||
purpleBackground: '#1111b7',
|
purpleBackground: '#1111b7',
|
||||||
yellowBackground: '#cc660a',
|
yellowBackground: '#cc660a',
|
||||||
|
|
||||||
secondaryBackgroundSmallTransparency: 'rgba(23, 23, 23, 0.8)',
|
secondaryBackgroundSmallTransparency: 'rgba(23, 23, 23, 0.97)',
|
||||||
|
|
||||||
primaryBorder: 'rgba(255, 255, 255, 0.08)',
|
primaryBorder: 'rgba(255, 255, 255, 0.08)',
|
||||||
|
|
||||||
@ -83,7 +83,6 @@ const darkThemeSpecific: typeof lightThemeSpecific = {
|
|||||||
|
|
||||||
export const modalBackground = (props: any) =>
|
export const modalBackground = (props: any) =>
|
||||||
css`
|
css`
|
||||||
backdrop-filter: blur(20px);
|
|
||||||
background: ${props.theme.secondaryBackgroundSmallTransparency};
|
background: ${props.theme.secondaryBackgroundSmallTransparency};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user