feat: update calendat

pull/1790/head
tangjinzhou 2020-02-10 16:38:13 +08:00
parent e895ec0d8c
commit 958f3c4592
24 changed files with 569 additions and 114 deletions

View File

@ -1,5 +1,5 @@
module.exports = {
dev: {
componentName: 'breadcrumb', // dev components
componentName: 'calendar', // dev components
},
};

View File

@ -1,9 +1,21 @@
import Select from '../select';
import { Group, Button } from '../radio';
import PropTypes from '../_util/vue-types';
import { initDefaultProps } from '../_util/props-util';
import { initDefaultProps, getComponentFromProp } from '../_util/props-util';
import { ConfigConsumerProps } from '../config-provider';
const Option = Select.Option;
const { Option } = Select;
function getMonthsLocale(value) {
const current = value.clone();
const localeData = value.localeData();
const months = [];
for (let i = 0; i < 12; i++) {
current.month(i);
months.push(localeData.monthsShort(current));
}
return months;
}
export const HeaderProps = {
prefixCls: PropTypes.string,
@ -16,6 +28,7 @@ export const HeaderProps = {
// onTypeChange: PropTypes.(type: string) => void,
value: PropTypes.any,
validRange: PropTypes.array,
headerRender: PropTypes.func,
};
export default {
@ -29,7 +42,7 @@ export default {
// private calenderHeaderNode: HTMLDivElement;
methods: {
getYearSelectElement(prefixCls, year) {
const { yearSelectOffset, yearSelectTotal, locale, fullscreen, validRange } = this;
const { yearSelectOffset, yearSelectTotal, locale = {}, fullscreen, validRange } = this;
let start = year - yearSelectOffset;
let end = start + yearSelectTotal;
if (validRange) {
@ -56,17 +69,6 @@ export default {
);
},
getMonthsLocale(value) {
const current = value.clone();
const localeData = value.localeData();
const months = [];
for (let i = 0; i < 12; i++) {
current.month(i);
months.push(localeData.monthsShort(current));
}
return months;
},
getMonthSelectElement(prefixCls, month, months) {
const { fullscreen, validRange, value } = this;
const options = [];
@ -125,37 +127,68 @@ export default {
this.$emit('valueChange', newValue);
},
onTypeChange(e) {
this.$emit('typeChange', e.target.value);
onInternalTypeChange(e) {
this.onTypeChange(e.target.value);
},
onTypeChange(val) {
this.$emit('typeChange', val);
},
getCalenderHeaderNode() {
return this.$refs.calenderHeaderNode;
},
getMonthYearSelections(getPrefixCls) {
const { prefixCls: customizePrefixCls, type, value } = this.$props;
const prefixCls = getPrefixCls('fullcalendar', customizePrefixCls);
const yearReactNode = this.getYearSelectElement(prefixCls, value.year());
const monthReactNode =
type === 'month'
? this.getMonthSelectElement(prefixCls, value.month(), getMonthsLocale(value))
: null;
return {
yearReactNode,
monthReactNode,
};
},
getTypeSwitch() {
const { locale = {}, type, fullscreen } = this.$props;
const size = fullscreen ? 'default' : 'small';
return (
<Group onChange={this.onInternalTypeChange} value={type} size={size}>
<Button value="month">{locale.month}</Button>
<Button value="year">{locale.year}</Button>
</Group>
);
},
onValueChange() {
this.$emit('valueChange', ...arguments);
},
headerRenderCustom(headerRender) {
const { type, value } = this.$props;
return headerRender({
value,
type: type || 'month',
onChange: this.onValueChange,
onTypeChange: this.onTypeChange,
});
},
},
render() {
const { prefixCls: customizePrefixCls, type, value, locale, fullscreen } = this;
const { prefixCls: customizePrefixCls, headerRender } = this;
const getPrefixCls = this.configProvider.getPrefixCls;
const prefixCls = getPrefixCls('fullcalendar', customizePrefixCls);
const yearSelect = this.getYearSelectElement(prefixCls, value.year());
const monthSelect =
type === 'date'
? this.getMonthSelectElement(prefixCls, value.month(), this.getMonthsLocale(value))
: null;
const size = fullscreen ? 'default' : 'small';
const typeSwitch = (
<Group onChange={this.onTypeChange} value={type} size={size}>
<Button value="date">{locale.month}</Button>
<Button value="month">{locale.year}</Button>
</Group>
);
return (
const typeSwitch = this.getTypeSwitch();
const { yearReactNode, monthReactNode } = this.getMonthYearSelections(getPrefixCls);
return headerRender ? (
this.headerRenderCustom(headerRender)
) : (
<div class={`${prefixCls}-header`} ref="calenderHeaderNode">
{yearSelect}
{monthSelect}
{yearReactNode}
{monthReactNode}
{typeSwitch}
</div>
);

View File

@ -17,7 +17,7 @@ exports[`renders ./components/calendar/demo/basic.md correctly 1`] = `
</div><span unselectable="on" class="ant-select-arrow" style="user-select: none;"><i aria-label="icon: down" class="ant-select-arrow-icon anticon anticon-down"><svg viewBox="64 64 896 896" data-icon="down" width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><path d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"></path></svg></i></span>
</div>
</div>
<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-button-wrapper ant-radio-button-wrapper-checked"><span class="ant-radio-button ant-radio-button-checked"><input type="radio" class="ant-radio-button-input" value="date"><span class="ant-radio-button-inner"></span></span><span>Month</span></label><label class="ant-radio-button-wrapper"><span class="ant-radio-button"><input type="radio" class="ant-radio-button-input" value="month"><span class="ant-radio-button-inner"></span></span><span>Year</span></label></div>
<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-button-wrapper ant-radio-button-wrapper-checked"><span class="ant-radio-button ant-radio-button-checked"><input type="radio" class="ant-radio-button-input" value="month"><span class="ant-radio-button-inner"></span></span><span>Month</span></label><label class="ant-radio-button-wrapper"><span class="ant-radio-button"><input type="radio" class="ant-radio-button-input" value="year"><span class="ant-radio-button-inner"></span></span><span>Year</span></label></div>
</div>
<div tabindex="0" class="ant-fullcalendar ant-fullcalendar-full ant-fullcalendar-fullscreen">
<div class="ant-fullcalendar-calendar-body">
@ -323,7 +323,7 @@ exports[`renders ./components/calendar/demo/card.md correctly 1`] = `
</div><span unselectable="on" class="ant-select-arrow" style="user-select: none;"><i aria-label="icon: down" class="ant-select-arrow-icon anticon anticon-down"><svg viewBox="64 64 896 896" data-icon="down" width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><path d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"></path></svg></i></span>
</div>
</div>
<div class="ant-radio-group ant-radio-group-outline ant-radio-group-small"><label class="ant-radio-button-wrapper ant-radio-button-wrapper-checked"><span class="ant-radio-button ant-radio-button-checked"><input type="radio" class="ant-radio-button-input" value="date"><span class="ant-radio-button-inner"></span></span><span>Month</span></label><label class="ant-radio-button-wrapper"><span class="ant-radio-button"><input type="radio" class="ant-radio-button-input" value="month"><span class="ant-radio-button-inner"></span></span><span>Year</span></label></div>
<div class="ant-radio-group ant-radio-group-outline ant-radio-group-small"><label class="ant-radio-button-wrapper ant-radio-button-wrapper-checked"><span class="ant-radio-button ant-radio-button-checked"><input type="radio" class="ant-radio-button-input" value="month"><span class="ant-radio-button-inner"></span></span><span>Month</span></label><label class="ant-radio-button-wrapper"><span class="ant-radio-button"><input type="radio" class="ant-radio-button-input" value="year"><span class="ant-radio-button-inner"></span></span><span>Year</span></label></div>
</div>
<div tabindex="0" class="ant-fullcalendar ant-fullcalendar-full">
<div class="ant-fullcalendar-calendar-body">
@ -629,7 +629,7 @@ exports[`renders ./components/calendar/demo/notice-calendar.md correctly 1`] = `
</div><span unselectable="on" class="ant-select-arrow" style="user-select: none;"><i aria-label="icon: down" class="ant-select-arrow-icon anticon anticon-down"><svg viewBox="64 64 896 896" data-icon="down" width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><path d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"></path></svg></i></span>
</div>
</div>
<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-button-wrapper ant-radio-button-wrapper-checked"><span class="ant-radio-button ant-radio-button-checked"><input type="radio" class="ant-radio-button-input" value="date"><span class="ant-radio-button-inner"></span></span><span>Month</span></label><label class="ant-radio-button-wrapper"><span class="ant-radio-button"><input type="radio" class="ant-radio-button-input" value="month"><span class="ant-radio-button-inner"></span></span><span>Year</span></label></div>
<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-button-wrapper ant-radio-button-wrapper-checked"><span class="ant-radio-button ant-radio-button-checked"><input type="radio" class="ant-radio-button-input" value="month"><span class="ant-radio-button-inner"></span></span><span>Month</span></label><label class="ant-radio-button-wrapper"><span class="ant-radio-button"><input type="radio" class="ant-radio-button-input" value="year"><span class="ant-radio-button-inner"></span></span><span>Year</span></label></div>
</div>
<div tabindex="0" class="ant-fullcalendar ant-fullcalendar-full ant-fullcalendar-fullscreen">
<div class="ant-fullcalendar-calendar-body">
@ -1042,7 +1042,7 @@ exports[`renders ./components/calendar/demo/select.md correctly 1`] = `
</div><span unselectable="on" class="ant-select-arrow" style="user-select: none;"><i aria-label="icon: down" class="ant-select-arrow-icon anticon anticon-down"><svg viewBox="64 64 896 896" data-icon="down" width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><path d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"></path></svg></i></span>
</div>
</div>
<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-button-wrapper ant-radio-button-wrapper-checked"><span class="ant-radio-button ant-radio-button-checked"><input type="radio" class="ant-radio-button-input" value="date"><span class="ant-radio-button-inner"></span></span><span>Month</span></label><label class="ant-radio-button-wrapper"><span class="ant-radio-button"><input type="radio" class="ant-radio-button-input" value="month"><span class="ant-radio-button-inner"></span></span><span>Year</span></label></div>
<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-button-wrapper ant-radio-button-wrapper-checked"><span class="ant-radio-button ant-radio-button-checked"><input type="radio" class="ant-radio-button-input" value="month"><span class="ant-radio-button-inner"></span></span><span>Month</span></label><label class="ant-radio-button-wrapper"><span class="ant-radio-button"><input type="radio" class="ant-radio-button-input" value="year"><span class="ant-radio-button-inner"></span></span><span>Year</span></label></div>
</div>
<div tabindex="0" class="ant-fullcalendar ant-fullcalendar-full ant-fullcalendar-fullscreen">
<div class="ant-fullcalendar-calendar-body">
@ -1346,7 +1346,7 @@ exports[`renders ./components/calendar/demo/select.md correctly 1`] = `
</div><span unselectable="on" class="ant-select-arrow" style="user-select: none;"><i aria-label="icon: down" class="ant-select-arrow-icon anticon anticon-down"><svg viewBox="64 64 896 896" data-icon="down" width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><path d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"></path></svg></i></span>
</div>
</div>
<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-button-wrapper ant-radio-button-wrapper-checked"><span class="ant-radio-button ant-radio-button-checked"><input type="radio" class="ant-radio-button-input" value="date"><span class="ant-radio-button-inner"></span></span><span>Month</span></label><label class="ant-radio-button-wrapper"><span class="ant-radio-button"><input type="radio" class="ant-radio-button-input" value="month"><span class="ant-radio-button-inner"></span></span><span>Year</span></label></div>
<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-button-wrapper ant-radio-button-wrapper-checked"><span class="ant-radio-button ant-radio-button-checked"><input type="radio" class="ant-radio-button-input" value="month"><span class="ant-radio-button-inner"></span></span><span>Month</span></label><label class="ant-radio-button-wrapper"><span class="ant-radio-button"><input type="radio" class="ant-radio-button-input" value="year"><span class="ant-radio-button-inner"></span></span><span>Year</span></label></div>
</div>
<div tabindex="0" class="ant-fullcalendar ant-fullcalendar-full ant-fullcalendar-fullscreen">
<div class="ant-fullcalendar-calendar-body">

View File

@ -17,7 +17,7 @@ exports[`Calendar Calendar should support locale 1`] = `
</div><span unselectable="on" class="ant-select-arrow" style="user-select: none;"><i aria-label="icon: down" class="ant-select-arrow-icon anticon anticon-down"><svg viewBox="64 64 896 896" data-icon="down" width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><path d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"></path></svg></i></span>
</div>
</div>
<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-button-wrapper ant-radio-button-wrapper-checked"><span class="ant-radio-button ant-radio-button-checked"><input type="radio" class="ant-radio-button-input" value="date"><span class="ant-radio-button-inner"></span></span><span>月</span></label><label class="ant-radio-button-wrapper"><span class="ant-radio-button"><input type="radio" class="ant-radio-button-input" value="month"><span class="ant-radio-button-inner"></span></span><span>年</span></label></div>
<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-button-wrapper ant-radio-button-wrapper-checked"><span class="ant-radio-button ant-radio-button-checked"><input type="radio" class="ant-radio-button-input" value="month"><span class="ant-radio-button-inner"></span></span><span>月</span></label><label class="ant-radio-button-wrapper"><span class="ant-radio-button"><input type="radio" class="ant-radio-button-input" value="year"><span class="ant-radio-button-inner"></span></span><span>年</span></label></div>
</div>
<div tabindex="0" class="ant-fullcalendar ant-fullcalendar-full ant-fullcalendar-fullscreen">
<div class="ant-fullcalendar-calendar-body">

View File

@ -3,11 +3,21 @@ import { mount } from '@vue/test-utils';
import { asyncExpect } from '@/tests/utils';
import MockDate from 'mockdate';
import Calendar from '..';
import Header from '../Header';
import Select from '../../select';
import Group from '../../radio/group';
import Button from '../../radio/radioButton';
import mountTest from '../../../tests/shared/mountTest';
import { sleep } from '../../../tests/utils';
function $$(className) {
return document.body.querySelectorAll(className);
}
describe('Calendar', () => {
mountTest(Calendar);
beforeAll(() => {
document.body.innerHTML = '';
});
it('Calendar should be selectable', async () => {
const onSelect = jest.fn();
const wrapper = mount(
@ -25,7 +35,7 @@ describe('Calendar', () => {
.trigger('click');
});
await asyncExpect(() => {
expect(onSelect).toBeCalledWith(expect.anything());
expect(onSelect).toHaveBeenCalledWith(expect.anything());
const value = onSelect.mock.calls[0][0];
expect(Moment.isMoment(value)).toBe(true);
});
@ -203,11 +213,11 @@ describe('Calendar', () => {
});
await asyncExpect(() => {
expect(wrapper.vm.sMode).toEqual(yearMode);
wrapper.vm.setType('date');
wrapper.setProps({ mode: monthMode });
});
await asyncExpect(() => {
expect(wrapper.vm.sMode).toEqual(monthMode);
expect(onPanelChangeStub).toHaveBeenCalledTimes(1);
expect(onPanelChangeStub).toHaveBeenCalledTimes(0);
});
});
@ -226,4 +236,164 @@ describe('Calendar', () => {
MockDate.reset();
});
});
it('should trigger onPanelChange when click last month of date', () => {
const onPanelChange = jest.fn();
const date = new Moment('1990-09-03');
const wrapper = mount(Calendar, {
propsData: {
value: date,
},
listeners: {
panelChange: onPanelChange,
},
sync: false,
});
wrapper
.findAll('.ant-fullcalendar-cell')
.at(0)
.trigger('click');
expect(onPanelChange).toHaveBeenCalled();
expect(onPanelChange.mock.calls[0][0].month()).toEqual(date.month() - 1);
});
it('switch should work correctly without prop mode', async () => {
const onPanelChange = jest.fn();
const date = new Moment(new Date(Date.UTC(2017, 7, 9, 8)));
const wrapper = mount(Calendar, {
propsData: {
value: date,
},
listeners: {
panelChange: onPanelChange,
},
sync: false,
});
expect(wrapper.vm.sMode).toBe('month');
expect(wrapper.findAll('.ant-fullcalendar-table').length).toBe(1);
expect(wrapper.findAll('.ant-fullcalendar-month-panel-table').length).toBe(0);
wrapper.findAll('.ant-radio-button-input[value="year"]').trigger('change');
await sleep(50);
expect(wrapper.findAll('.ant-fullcalendar-table').length).toBe(0);
expect(wrapper.findAll('.ant-fullcalendar-month-panel-table').length).toBe(1);
expect(onPanelChange).toHaveBeenCalled();
expect(onPanelChange.mock.calls[0][1]).toEqual('year');
});
const createWrapper = async (start, end, value, onValueChange) => {
document.body.innerHTML = '';
const wrapper = mount(
{
render() {
return (
<Header
onValueChange={onValueChange}
value={value}
validRange={[start, end]}
locale={{ year: '年' }}
/>
);
},
},
{
sync: false,
attachToDocument: true,
},
);
await sleep(50);
wrapper
.findAll('.ant-fullcalendar-year-select')
.at(0)
.trigger('click');
await sleep(50);
$$('.ant-select-dropdown-menu-item')[0].click();
await sleep(50);
};
it('if value.month > end.month, set value.month to end.month', async () => {
const value = new Moment('1990-01-03');
const start = new Moment('2019-04-01');
const end = new Moment('2019-11-01');
const onValueChange = jest.fn();
await createWrapper(start, end, value, onValueChange);
expect(onValueChange).toHaveBeenCalledWith(value.year('2019').month('3'));
});
it('if value.month > end.month, set value.month to end.month1', async () => {
const value = new Moment('1990-01-03');
const start = new Moment('2019-04-01');
const end = new Moment('2019-11-01');
const onValueChange = jest.fn();
await createWrapper(start, end, value, onValueChange);
expect(onValueChange).toHaveBeenCalledWith(value.year('2019').month('3'));
});
it('if start.month > value.month, set value.month to start.month ', async () => {
const value = new Moment('1990-01-03');
const start = new Moment('2019-11-01');
const end = new Moment('2019-03-01');
const onValueChange = jest.fn();
await createWrapper(start, end, value, onValueChange);
expect(onValueChange).toHaveBeenCalledWith(value.year('2019').month('10'));
});
it('onMonthChange should work correctly', async () => {
const start = new Moment('2018-11-01');
const end = new Moment('2019-03-01');
const value = new Moment('2018-12-03');
const onValueChange = jest.fn();
const wrapper = mount(
{
render() {
return (
<Header
onValueChange={onValueChange}
value={value}
validRange={[start, end]}
locale={{ year: '年' }}
type="month"
/>
);
},
},
{
sync: false,
attachToDocument: true,
},
);
await sleep(50);
wrapper
.findAll('.ant-fullcalendar-month-select')
.at(0)
.trigger('click');
await sleep(50);
wrapper
.findAll('.ant-select-dropdown-menu-item')
.at(0)
.trigger('click');
await sleep(50);
expect(onValueChange).toHaveBeenCalledWith(value.month(10));
});
it('onTypeChange should work correctly', () => {
const onTypeChange = jest.fn();
const value = new Moment('2018-12-03');
const wrapper = mount({
render() {
return (
<Header
onTypeChange={onTypeChange}
locale={{ year: '年', month: '月' }}
value={value}
type="date"
/>
);
},
});
wrapper
.findAll('input')
.at(1)
.trigger('change');
expect(onTypeChange).toHaveBeenCalledWith('year');
});
});

View File

@ -0,0 +1,99 @@
<cn>
#### 自定义头部
自定义日历头部内容
</cn>
<us>
#### Customize Header
Customize Calendar header content.
</us>
```tpl
<template>
<div style="width: 300px; border: 1px solid #d9d9d9; border-radius: 4px">
<a-calendar :fullscreen="false" :header-render="headerRender" @panelChange="onPanelChange" />
</div>
</template>
<script>
export default {
methods: {
onPanelChange(value, mode) {
console.log(value, mode);
},
headerRender({ value, type, onChange, onTypeChange }) {
const start = 0;
const end = 12;
const monthOptions = [];
const current = value.clone();
const localeData = value.localeData();
const months = [];
for (let i = 0; i < 12; i++) {
current.month(i);
months.push(localeData.monthsShort(current));
}
for (let index = start; index < end; index++) {
monthOptions.push(
<a-select-option class="month-item" key={`${index}`}>
{months[index]}
</a-select-option>,
);
}
const month = value.month();
const year = value.year();
const options = [];
for (let i = year - 10; i < year + 10; i += 1) {
options.push(
<a-select-option key={i} value={i} class="year-item">
{i}
</a-select-option>,
);
}
return (
<div style={{ padding: '10px' }}>
<div style={{ marginBottom: '10px' }}>Custom header </div>
<a-row type="flex" justify="space-between">
<a-col>
<a-radio-group size="small" onChange={e => onTypeChange(e.target.value)} value={type}>
<a-radio-button value="month">Month</a-radio-button>
<a-radio-button value="year">Year</a-radio-button>
</a-radio-group>
</a-col>
<a-col>
<a-select
size="small"
dropdownMatchSelectWidth={false}
class="my-year-select"
onChange={newYear => {
const now = value.clone().year(newYear);
onChange(now);
}}
value={String(year)}
>
{options}
</a-select>
</a-col>
<a-col>
<a-select
size="small"
dropdownMatchSelectWidth={false}
value={String(month)}
onChange={selectedMonth => {
const newValue = value.clone();
newValue.month(parseInt(selectedMonth, 10));
onChange(newValue);
}}
>
{monthOptions}
</a-select>
</a-col>
</a-row>
</div>
);
},
},
};
</script>
```

View File

@ -3,6 +3,8 @@ import Basic from './basic';
import Card from './card';
import NoticeCalendar from './notice-calendar';
import Select from './select';
import CustomizeHeader from './customize-header.vue';
import CustomizeHeaderString from '!raw-loader!./customize-header.vue';
import CN from '../index.zh-CN.md';
import US from '../index.en-US.md';
const md = {
@ -40,6 +42,10 @@ export default {
<Card />
<NoticeCalendar />
<Select />
<CustomizeHeader />
<demo-container code={CustomizeHeaderString}>
<CustomizeHeader />
</demo-container>
<api>
<CN slot="cn" />
<US />

View File

@ -15,24 +15,25 @@ moment.locale('zh-cn');
customize the progress dot by setting a scoped slot
| Property | Description | Type | Default |
| --- | --- | --- | --- |
| dateCellRender | Customize the display of the date cell by setting a scoped slot, the returned content will be appended to the cell | function(date: moment) | - |
| dateFullCellRender | Customize the display of the date cell by setting a scoped slot, the returned content will override the cell | function(date: moment) | - |
| defaultValue | The date selected by default | [moment](http://momentjs.com/) | default date |
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| dateCellRender | Customize the display of the date cell by setting a scoped slot, the returned content will be appended to the cell | function(date: moment) | - | |
| dateFullCellRender | Customize the display of the date cell by setting a scoped slot, the returned content will override the cell | function(date: moment) | - | |
| defaultValue | The date selected by default | [moment](http://momentjs.com/) | default date | |
| disabledDate | Function that specifies the dates that cannot be selected | (currentDate: moment) => boolean | - |
| fullscreen | Whether to display in full-screen | boolean | `true` |
| locale | The calendar's locale | object | [default](https://github.com/vueComponent/ant-design-vue/blob/master/components/date-picker/locale/example.json) |
| mode | The display mode of the calendar | `month` \| `year` | `month` |
| monthCellRender | Customize the display of the month cell by setting a scoped slot, the returned content will be appended to the cell | function(date: moment) | - |
| monthFullCellRender | Customize the display of the month cell by setting a scoped slot, the returned content will override the cell | function(date: moment) | - |
| validRange | to set valid range | \[[moment](http://momentjs.com/), [moment](http://momentjs.com/)] | - |
| value(v-model) | The current selected date | [moment](http://momentjs.com/) | current date |
| fullscreen | Whether to display in full-screen | boolean | `true` | |
| locale | The calendar's locale | object | [default](https://github.com/vueComponent/ant-design-vue/blob/master/components/date-picker/locale/example.json) | |
| mode | The display mode of the calendar | `month` \| `year` | `month` | |
| monthCellRender | Customize the display of the month cell by setting a scoped slot, the returned content will be appended to the cell | function(date: moment) | - | |
| monthFullCellRender | Customize the display of the month cell by setting a scoped slot, the returned content will override the cell | function(date: moment) | - | |
| validRange | to set valid range | \[[moment](http://momentjs.com/), [moment](http://momentjs.com/)] | - | |
| value(v-model) | The current selected date | [moment](http://momentjs.com/) | current date | |
| headerRender | render custom header in panel | function(object:{value: moment, type: string, onChange: f(), onTypeChange: f()}) \| slot-scope | - | 1.5.0 |
### events
| Events Name | Description | Arguments |
| ----------- | ------------------------------------ | ------------------------------------ |
| panelChange | Callback for when panel changes | function(date: moment, mode: string) | - |
| select | Callback for when a date is selected | function(date: moment | - |
| change | Callback for when value change | function(date: moment | - |
| Events Name | Description | Arguments | Version |
| --- | --- | --- | --- |
| panelChange | Callback for when panel changes | function(date: moment, mode: string) | - | |
| select | Callback for when a date is selected | function(date: moment | - | |
| change | Callback for when value change | function(date: moment | - | |

View File

@ -1,10 +1,16 @@
import PropTypes from '../_util/vue-types';
import BaseMixin from '../_util/BaseMixin';
import { getOptionProps, hasProp, initDefaultProps, getListeners } from '../_util/props-util';
import {
getOptionProps,
hasProp,
initDefaultProps,
getListeners,
getComponentFromProp,
} from '../_util/props-util';
import * as moment from 'moment';
import FullCalendar from '../vc-calendar/src/FullCalendar';
import Header, { HeaderRender } from './Header';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
import Header from './Header';
import interopDefault from '../_util/interopDefault';
import { ConfigConsumerProps } from '../config-provider';
import enUS from './locale/en_US';
@ -46,6 +52,7 @@ export const CalendarProps = () => ({
// onSelect?: (date?: moment.Moment) => void;
disabledDate: PropTypes.func,
validRange: PropTypes.custom(isMomentArray),
headerRender: PropTypes.func,
});
const Calendar = {
@ -54,7 +61,6 @@ const Calendar = {
props: initDefaultProps(CalendarProps(), {
locale: {},
fullscreen: true,
mode: 'month',
}),
model: {
prop: 'value',
@ -71,7 +77,7 @@ const Calendar = {
this._sPrefixCls = undefined;
return {
sValue: value,
sMode: this.mode,
sMode: this.mode || 'month',
};
},
watch: {
@ -87,55 +93,13 @@ const Calendar = {
},
},
methods: {
monthCellRender2(value) {
const { _sPrefixCls, $scopedSlots } = this;
const monthCellRender = this.monthCellRender || $scopedSlots.monthCellRender || noop;
return (
<div class={`${_sPrefixCls}-month`}>
<div class={`${_sPrefixCls}-value`}>{value.localeData().monthsShort(value)}</div>
<div class={`${_sPrefixCls}-content`}>{monthCellRender(value)}</div>
</div>
);
},
dateCellRender2(value) {
const { _sPrefixCls, $scopedSlots } = this;
const dateCellRender = this.dateCellRender || $scopedSlots.dateCellRender || noop;
return (
<div class={`${_sPrefixCls}-date`}>
<div class={`${_sPrefixCls}-value`}>{zerofixed(value.date())}</div>
<div class={`${_sPrefixCls}-content`}>{dateCellRender(value)}</div>
</div>
);
},
setValue(value, way) {
if (way === 'select') {
this.$emit('select', value);
} else if (way === 'changePanel') {
this.onPanelChange(value, this.sMode);
}
if (!hasProp(this, 'value')) {
this.setState({ sValue: value });
}
},
setType(type) {
const mode = type === 'date' ? 'month' : 'year';
if (this.sMode !== mode) {
this.setState({ sMode: mode });
this.onPanelChange(this.sValue, mode);
}
},
onHeaderValueChange(value) {
this.setValue(value, 'changePanel');
},
onHeaderTypeChange(type) {
this.setType(type);
onHeaderTypeChange(mode) {
this.sMode = mode;
this.onPanelChange(this.sValue, mode);
},
onPanelChange(value, mode) {
this.$emit('panelChange', value, mode);
if (value !== this.sValue) {
@ -146,6 +110,21 @@ const Calendar = {
onSelect(value) {
this.setValue(value, 'select');
},
setValue(value, way) {
const prevValue = this.value || this.sValue;
const { sMode: mode } = this;
if (!hasProp(this, 'value')) {
this.setState({ sValue: value });
}
if (way === 'select') {
if (prevValue && prevValue.month() !== value.month()) {
this.onPanelChange(value, mode);
}
this.$emit('select', value);
} else if (way === 'changePanel') {
this.onPanelChange(value, mode);
}
},
getDateRange(validRange, disabledDate) {
return current => {
if (!current) {
@ -170,6 +149,28 @@ const Calendar = {
};
return result;
},
monthCellRender2(value) {
const { _sPrefixCls, $scopedSlots } = this;
const monthCellRender = this.monthCellRender || $scopedSlots.monthCellRender || noop;
return (
<div class={`${_sPrefixCls}-month`}>
<div class={`${_sPrefixCls}-value`}>{value.localeData().monthsShort(value)}</div>
<div class={`${_sPrefixCls}-content`}>{monthCellRender(value)}</div>
</div>
);
},
dateCellRender2(value) {
const { _sPrefixCls, $scopedSlots } = this;
const dateCellRender = this.dateCellRender || $scopedSlots.dateCellRender || noop;
return (
<div class={`${_sPrefixCls}-date`}>
<div class={`${_sPrefixCls}-value`}>{zerofixed(value.date())}</div>
<div class={`${_sPrefixCls}-content`}>{dateCellRender(value)}</div>
</div>
);
},
renderCalendar(locale, localeCode) {
const props = getOptionProps(this);
const { sValue: value, sMode: mode, $scopedSlots } = this;
@ -182,9 +183,9 @@ const Calendar = {
dateFullCellRender,
monthFullCellRender,
} = props;
const headerRender = this.headerRender || $scopedSlots.headerRender;
const getPrefixCls = this.configProvider.getPrefixCls;
const prefixCls = getPrefixCls('fullcalendar', customizePrefixCls);
const type = mode === 'year' ? 'month' : 'date';
// To support old version react.
// Have to add prefixCls on the instance.
@ -211,7 +212,7 @@ const Calendar = {
...props,
Select: {},
locale: locale.lang,
type: type,
type: mode === 'year' ? 'month' : 'date',
prefixCls: prefixCls,
showHeader: false,
value: value,
@ -228,7 +229,8 @@ const Calendar = {
<div class={cls}>
<Header
fullscreen={fullscreen}
type={type}
type={mode}
headerRender={headerRender}
value={value}
locale={locale.lang}
prefixCls={prefixCls}

View File

@ -25,6 +25,7 @@
| monthFullCellRender | 作用域插槽,自定义渲染月单元格,返回内容覆盖单元格 | function(date: moment) | 无 |
| validRange | 设置可以显示的日期 | \[[moment](http://momentjs.com/), [moment](http://momentjs.com/)] | 无 |
| value(v-model) | 展示日期 | [moment](http://momentjs.com/) | 当前日期 |
| headerRender | 自定义头部内容 | function(object:{value: moment, type: string, onChange: f(), onTypeChange: f()}) \| slot-scope | - | 1.5.0 |
### 事件

View File

@ -0,0 +1,3 @@
import hr_HR from '../../date-picker/locale/hr_HR';
export default hr_HR;

View File

@ -0,0 +1,3 @@
import lv_LV from '../../date-picker/locale/lv_LV';
export default lv_LV;

View File

@ -0,0 +1,3 @@
import mk_MK from '../../date-picker/locale/mk_MK';
export default mk_MK;

View File

@ -0,0 +1,3 @@
import ms_MY from '../../date-picker/locale/ms_MY';
export default ms_MY;

View File

@ -0,0 +1,3 @@
import ro_RO from '../../date-picker/locale/ro_RO';
export default ro_RO;

View File

@ -0,0 +1,3 @@
import ta_IN from '../../date-picker/locale/ta_IN';
export default ta_IN;

View File

@ -11,6 +11,10 @@ const locale = {
timePickerLocale: {
...TimePickerLocale,
},
dateFormat: 'DD-MM-YYYY',
monthFormat: 'MM-YYYY',
dateTimeFormat: 'DD-MM-YYYY HH:mm:ss',
weekFormat: 'wo-YYYY',
};
// All settings at:

View File

@ -0,0 +1,19 @@
import CalendarLocale from '../../vc-calendar/src/locale/hr_HR';
import TimePickerLocale from '../../time-picker/locale/hr_HR';
// Merge into a locale object
const locale = {
lang: {
placeholder: 'Odaberite datum',
rangePlaceholder: ['Početni datum', 'Završni datum'],
...CalendarLocale,
},
timePickerLocale: {
...TimePickerLocale,
},
};
// All settings at:
// https://github.com/ant-design/ant-design/blob/master/components/date-picker/locale/example.json
export default locale;

View File

@ -0,0 +1,19 @@
import CalendarLocale from '../../vc-calendar/src/locale/lv_LV';
import TimePickerLocale from '../../time-picker/locale/lv_LV';
// Merge into a locale object
const locale = {
lang: {
placeholder: 'Izvēlieties datumu',
rangePlaceholder: ['Sākuma datums', 'Beigu datums'],
...CalendarLocale,
},
timePickerLocale: {
...TimePickerLocale,
},
};
// All settings at:
// https://github.com/ant-design/ant-design/blob/master/components/date-picker/locale/example.json
export default locale;

View File

@ -0,0 +1,19 @@
import CalendarLocale from '../../vc-calendar/src/locale/mk_MK';
import TimePickerLocale from '../../time-picker/locale/mk_MK';
// Merge into a locale object
const locale = {
lang: {
placeholder: 'Избери датум',
rangePlaceholder: ['Од датум', 'До датум'],
...CalendarLocale,
},
timePickerLocale: {
...TimePickerLocale,
},
};
// All settings at:
// https://github.com/ant-design/ant-design/blob/master/components/date-picker/locale/example.json
export default locale;

View File

@ -0,0 +1,19 @@
import CalendarLocale from '../../vc-calendar/src/locale/ms_MY';
import TimePickerLocale from '../../time-picker/locale/ms_MY';
// Merge into a locale object
const locale = {
lang: {
placeholder: 'Pilih tarikh',
rangePlaceholder: ['Tarikh mula', 'Tarikh akhir'],
...CalendarLocale,
},
timePickerLocale: {
...TimePickerLocale,
},
};
// All settings at:
// https://github.com/ant-design/ant-design/blob/master/components/date-picker/locale/example.json
export default locale;

View File

@ -0,0 +1,19 @@
import CalendarLocale from '../../vc-calendar/src/locale/ro_RO';
import TimePickerLocale from '../../time-picker/locale/ro_RO';
// Merge into a locale object
const locale = {
lang: {
placeholder: 'Selectează data',
rangePlaceholder: ['Data start', 'Data sfârșit'],
...CalendarLocale,
},
timePickerLocale: {
...TimePickerLocale,
},
};
// All settings at:
// https://github.com/ant-design/ant-design/blob/master/components/date-picker/locale/example.json
export default locale;

View File

@ -0,0 +1,20 @@
// Tamil Locale added to rc-calendar
import CalendarLocale from '../../vc-calendar/src/locale/ta_IN';
import TimePickerLocale from '../../time-picker/locale/ta_IN';
// Merge into a locale object
const locale = {
lang: {
placeholder: 'தேதியைத் தேர்ந்தெடுக்கவும்',
rangePlaceholder: ['தொடக்க தேதி', 'கடைசி தேதி'],
...CalendarLocale,
},
timePickerLocale: {
...TimePickerLocale,
},
};
// All settings at:
// https://github.com/ant-design/ant-design/blob/master/components/date-picker/locale/example.json
export default locale;

8
types/calendar.d.ts vendored
View File

@ -4,8 +4,14 @@
import { AntdComponent } from './component';
import { Moment } from 'moment';
export interface RenderHeader {
value: Moment;
onChange?: (value: Moment) => void;
type: string;
onTypeChange: (type: string) => void;
}
export declare class Calendar extends AntdComponent {
headerRender: (headerRender: RenderHeader) => any;
/**
* Customize the display of the date cell by setting a scoped slot,
* the returned content will be appended to the cell