Skip to content

Commit

Permalink
feat(DatePicker): add support renderCell on <DatePicker> (#3641)
Browse files Browse the repository at this point in the history
  • Loading branch information
simonguo committed Mar 1, 2024
1 parent d457d3a commit b63d1a3
Show file tree
Hide file tree
Showing 12 changed files with 136 additions and 55 deletions.
11 changes: 8 additions & 3 deletions docs/pages/components/date-picker/en-US/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ Clicking "Prev Day" in the example does not close the picker layer because the `

<!--{include:`caret.md`}-->

### Custom Calendar Cell

<!--{include:`render-cell.md`}-->

### Native pickers

If you only need to meet the simple date selection function, you can use the native pickers supported by the browser.
Expand Down Expand Up @@ -128,12 +132,12 @@ Has keyboard interaction for the DateInput component by default.

| Property | Type`(default)` | Description |
| --------------------- | --------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| appearance | 'default' &#124; 'subtle' `('default')` | Set picker appearence |
| appearance | 'default' \| 'subtle' `('default')` | Set picker appearence |
| block | boolean | Blocking an entire row |
| calendarDefaultDate | Date | Calendar panel default presentation date and time |
| caretAs | ElementType | Custom component for the caret icon |
| cleanable | boolean `(true)` | Whether the selected value can be cleared |
| container | HTMLElement &#124; (() => HTMLElement) | Sets the rendering container |
| container | HTMLElement \| (() => HTMLElement) | Sets the rendering container |
| defaultOpen | boolean | Default value of open property |
| defaultValue | Date | Default value |
| disabled | boolean | Whether disabled the component |
Expand Down Expand Up @@ -176,13 +180,14 @@ Has keyboard interaction for the DateInput component by default.
| placement | [Placement](#code-ts-placement-code) `('bottomStart')` | The placement of component |
| preventOverflow | boolean | Prevent floating element overflow |
| ranges | [Range[]](#code-ts-range-code) ([Ranges](#code-ts-ranges-code)) | Shortcut config |
| renderCell | (date: Date) => ReactNode | Custom calendar cell rendering <br/>![](https://img.shields.io/badge/min-v5.54.0-blue) |
| shouldDisableDate | (date:Date) => boolean | Disabled date |
| shouldDisableHour | (hour:number, date:Date) => boolean | Disabled hours |
| shouldDisableMinute | (minute:number, date:Date) => boolean | Disabled minutes |
| shouldDisableSecond | (second:number, date:Date) => boolean | Disabled seconds |
| showMeridian | boolean | Display hours in 12 format |
| showWeekNumbers | boolean | Whether to show week numbers |
| size | 'lg' &#124; 'md' &#124; 'sm' &#124; 'xs' `('md')` | A picker can have different sizes |
| size | 'lg' \| 'md' \| 'sm' \| 'xs' `('md')` | A picker can have different sizes |
| value | Date | Value (Controlled) |

<!--{include:(_common/types/placement.md)}-->
Expand Down
2 changes: 1 addition & 1 deletion docs/pages/components/date-picker/fragments/basic.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<!--start-code-->

```js
import { DatePicker, Stack } from 'rsuite';
import { DatePicker } from 'rsuite';

const App = () => <DatePicker />;

Expand Down
40 changes: 19 additions & 21 deletions docs/pages/components/date-picker/fragments/intl-zh-cn.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,25 @@
import { DatePicker } from 'rsuite';

const App = () => (
<div className="field only-date">
<DatePicker
format="yyyy-MM-dd HH:mm:ss"
style={{ width: 260 }}
locale={{
sunday: '',
monday: '',
tuesday: '',
wednesday: '',
thursday: '',
friday: '',
saturday: '',
ok: '确定',
today: '今天',
yesterday: '昨天',
hours: '',
minutes: '',
seconds: ''
}}
/>
</div>
<DatePicker
format="yyyy-MM-dd HH:mm:ss"
style={{ width: 260 }}
locale={{
sunday: '',
monday: '',
tuesday: '',
wednesday: '',
thursday: '',
friday: '',
saturday: '',
ok: '确定',
today: '今天',
yesterday: '昨天',
hours: '',
minutes: '',
seconds: ''
}}
/>
);

ReactDOM.render(<App />, document.getElementById('root'));
Expand Down
40 changes: 19 additions & 21 deletions docs/pages/components/date-picker/fragments/intl.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,25 @@
import { DatePicker } from 'rsuite';

const App = () => (
<div className="field only-date">
<DatePicker
format="yyyy-MM-dd HH:mm:ss"
style={{ width: 260 }}
locale={{
sunday: 'Su',
monday: 'Mo',
tuesday: 'Tu',
wednesday: 'We',
thursday: 'Th',
friday: 'Fr',
saturday: 'Sa',
ok: 'OK',
today: 'Today',
yesterday: 'Yesterday',
hours: 'Hours',
minutes: 'Minutes',
seconds: 'Seconds'
}}
/>
</div>
<DatePicker
format="yyyy-MM-dd HH:mm:ss"
style={{ width: 260 }}
locale={{
sunday: 'Su',
monday: 'Mo',
tuesday: 'Tu',
wednesday: 'We',
thursday: 'Th',
friday: 'Fr',
saturday: 'Sa',
ok: 'OK',
today: 'Today',
yesterday: 'Yesterday',
hours: 'Hours',
minutes: 'Minutes',
seconds: 'Seconds'
}}
/>
);

ReactDOM.render(<App />, document.getElementById('root'));
Expand Down
1 change: 0 additions & 1 deletion docs/pages/components/date-picker/fragments/placeholder.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { DatePicker } from 'rsuite';

const App = () => (
<>
{' '}
<DatePicker placeholder="Select Date" style={{ width: 200 }} />
</>
);
Expand Down
34 changes: 34 additions & 0 deletions docs/pages/components/date-picker/fragments/render-cell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<!--start-code-->

```js
import { DatePicker } from 'rsuite';

const App = () => (
<DatePicker
defaultValue={new Date('2024-10-01')}
renderCell={date => {
const day = date.getDate();
const month = date.getMonth();
const weekday = date.getDay();

if (day === 1 && month === 9) {
return <span>{day}🎉</span>;
}

if (month === 1 && day === 14) {
return <span>{day}❤️</span>;
}

if (weekday === 0 || weekday === 6) {
return <span style={{ color: 'blue' }}>{day}</span>;
}

return day;
}}
/>
);

ReactDOM.render(<App />, document.getElementById('root'));
```

<!--end-code-->
11 changes: 8 additions & 3 deletions docs/pages/components/date-picker/zh-CN/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ DatePicker 是一个高度可定制的组件,用户可以输入或选择不同

<!--{include:`caret.md`}-->

### 自定义渲染单元格

<!--{include:`render-cell.md`}-->

### 原生的选择器

如果您只需要满足简单的日期选择功能,完全可以使用浏览器支持的原生选择器。
Expand Down Expand Up @@ -128,12 +132,12 @@ DatePicker 是一个高度可定制的组件,用户可以输入或选择不同

| 属性名称 | 类型`(默认值)` | 描述 |
| --------------------- | --------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| appearance | 'default' &#124; 'subtle' `('default')` | 设置外观 |
| appearance | 'default' \| 'subtle' `('default')` | 设置外观 |
| block | boolean | 堵塞整行 |
| calendarDefaultDate | Date | 日历面板默认呈现的日期时间 |
| caretAs | ElementType | 自定义右侧箭头图标的组件 |
| cleanable | boolean `(true)` | 可以清除 |
| container | HTMLElement &#124; (() => HTMLElement) | 设置渲染的容器 |
| container | HTMLElement \| (() => HTMLElement) | 设置渲染的容器 |
| defaultOpen | boolean | 默认打开 |
| defaultValue | Date | 默认值 |
| disabled | boolean | 禁用组件 |
Expand Down Expand Up @@ -177,13 +181,14 @@ DatePicker 是一个高度可定制的组件,用户可以输入或选择不同
| placement | [Placement](#code-ts-placement-code) `('bottomStart')` | 显示位置 |
| preventOverflow | boolean | 防止浮动元素溢出 |
| ranges | [Range[]](#code-ts-range-code) ([Ranges](#code-ts-ranges-code)) | 快捷项配置 |
| renderCell | (date: Date) => ReactNode | 自定义渲染日历单元格 <br/>![](https://img.shields.io/badge/min-v5.54.0-blue) |
| shouldDisableDate | (date:Date) => boolean | 禁用日期 |
| shouldDisableHour | (hour:number, date:Date) => boolean | 禁用小时 |
| shouldDisableMinute | (minute:number, date:Date) => boolean | 禁用分钟 |
| shouldDisableSecond | (second:number, date:Date) => boolean | 禁用秒 |
| showMeridian | boolean | 显示 12 小时制的时间格式 |
| showWeekNumbers | boolean | 显示周数量 |
| size | 'lg' &#124; 'md' &#124; 'sm' &#124; 'xs' `('md')` | 组件设置尺寸 |
| size | 'lg' \| 'md' \| 'sm' \| 'xs' `('md')` | 组件设置尺寸 |
| value | Date | 值`受控 |

<!--{include:(_common/types/placement.md)}-->
Expand Down
7 changes: 7 additions & 0 deletions src/Calendar/CalendarContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ export interface CalendarProps
/** Custom rendering cell*/
renderCell?: (date: Date) => React.ReactNode;

/**
* Custom rendering cell on the picker
*/
renderCellOnPicker?: (date: Date) => React.ReactNode;

/** Custom cell classes base on it's date */
cellClassName?: (date: Date) => string | undefined;

Expand Down Expand Up @@ -147,6 +152,7 @@ const CalendarContainer: RsRefForwardingComponent<'div', CalendarProps> = React.
calendarDate: calendarDateProp,
cellClassName,
renderCell,
renderCellOnPicker,
renderTitle,
renderToolbar,
showMeridian,
Expand Down Expand Up @@ -238,6 +244,7 @@ const CalendarContainer: RsRefForwardingComponent<'div', CalendarProps> = React.
onSelect,
cellClassName,
renderCell,
renderCellOnPicker,
showWeekNumbers,
inline
};
Expand Down
18 changes: 14 additions & 4 deletions src/Calendar/TableCell.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import partial from 'lodash/partial';
import { DateUtils, useClassNames, useCustom } from '../utils';
import { isSameDay } from '../utils/dateUtils';
import { useClassNames, useCustom } from '../utils';
import { isSameDay, getDate } from '../utils/dateUtils';
import { useCalendarContext } from './CalendarContext';
import { RsRefForwardingComponent, WithAsProps } from '../@types/common';
import { getAriaLabel } from './utils';
Expand Down Expand Up @@ -33,7 +33,13 @@ const TableCell: RsRefForwardingComponent<'div', TableCellProps> = React.forward
...rest
} = props;

const { onMouseMove, cellClassName, renderCell, locale: overrideLocale } = useCalendarContext();
const {
onMouseMove,
cellClassName,
renderCell,
renderCellOnPicker,
locale: overrideLocale
} = useCalendarContext();
const { prefix, merge } = useClassNames(classPrefix);
const { locale, formatDate } = useCustom('Calendar', overrideLocale);
const formatStr = locale.formattedDayPattern;
Expand Down Expand Up @@ -69,7 +75,11 @@ const TableCell: RsRefForwardingComponent<'div', TableCellProps> = React.forward
{...rest}
>
<div className={prefix('cell-content')}>
<span className={prefix('cell-day')}>{DateUtils.getDate(date)}</span>
{renderCellOnPicker ? (
renderCellOnPicker(date)
) : (
<span className={prefix('cell-day')}>{getDate(date)}</span>
)}
{renderCell?.(date)}
</div>
</Component>
Expand Down
1 change: 1 addition & 0 deletions src/Calendar/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export interface CalendarInnerContextValue {
onMouseMove?: (date: Date) => void;
onSelect?: (date: Date, event: React.MouseEvent) => void;
renderCell?: (date: Date) => React.ReactNode;
renderCellOnPicker?: (date: Date) => React.ReactNode;
cellClassName?: (date: Date) => string | undefined;
showWeekNumbers?: boolean;
inline?: boolean;
Expand Down
10 changes: 9 additions & 1 deletion src/DatePicker/DatePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,13 @@ export interface DatePickerProps
* @deprecated
*/
renderValue?: (value: Date, format: string) => string;

/**
* Custom rendering calendar cell content.
*
* @version 5.54.0
*/
renderCell?: (date: Date) => React.ReactNode;
}

/**
Expand Down Expand Up @@ -278,6 +285,7 @@ const DatePicker: RsRefForwardingComponent<'div', DatePickerProps> = React.forwa
onToggleMonthDropdown,
onToggleTimeDropdown,
onShortcutClick,
renderCell,
...restProps
} = props;

Expand Down Expand Up @@ -662,6 +670,7 @@ const DatePicker: RsRefForwardingComponent<'div', DatePickerProps> = React.forwa
format={formatStr}
isoWeek={isoWeek}
calendarDate={calendarDate}
renderCellOnPicker={renderCell}
onMoveForward={handleMoveForward}
onMoveBackward={handleMoveBackward}
onSelect={handleSelect}
Expand Down Expand Up @@ -815,7 +824,6 @@ DatePicker.propTypes = {
onToggleMonthDropdown: PropTypes.func,
onToggleTimeDropdown: PropTypes.func,
oneTap: PropTypes.bool,
panelContainerRef: PropTypes.any,
ranges: PropTypes.array,
showMeridian: PropTypes.bool,
showWeekNumbers: PropTypes.bool,
Expand Down
16 changes: 16 additions & 0 deletions src/DatePicker/test/DatePickerSpec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -981,6 +981,22 @@ describe('DatePicker', () => {
);
});

it('Should custom render cell', () => {
render(
<DatePicker
open
value={new Date('2023-10-01')}
renderCell={date => {
const day = date.getDate();

return day === 1 ? <span>1🎉</span> : day;
}}
/>
);

expect(screen.getByRole('gridcell', { name: '01 Oct 2023' })).to.have.text('1🎉');
});

describe('Accessibility', () => {
it('Should have a aria-label attribute', () => {
render(<DatePicker aria-label="Custom label" />);
Expand Down

0 comments on commit b63d1a3

Please sign in to comment.