Skip to content

Commit

Permalink
feat: add date picker (#2644)
Browse files Browse the repository at this point in the history
Co-authored-by: himself65 <himself65@outlook.com>
(cherry picked from commit 29d8f61)
  • Loading branch information
JimmFly authored and himself65 committed Jun 8, 2023
1 parent 9429018 commit 48c486d
Show file tree
Hide file tree
Showing 15 changed files with 706 additions and 22 deletions.
2 changes: 2 additions & 0 deletions packages/component/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"lit": "^2.7.5",
"lottie-web": "^5.12.0",
"react": "18.3.0-canary-16d053d59-20230506",
"react-datepicker": "^4.12.0",
"react-dom": "18.3.0-canary-16d053d59-20230506",
"react-error-boundary": "^4.0.9",
"react-is": "^18.2.0",
Expand All @@ -56,6 +57,7 @@
"@blocksuite/lit": "0.0.0-20230606130340-805f430b-nightly",
"@blocksuite/store": "0.0.0-20230606130340-805f430b-nightly",
"@types/react": "^18.2.6",
"@types/react-datepicker": "^4.11.2",
"@types/react-dnd": "^3.0.2",
"@types/react-dom": "18.2.4",
"@vanilla-extract/css": "^1.11.0",
Expand Down
191 changes: 191 additions & 0 deletions packages/component/src/components/date-picker/date-picker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
import {
ArrowDownSmallIcon,
ArrowLeftSmallIcon,
ArrowRightSmallIcon,
} from '@blocksuite/icons';
import dayjs from 'dayjs';
import { useCallback, useState } from 'react';
import DatePicker from 'react-datepicker';

import * as styles from './index.css';
const months = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
];
type DatePickerProps = {
value?: string;
onChange: (value: string) => void;
};

export const AFFiNEDatePicker = (props: DatePickerProps) => {
const { value, onChange } = props;
const [openMonthPicker, setOpenMonthPicker] = useState(false);
const [selectedDate, setSelectedDate] = useState<Date | null>(
value ? dayjs(value).toDate() : null
);
const handleOpenMonthPicker = useCallback(() => {
setOpenMonthPicker(true);
}, []);
const handleCloseMonthPicker = useCallback(() => {
setOpenMonthPicker(false);
}, []);
const handleSelectDate = (date: Date | null) => {
if (date) {
setSelectedDate(date);
onChange(dayjs(date).format('YYYY-MM-DD'));
setOpenMonthPicker(false);
}
};
const renderCustomHeader = ({
date,
decreaseMonth,
increaseMonth,
prevMonthButtonDisabled,
nextMonthButtonDisabled,
}: {
date: Date;
decreaseMonth: () => void;
increaseMonth: () => void;
prevMonthButtonDisabled: boolean;
nextMonthButtonDisabled: boolean;
}) => {
const selectedYear = dayjs(date).year();
const selectedMonth = dayjs(date).month();
return (
<div className={styles.headerStyle}>
<div
data-testid="date-picker-current-month"
className={styles.mouthStyle}
>
{months[selectedMonth]}
</div>
<div
data-testid="date-picker-current-year"
className={styles.yearStyle}
>
{selectedYear}
</div>
<div
data-testid="month-picker-button"
className={styles.arrowDownStyle}
onClick={handleOpenMonthPicker}
>
<ArrowDownSmallIcon />
</div>
<button
data-testid="date-picker-prev-button"
className={styles.arrowLeftStyle}
onClick={decreaseMonth}
disabled={prevMonthButtonDisabled}
>
<ArrowLeftSmallIcon />
</button>
<button
data-testid="date-picker-next-button"
className={styles.arrowRightStyle}
onClick={increaseMonth}
disabled={nextMonthButtonDisabled}
>
<ArrowRightSmallIcon />
</button>
</div>
);
};
const renderCustomMonthHeader = ({
date,
decreaseYear,
increaseYear,
prevYearButtonDisabled,
nextYearButtonDisabled,
}: {
date: Date;
decreaseYear: () => void;
increaseYear: () => void;
prevYearButtonDisabled: boolean;
nextYearButtonDisabled: boolean;
}) => {
const selectedYear = dayjs(date).year();
return (
<div className={styles.monthHeaderStyle}>
<div
data-testid="month-picker-current-year"
className={styles.monthTitleStyle}
>
{selectedYear}
</div>
<button
data-testid="month-picker-prev-button"
className={styles.arrowLeftStyle}
onClick={decreaseYear}
disabled={prevYearButtonDisabled}
>
<ArrowLeftSmallIcon />
</button>
<button
data-testid="month-picker-next-button"
className={styles.arrowRightStyle}
onClick={increaseYear}
disabled={nextYearButtonDisabled}
>
<ArrowRightSmallIcon />
</button>
</div>
);
};
return (
<DatePicker
onClickOutside={handleCloseMonthPicker}
className={styles.inputStyle}
calendarClassName={styles.calendarStyle}
weekDayClassName={() => styles.weekStyle}
dayClassName={() => styles.dayStyle}
popperClassName={styles.popperStyle}
monthClassName={() => styles.mouthsStyle}
selected={selectedDate}
onChange={handleSelectDate}
showPopperArrow={false}
dateFormat="MMM dd"
showMonthYearPicker={openMonthPicker}
shouldCloseOnSelect={!openMonthPicker}
renderCustomHeader={({
date,
decreaseYear,
increaseYear,
decreaseMonth,
increaseMonth,
prevYearButtonDisabled,
nextYearButtonDisabled,
prevMonthButtonDisabled,
nextMonthButtonDisabled,
}) =>
openMonthPicker
? renderCustomMonthHeader({
date,
decreaseYear,
increaseYear,
prevYearButtonDisabled,
nextYearButtonDisabled,
})
: renderCustomHeader({
date,
decreaseMonth,
increaseMonth,
prevMonthButtonDisabled,
nextMonthButtonDisabled,
})
}
/>
);
};

export default AFFiNEDatePicker;

0 comments on commit 48c486d

Please sign in to comment.