Skip to content

Commit

Permalink
feat(components/calendar): 添加 month 参数控制展示的月份
Browse files Browse the repository at this point in the history
  • Loading branch information
mengxinssfd committed Jan 11, 2024
1 parent 6271b71 commit a69054b
Show file tree
Hide file tree
Showing 7 changed files with 63 additions and 27 deletions.
23 changes: 20 additions & 3 deletions packages/components/src/calendar/Calendar.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import {
useFollowingState,
useStateRef,
getClasses,
useWatch,
} from '@pkg/shared';
import { getStartOfMonth, getClassNames } from '@tool-pack/basic';
import { CalendarHeader } from '~/calendar/components/Header';
import type { CalendarProps } from './calendar.types';
import { CalendarTable } from '~/calendar/components';
import { useStateRef, getClasses } from '@pkg/shared';
import type { RequiredPart } from '@tool-pack/types';
import { getClassNames } from '@tool-pack/basic';
import React from 'react';

const cls = getClasses('calendar', ['date-cell'], ['prev-month', 'next-month']);
Expand All @@ -19,6 +24,7 @@ export const Calendar: React.FC<CalendarProps> = React.forwardRef<
CalendarProps
>((props, ref) => {
const {
month: outerMonth,
attrs = {},
firstDay,
onChange,
Expand All @@ -29,6 +35,11 @@ export const Calendar: React.FC<CalendarProps> = React.forwardRef<
} = props as RequiredPart<CalendarProps, keyof typeof defaultProps>;

const [valueRef, setValueRef] = useStateRef(value);
const [month, setMonth] = useFollowingState(
outerMonth,
(v) => v || getStartOfMonth(value),
);
useWatch(valueRef.current, (v) => setMonth(getStartOfMonth(v)));

return (
<div
Expand All @@ -37,13 +48,19 @@ export const Calendar: React.FC<CalendarProps> = React.forwardRef<
ref={ref}
>
{header && (
<CalendarHeader value={valueRef.current} setValue={setValue} />
<CalendarHeader
onMonthChange={setMonth}
onChange={setValue}
today={today}
value={month}
/>
)}
<CalendarTable
value={valueRef.current}
firstDay={firstDay}
setValue={setValue}
dateCell={dateCell}
month={month}
today={today}
/>
</div>
Expand Down
1 change: 1 addition & 0 deletions packages/components/src/calendar/calendar.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export interface CalendarProps
firstDay?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
onChange?: (value: Date) => void;
header?: boolean;
month?: Date;
value?: Date;
today?: Date;
}
13 changes: 8 additions & 5 deletions packages/components/src/calendar/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@ import { Icon } from '~/icon';
import React from 'react';

interface Props {
setValue: (value: Date) => void;
onMonthChange: (value: Date) => void;
onChange: (value: Date) => void;
today: Date;
value: Date;
}
const cls = getClasses('calendar-header', ['month'], []);
const defaultProps = {} satisfies Partial<Props>;

export const CalendarHeader: React.FC<Props> = (props) => {
const { setValue, value } = props as RequiredPart<
const { onMonthChange, onChange, today, value } = props as RequiredPart<
Props,
keyof typeof defaultProps
>;
Expand Down Expand Up @@ -42,15 +44,16 @@ export const CalendarHeader: React.FC<Props> = (props) => {
</div>
);
function clickToday() {
setValue(new Date());
onChange(today);
onMonthChange(today);
}
function changeMonth(offset: -1 | 1): void {
const endOfMonth = getEndOfMonth(value, offset);
if (endOfMonth.getDate() < value.getDate()) {
setValue(endOfMonth);
onMonthChange(endOfMonth);
return;
}
setValue(dateAdd(value, offset, 'month'));
onMonthChange(dateAdd(value, offset, 'month'));
}
};

Expand Down
19 changes: 9 additions & 10 deletions packages/components/src/calendar/components/Table.Cell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ interface Props extends ConvertOptional<Pick<CalendarProps, 'dateCell'>> {
onClick(value: Date): void;
today: Date;
value: Date;
month: Date;
date: Date;
}

Expand All @@ -20,22 +21,20 @@ const cls = getClasses(
const defaultProps = {} satisfies Partial<Props>;

export const CalendarTableCell: React.FC<Props> = (props) => {
const { dateCell, onClick, today, value, date } = props as RequiredPart<
Props,
keyof typeof defaultProps
>;
const valueYear = value.getFullYear();
const valueMonth = value.getMonth();
const { dateCell, onClick, today, month, value, date } =
props as RequiredPart<Props, keyof typeof defaultProps>;
const dateYear = date.getFullYear();
const dateMonth = date.getMonth();
const monthYear = month.getFullYear();
const monthMonth = month.getMonth();

const status = {
isNextMonth:
dateYear > valueYear ||
(dateYear === valueYear && dateMonth > valueMonth),
dateYear > monthYear ||
(dateYear === monthYear && dateMonth > monthMonth),
isPreMonth:
dateYear < valueYear ||
(dateYear === valueYear && dateMonth < valueMonth),
dateYear < monthYear ||
(dateYear === monthYear && dateMonth < monthMonth),
isSelected: isSameTime('yyyy-MM-dd', value, date),
isToday: isSameTime('yyyy-MM-dd', today, date),
};
Expand Down
7 changes: 5 additions & 2 deletions packages/components/src/calendar/components/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import React, { useMemo } from 'react';

interface Props
extends ConvertOptional<
Pick<CalendarProps, 'firstDay' | 'dateCell' | 'value'>
Pick<CalendarProps, 'firstDay' | 'dateCell' | 'value' | 'month'>
> {
setValue(value: Date): void;
today: Date;
Expand All @@ -27,12 +27,14 @@ const defaultProps = {} satisfies Partial<Props>;
export const CalendarTable: React.FC<Props> = (props) => {
const {
value = new Date(),
month = value,
firstDay,
setValue,
dateCell,
today,
} = props as RequiredPart<Props, keyof typeof defaultProps>;
const dates: Date[][] = useMemo(() => {
const value = month;
const endOfMonth = getEndOfMonth(value);

const list: Date[] = [
Expand Down Expand Up @@ -91,7 +93,7 @@ export const CalendarTable: React.FC<Props> = (props) => {
function getFill(month: Date): (v: number) => Date {
return (v) => new Date(month.getFullYear(), month.getMonth(), v);
}
}, [value, firstDay]);
}, [month, firstDay]);

const weekDays: readonly string[] = useMemo(
() => [...weekDayNames.slice(firstDay), ...weekDayNames.slice(0, firstDay)],
Expand All @@ -116,6 +118,7 @@ export const CalendarTable: React.FC<Props> = (props) => {
dateCell={dateCell}
onClick={setValue}
today={today}
month={month}
value={value}
date={date}
/>
Expand Down
26 changes: 19 additions & 7 deletions packages/components/src/calendar/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,44 @@ $r: Name.$calendar;
$c: #{Name.$calendar}-cell;
$h: #{Name.$calendar}-header;
$t: #{Name.$calendar}-table;

.#{$r} {
:root {
--t-calendar-border: 1px solid var(--t-color-info-l-7);
--t-calendar-table-padding: 12px 0 35px;
--t-calendar-cell-height: 80px;
--t-calendar-cell-bg: unset;
--t-calendar-cell-active-bg: var(--t-color-primary-l-7);
--t-calendar-cell-color: unset;
--t-calendar-cell-active-color: var(--t-color-primary-l-2);
}

// .#{$r} {
// }

.#{$c} {
box-sizing: border-box;
padding: 8px;
height: var(--t-calendar-cell-height);
color: var(--t-calendar-cell-color);
background-color: var(--t-calendar-cell-bg);
box-sizing: border-box;
&--prev-month,
&--next-month {
color: var(--t-color-info-l-3);
--t-calendar-cell-color: var(--t-color-info-l-3);
&.#{$c}--active {
--t-calendar-cell-active-color: var(--t-color-primary-l-5);
--t-calendar-cell-active-bg: var(--t-color-info-l-7);
}
}
&--today,
&--active {
color: var(--t-color-primary-l-2);
--t-calendar-cell-color: var(--t-calendar-cell-active-color);
}
&--active {
background-color: var(--t-color-primary-l-7);
--t-calendar-cell-bg: var(--t-calendar-cell-active-bg);
}
&:not(&--disabled, &--active) {
cursor: pointer;
&:hover {
background-color: var(--t-color-primary-l-7);
--t-calendar-cell-bg: var(--t-color-primary-l-7);
}
}
}
Expand Down
1 change: 1 addition & 0 deletions packages/components/src/calendar/index.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ type DateCell = (
| -------- | ------------------------------------------ | ----------------------------------------------- | ---------- | ---- |
| value | 选中的日期 | Date | new Date() | -- |
| today | 今天的日期(可忽略,用于测试时固定为某一天) | Date | new Date() | -- |
| month | 日历所展示的月份 | Date | new Date() | -- |
| onChange | 当选中的日期变化触发的回调 | (value: Date) => void | -- | -- |
| dateCell | 自定义渲染格子内容 | 见上面 DateCell | -- | -- |
| header | 头部显示或隐藏 | boolean | true | -- |
Expand Down

0 comments on commit a69054b

Please sign in to comment.