Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: min and max prop in date picker/range picker [#628] #669

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions example/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import HideSeconds from './demo/HideSeconds.vue';
import MinuteStep from './demo/MinuteStep.vue';
import FixedTimeList from './demo/FixedTimeList.vue';
import Disabled from './demo/Disabled.vue';
import MinMax from './demo/MinMax.vue';

import docEn from './en.md';
import docZhCN from './zh-cn.md';
Expand Down Expand Up @@ -74,6 +75,11 @@ const components = [
component: ControlOpen,
code: fs.readFileSync(`${__dirname}/demo/ControlOpen.vue`, 'utf8'),
},
{
id: 'MinMax',
component: MinMax,
code: fs.readFileSync(`${__dirname}/demo/MinMax.vue`, 'utf8'),
},
];

function transformMd(text) {
Expand Down
46 changes: 46 additions & 0 deletions example/demo/MinMax.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<template>
<div>
<div>
<p>min: {{ min }}</p>
<p>max: {{ max }}</p>
</div>
<div class="box">
<section>
<date-picker
v-model="value"
placeholder="Select date"
format="YYYY-MM-DD"
type="date"
:min="min"
:max="max"
></date-picker>
</section>
<section>
<date-picker
v-model="value"
placeholder="Select date range"
format="YYYY-MM-DD"
type="date"
range
:min="min"
:max="max"
></date-picker>
</section>
</div>
</div>
</template>

<script>
const MONTH_1 = 2.628e9;

export default {
name: 'ControlOpen',
data() {
return {
value: '',
min: new Date(Date.now() - 3 * MONTH_1),
max: new Date(Date.now() + 200 * MONTH_1),
};
},
};
</script>
7 changes: 7 additions & 0 deletions example/en.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@ You can use the prop `open` to control the visible of popup.

This example shows how to close the popup when the seconds is selected.

<!-- MinMax -->
### Min Max

You can use the prop `min` &amp; `max` to specify range.

This example shows how to use min and max date to restrict specify dates.

<!-- HideSeconds -->

### Hide seconds selection & display AMPM selection
Expand Down
6 changes: 6 additions & 0 deletions example/zh-cn.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@

下面的例子说明怎么关闭弹窗当选择秒的时候

<!-- MinMax -->

### Min Max

<!-- todo -->

<!-- HideSeconds -->

### 隐藏秒和显示 am/pm
Expand Down
61 changes: 57 additions & 4 deletions src/calendar/calendar-panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,27 @@ export default {
type: Boolean,
default: false,
},
min: {
type: Date,
},
max: {
type: Date,
},
},
data() {
const panels = ['date', 'month', 'year'];
const index = Math.max(panels.indexOf(this.type), panels.indexOf(this.defaultPanel));
const panel = index !== -1 ? panels[index] : 'date';
const minDate = (this.min && new Date(this.min)) || undefined;
const maxDate = (this.max && new Date(this.max)) || undefined;
if (minDate) minDate.setHours(0, 0, 0, 0);
if (maxDate) maxDate.setHours(23, 59, 59, 999);

return {
panel,
innerCalendar: new Date(),
minDate,
maxDate,
};
},
computed: {
Expand Down Expand Up @@ -186,7 +199,10 @@ export default {
},
getMonthClasses(month) {
if (this.type !== 'month') {
return this.calendarMonth === month ? 'active' : '';
const classes = [this.calendarMonth === month ? 'active' : ''];
if (this.getIsMonthDisabled(month)) classes.push('disabled');

return classes;
}
const classes = [];
const cellDate = this.getMonthCellDate(month);
Expand All @@ -195,15 +211,18 @@ export default {
},
getYearClasses(year) {
if (this.type !== 'year') {
return this.calendarYear === year ? 'active' : '';
const classes = [this.calendarYear === year ? 'active' : ''];
if (this.getIsYearDisabled(year)) classes.push('disabled');

return classes;
}
const classes = [];
const cellDate = this.getYearCellDate(year);
classes.push(this.getStateClass(cellDate));
return classes.concat(this.getClasses(cellDate, this.innerValue, classes.join(' ')));
},
getStateClass(cellDate) {
if (this.isDisabled(cellDate)) {
if (this.getIsDateDisabled(cellDate) || this.isDisabled(cellDate)) {
return 'disabled';
}
if (this.innerValue.some(v => v.getTime() === cellDate.getTime())) {
Expand All @@ -221,9 +240,34 @@ export default {
});
return active ? `${this.prefixClass}-active-week` : '';
},
getIsYearDisabled(year) {
return (
(!!this.minDate && year < this.minDate.getFullYear()) ||
(!!this.maxDate && year > this.maxDate.getFullYear())
);
},
getIsMonthDisabled(month) {
const cellDate = this.getMonthCellDate(month);

return (
(!!this.minDate &&
(this.minDate.getFullYear() > cellDate.getFullYear() ||
(this.minDate.getFullYear() === cellDate.getFullYear() &&
month < this.minDate.getMonth()))) ||
(!!this.maxDate &&
(this.maxDate.getFullYear() < cellDate.getFullYear() ||
(this.maxDate.getFullYear() === cellDate.getFullYear() &&
month > this.maxDate.getMonth())))
);
},
getIsDateDisabled(cellDate) {
return (
(!!this.minDate && this.minDate > cellDate) || (!!this.maxDate && this.maxDate < cellDate)
);
},
},
render() {
const { panel, innerCalendar } = this;
const { panel, innerCalendar, minDate, maxDate } = this;
if (panel === 'year') {
return (
<TableYear
Expand All @@ -232,6 +276,9 @@ export default {
getYearPanel={this.getYearPanel}
onSelect={this.handleSelectYear}
onChangecalendar={this.handleCalendarChange}
getIsYearDisabled={this.getIsYearDisabled}
min={minDate && minDate.getFullYear()}
max={maxDate && maxDate.getFullYear()}
/>
);
}
Expand All @@ -243,6 +290,9 @@ export default {
onSelect={this.handleSelectMonth}
onChangepanel={this.handelPanelChange}
onChangecalendar={this.handleCalendarChange}
getIsMonthDisabled={this.getIsMonthDisabled}
min={minDate && minDate.getFullYear()}
max={maxDate && maxDate.getFullYear()}
/>
);
}
Expand All @@ -259,6 +309,9 @@ export default {
onSelect={this.handleSelectDate}
onChangepanel={this.handelPanelChange}
onChangecalendar={this.handleCalendarChange}
getIsDateDisabled={this.getIsDateDisabled}
min={minDate}
max={maxDate}
/>
);
},
Expand Down
9 changes: 8 additions & 1 deletion src/calendar/icon-button.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
<template>
<button
type="button"
:class="`${prefixClass}-btn ${prefixClass}-btn-text ${prefixClass}-btn-icon-${type}`"
v-bind="{ disabled }"
:class="[
`${prefixClass}-btn ${prefixClass}-btn-text ${prefixClass}-btn-icon-${type}`,
{
[`${prefixClass}-btn-disabled`]: disabled,
},
]"
v-on="$listeners"
>
<i :class="`${prefixClass}-icon-${type}`"></i>
Expand All @@ -12,6 +18,7 @@
export default {
props: {
type: String,
disabled: Boolean,
},
inject: {
prefixClass: {
Expand Down
64 changes: 59 additions & 5 deletions src/calendar/table-date.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,26 @@
<template>
<div :class="`${prefixClass}-calendar ${prefixClass}-calendar-panel-date`">
<div :class="`${prefixClass}-calendar-header`">
<icon-button type="double-left" @click="handleIconDoubleLeftClick"></icon-button>
<icon-button type="left" @click="handleIconLeftClick"></icon-button>
<icon-button type="double-right" @click="handleIconDoubleRightClick"></icon-button>
<icon-button type="right" @click="handleIconRightClick"></icon-button>
<icon-button
:disabled="isDoubleLeftDisabled"
type="double-left"
@click="handleIconDoubleLeftClick"
></icon-button>
<icon-button
:disabled="isGoLeftDisabled"
type="left"
@click="handleIconLeftClick"
></icon-button>
<icon-button
:disabled="isDoubleRightDisabled"
type="double-right"
@click="handleIconDoubleRightClick"
></icon-button>
<icon-button
:disabled="isGoRightDisabled"
type="right"
@click="handleIconRightClick"
></icon-button>
<span :class="`${prefixClass}-calendar-header-label`">
<button
v-for="item in yearMonth"
Expand Down Expand Up @@ -107,8 +123,44 @@ export default {
type: Function,
default: () => [],
},
getIsDateDisabled: {
type: Function,
default: () => [],
},
min: { type: Date },
max: { type: Date },
},
computed: {
isDoubleLeftDisabled() {
if (!this.min || !this.calendar) return false;

const date = new Date(this.calendar);
date.setFullYear(date.getFullYear() - 1);
const min = new Date(this.min);
min.setDate(date.getDate());
return date <= min;
},
isDoubleRightDisabled() {
if (!this.max || !this.calendar) return false;

const date = new Date(this.calendar);
date.setFullYear(date.getFullYear() + 1);
const max = new Date(this.max);
max.setDate(date.getDate());
return date >= max;
},
isGoLeftDisabled() {
if (!this.min) return false;

return this.calendar < this.min;
},
isGoRightDisabled() {
if (!this.max) return false;

const date = new Date(this.calendar);
date.setMonth(date.getMonth() + 1);
return date > this.max;
},
firstDayOfWeek() {
return this.getLocale().formatLocale.firstDayOfWeek || 0;
},
Expand Down Expand Up @@ -191,7 +243,9 @@ export default {
if (index) {
const [row, col] = index.split(',').map(v => parseInt(v, 10));
const date = this.dates[row][col];
this.$emit('select', new Date(date));
if (!this.getIsDateDisabled(date)) {
this.$emit('select', new Date(date));
}
}
},
formatDate(date, fmt) {
Expand Down
31 changes: 29 additions & 2 deletions src/calendar/table-month.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
<template>
<div :class="`${prefixClass}-calendar ${prefixClass}-calendar-panel-month`">
<div :class="`${prefixClass}-calendar-header`">
<icon-button type="double-left" @click="handleIconDoubleLeftClick"></icon-button>
<icon-button type="double-right" @click="handleIconDoubleRightClick"></icon-button>
<icon-button
type="double-left"
:disabled="isDoubleLeftDisabled"
@click="handleIconDoubleLeftClick"
></icon-button>
<icon-button
type="double-right"
:disabled="isDoubleRightDisabled"
@click="handleIconDoubleRightClick"
></icon-button>
<span :class="`${prefixClass}-calendar-header-label`">
<button
type="button"
Expand Down Expand Up @@ -53,15 +61,33 @@ export default {
type: Date,
default: () => new Date(),
},
getIsMonthDisabled: {
type: Function,
default: () => false,
},
getCellClasses: {
type: Function,
default: () => [],
},
min: {
// in year e.g. 2021
type: Number,
},
max: {
// in year e.g. 2021
type: Number,
},
},
computed: {
calendarYear() {
return this.calendar.getFullYear();
},
isDoubleLeftDisabled() {
return !!this.min && this.calendarYear <= this.min;
},
isDoubleRightDisabled() {
return !!this.max && this.calendarYear >= this.max;
},
months() {
const locale = this.getLocale();
const monthsLocale = locale.months || locale.formatLocale.monthsShort;
Expand Down Expand Up @@ -96,6 +122,7 @@ export default {
}
const month = target.getAttribute('data-month');
if (month) {
if (this.getIsMonthDisabled(month)) return;
this.$emit('select', parseInt(month, 10));
}
},
Expand Down
Loading