diff --git a/packages/button/src/button.vue b/packages/button/src/button.vue index 368654f371..1bf90c5072 100644 --- a/packages/button/src/button.vue +++ b/packages/button/src/button.vue @@ -130,6 +130,7 @@ export default defineComponent({ } return { + elFormItemSize_, buttonSize, buttonDisabled, handleClick, diff --git a/packages/calendar/src/date-table.vue b/packages/calendar/src/date-table.vue index dcd56af089..0656ba8cf3 100644 --- a/packages/calendar/src/date-table.vue +++ b/packages/calendar/src/date-table.vue @@ -48,12 +48,9 @@ import { } from 'vue' import dayjs, { Dayjs } from 'dayjs' import localeData from 'dayjs/plugin/localeData' +import { rangeArr } from '@element-plus/time-picker/src/common/date-utils' dayjs.extend(localeData) -const rangeArr = n => { - return Array.from(Array(n).keys()) -} - export const getPrevMonthLastDays = (date: Dayjs, amount) => { const lastDay = date.subtract(1, 'month').endOf('month').date() return rangeArr(amount).map((_, index) => lastDay - (amount - index - 1)) diff --git a/packages/date-picker/__tests__/date-picker.spec.ts b/packages/date-picker/__tests__/date-picker.spec.ts new file mode 100644 index 0000000000..e7999f5fc2 --- /dev/null +++ b/packages/date-picker/__tests__/date-picker.spec.ts @@ -0,0 +1,572 @@ +import Picker from '@element-plus/time-picker/src/common/picker.vue' +import { mount } from '@vue/test-utils' +import dayjs from 'dayjs' +import { nextTick } from 'vue' +import DatePicker from '../src/date-picker' + +const _mount = (template: string, data = () => ({}), otherObj?) => mount({ + components: { + 'el-date-picker': DatePicker, + }, + template, + data, + ...otherObj, +}, { + global: { + provide: { + elForm: {}, + elFormItem: {}, + }, + }, +}) + +afterEach(() => { + document.documentElement.innerHTML = '' +}) + + +describe('DatePicker', () => { + it('create', async () => { + const wrapper = _mount(``) + const input = wrapper.find('input') + expect(input.attributes('placeholder')).toBe('test_') + expect(input.attributes('readonly')).not.toBeUndefined() + }) + + it('select date', async () => { + const wrapper = _mount(``, () => ({ value: '' })) + const date = dayjs() + + const input = wrapper.find('input') + input.trigger('blur') + input.trigger('focus') + await nextTick() + const spans = document.querySelectorAll('.el-date-picker__header-label') + const arrowLeftElm = document.querySelector('.el-date-picker__prev-btn.el-icon-arrow-left') as HTMLElement + const arrowRightElm = document.querySelector('.el-date-picker__next-btn.el-icon-arrow-right') as HTMLElement + expect(spans[0].textContent).toContain(date.year()) + expect(spans[1].textContent).toContain(date.format('MMMM')) + const arrowLeftYeayElm = document.querySelector('.el-date-picker__prev-btn.el-icon-d-arrow-left') as HTMLElement + arrowLeftYeayElm.click() + let count = 20 + while (--count) { + arrowLeftElm.click() + } + count = 20 + while (--count) { + arrowRightElm.click() + } + await nextTick() + expect(spans[0].textContent).toContain(date.add(-1, 'year').year()) + expect(spans[1].textContent).toContain(date.format('MMMM')); + (document.querySelector('td.available') as HTMLElement).click() + await nextTick() + const vm = wrapper.vm as any + expect(vm.value).toBeDefined() + }) + + it('defaultTime and clear value', async () => { + const wrapper = _mount(``, () => ({ value: '' })) + const input = wrapper.find('input') + input.trigger('blur') + input.trigger('focus') + await nextTick(); + (document.querySelector('td.available') as HTMLElement).click() + await nextTick() + const vm = wrapper.vm as any + expect(vm.value).toBeDefined() + expect(vm.value.getHours()).toBe(12) + expect(vm.value.getMinutes()).toBe(0) + expect(vm.value.getSeconds()).toBe(1) + const picker = wrapper.findComponent(Picker); + (picker.vm as any).showClose = true + await nextTick(); + (picker.element.querySelector('.el-icon-circle-close') as HTMLElement).click() + expect(vm.value).toBeNull() + }) + + it('event change, focus, blur', async () => { + const changeHandler = jest.fn() + const focusHandler = jest.fn() + const blurHandler = jest.fn() + let onChangeValue + const wrapper = _mount(``, () => ({ value: new Date(2016, 9, 10, 18, 40) }), { + methods: { + onChange(e) { + onChangeValue = e + return changeHandler(e) + }, + onFocus(e) { + return focusHandler(e) + }, + onBlur(e) { + return blurHandler(e) + }, + }, + }) + + const input = wrapper.find('input') + input.trigger('blur') + input.trigger('focus') + await nextTick() + expect(focusHandler).toHaveBeenCalledTimes(1); + (document.querySelector('td.available') as HTMLElement).click() + await nextTick() + expect(changeHandler).toHaveBeenCalledTimes(1) + expect(blurHandler).toHaveBeenCalledTimes(1) + expect(onChangeValue.getTime()).toBe(new Date(2016, 9, 1).getTime()) + }) + + it('shortcuts', async () => { + const text = 'Yesterday' + const value = new Date(Date.now() - 86400000) + value.setHours(0,0,0,0) + const wrapper = _mount(``, () => ({ value: '', shortcuts: [{ + text, + value, + }] })) + const input = wrapper.find('input') + input.trigger('blur') + input.trigger('focus') + await nextTick() + const shortcut = document.querySelector('.el-picker-panel__shortcut') + expect(shortcut.textContent).toBe(text) + expect(document.querySelector('.el-picker-panel__sidebar')).not.toBeNull(); + (shortcut as HTMLElement).click() + await nextTick() + const vm = wrapper.vm as any + expect(vm.value.valueOf()).toBe(value.valueOf()) + }) + + it('disabledDate', async () => { + const wrapper = _mount(``, () => ({ value: '', disabledDate(time) { + return time.getTime() < Date.now() - 8.64e7 + } })) + const input = wrapper.find('input') + input.trigger('blur') + input.trigger('focus') + await nextTick() + expect(document.querySelector('.disabled')).not.toBeNull() + }) +}) + +describe('DatePicker Navigation', () => { + let prevMonth, prevYear, nextMonth, nextYear, getYearLabel, getMonthLabel + + const initNavigationTest = async value => { + const wrapper = _mount(``, () => ({ value })) + + const input = wrapper.find('input') + input.trigger('blur') + input.trigger('focus') + await nextTick() + prevMonth = document.querySelector('button.el-icon-arrow-left') + prevYear = document.querySelector('button.el-icon-d-arrow-left') + nextMonth = document.querySelector('button.el-icon-arrow-right') + nextYear = document.querySelector('button.el-icon-d-arrow-right') + getYearLabel = () => document.querySelectorAll('.el-date-picker__header-label')[0].textContent + getMonthLabel = () => document.querySelectorAll('.el-date-picker__header-label')[1].textContent + } + + it('month, year', async() => { + await initNavigationTest(new Date(2000, 0, 1)) + expect(getYearLabel()).toContain('2000') + expect(getMonthLabel()).toContain('January') + + prevMonth.click() + await nextTick() + expect(getYearLabel()).toContain('1999') + expect(getMonthLabel()).toContain('December') + + prevYear.click() + await nextTick() + expect(getYearLabel()).toContain('1998') + expect(getMonthLabel()).toContain('December') + + nextMonth.click() + await nextTick() + expect(getYearLabel()).toContain('1999') + expect(getMonthLabel()).toContain('January') + + nextYear.click() + await nextTick() + expect(getYearLabel()).toContain('2000') + expect(getMonthLabel()).toContain('January') + }) + + it('month with fewer dates', async() => { + // July has 31 days, June has 30 + await initNavigationTest(new Date(2000, 6, 31)) + prevMonth.click() + await nextTick() + expect(getYearLabel()).toContain('2000') + expect(getMonthLabel()).toContain('June') + }) + + it('year with fewer Feburary dates', async() => { + // Feburary 2008 has 29 days, Feburary 2007 has 28 + await initNavigationTest(new Date(2008, 1, 29)) + prevYear.click() + await nextTick() + expect(getYearLabel()).toContain('2007') + expect(getMonthLabel()).toContain('February') + }) + + it('month label with fewer dates', async() => { + await initNavigationTest(new Date(2000, 6, 31)) + const yearLabel = document.querySelectorAll('.el-date-picker__header-label')[0]; + (yearLabel as HTMLElement).click() + await nextTick() + const year1999Label = document.querySelectorAll('.el-year-table td a')[1]; + (year1999Label as HTMLElement).click() + await nextTick() + const juneLabel = document.querySelectorAll('.el-month-table td a')[5]; + (juneLabel as HTMLElement).click() + await nextTick() + expect(getYearLabel()).toContain('2001') + expect(getMonthLabel()).toContain('June') + const monthLabel = document.querySelectorAll('.el-date-picker__header-label')[1]; + (monthLabel as HTMLElement).click() + await nextTick() + const janLabel = document.querySelectorAll('.el-month-table td a')[0]; + (janLabel as HTMLElement).click() + await nextTick() + expect(getYearLabel()).toContain('2001') + expect(getMonthLabel()).toContain('January') + }) +}) + +describe('MonthPicker', () => { + it('basic', async () => { + const wrapper = _mount(``, () => ({ value: new Date(2020, 7, 1) })) + const input = wrapper.find('input') + input.trigger('blur') + input.trigger('focus') + await nextTick() + expect((document.querySelector('.el-month-table') as HTMLElement).style.display).toBe('') + expect(document.querySelector('.el-year-table')).toBeNull(); + (document.querySelector('.el-month-table a.cell') as HTMLElement).click() + await nextTick() + const vm = wrapper.vm as any + expect(vm.value.getMonth()).toBe(0) + }) +}) + +describe('YearPicker', () => { + it('basic', async () => { + const wrapper = _mount(``, () => ({ value: new Date(2020, 7, 1) })) + const input = wrapper.find('input') + input.trigger('blur') + input.trigger('focus') + await nextTick() + expect((document.querySelector('.el-year-table') as HTMLElement).style.display).toBe('') + expect(document.querySelector('.el-month-table')).toBeNull() + + const leftBtn = document.querySelector('.el-icon-d-arrow-left') as HTMLElement + const rightBtn = document.querySelector('.el-icon-d-arrow-right') as HTMLElement + let count = 2 + + while (--count) { + leftBtn.click() + } + count = 3 + while (--count) { + rightBtn.click() + } + + await nextTick(); + + (document.querySelector('.el-year-table a.cell') as HTMLElement).click() + await nextTick() + const vm = wrapper.vm as any + expect(vm.value.getFullYear()).toBe(2030) + }) +}) + +describe('WeekPicker', () => { + it('create', async () => { + const wrapper = _mount(``, () => ({ value: new Date(2020, 7, 15) })) + const input = wrapper.find('input') + input.trigger('blur') + input.trigger('focus') + await nextTick() + expect(document.querySelector('.is-week-mode')).not.toBeNull(); + // select month still is in week-mode + (document.querySelectorAll('.el-date-picker__header-label')[1] as HTMLElement).click() + await nextTick(); + (document.querySelectorAll('.el-month-table .cell')[7] as HTMLElement).click() + await nextTick() + expect(document.querySelector('.is-week-mode')).not.toBeNull() + const numberOfHighlightRows = () => document.querySelectorAll('.el-date-table__row.current').length; + (document.querySelector('.el-date-table__row ~ .el-date-table__row td.available') as HTMLElement).click() + await nextTick() + const vm = wrapper.vm as any + expect(vm.value).not.toBeNull() + input.trigger('blur') + input.trigger('focus') + await nextTick() + expect(numberOfHighlightRows()).toBe(1); + // test: next month should not have highlight + (document.querySelector('.el-icon-arrow-right') as HTMLElement).click() + await nextTick() + expect(numberOfHighlightRows()).toBe(0); + // test: next year should not have highlight + (document.querySelector('.el-icon-arrow-left') as HTMLElement).click() + await nextTick(); + (document.querySelector('.el-icon-d-arrow-right') as HTMLElement).click() + await nextTick() + expect(numberOfHighlightRows()).toBe(0) + }) +}) + +describe('DatePicker dates', () => { + it('create', async () => { + const wrapper = _mount(``, () => ({ value: '' })) + const input = wrapper.find('input') + input.trigger('blur') + input.trigger('focus') + await nextTick() + const td = (document.querySelectorAll('.el-date-table__row .available') as NodeListOf) + const vm = wrapper.vm as any + td[0].click() + await nextTick() + expect(vm.value.length).toBe(1) + td[1].click() + await nextTick() + expect(vm.value.length).toBe(2) + expect(document.querySelectorAll('.el-date-table__row .selected').length).toBe(2) + td[0].click() + await nextTick() + expect(vm.value.length).toBe(1) + td[1].click() + await nextTick() + expect(vm.value.length).toBe(0) + }) +}) + +describe('DateRangePicker', () => { + + it('create', async () => { + const wrapper = _mount(``, () => ({ value: '' })) + const inputs = wrapper.findAll('input') + inputs[0].trigger('blur') + inputs[0].trigger('focus') + await nextTick() + + const panels = document.querySelectorAll('.el-date-range-picker__content') + expect(panels.length).toBe(2); + (panels[0].querySelector('td.available') as HTMLElement).click() + await nextTick(); + (panels[1].querySelector('td.available') as HTMLElement).click() + await nextTick() + inputs[0].trigger('blur') + inputs[0].trigger('focus') + await nextTick() + // correct highlight + const startDate = document.querySelectorAll('.start-date') + const endDate = document.querySelectorAll('.end-date') + const inRangeDate = document.querySelectorAll('.in-range') + expect(startDate.length).toBe(1) + expect(endDate.length).toBe(1) + expect(inRangeDate.length).toBeGreaterThan(28) + // value is array + const vm = wrapper.vm as any + expect(Array.isArray(vm.value)).toBeTruthy() + // input text is something like date string + expect(inputs[0].element.value.length).toBe(10) + expect(inputs[1].element.value.length).toBe(10) + }) + + it('reverse selection', async () => { + const wrapper = _mount(``, () => ({ value: '' })) + const inputs = wrapper.findAll('input') + inputs[0].trigger('blur') + inputs[0].trigger('focus') + await nextTick() + + const panels = document.querySelectorAll('.el-date-range-picker__content'); + (panels[1].querySelector('td.available') as HTMLElement).click() + await nextTick(); + (panels[0].querySelector('td.available') as HTMLElement).click() + await nextTick() + inputs[0].trigger('blur') + inputs[0].trigger('focus') + await nextTick() + // correct highlight + const startDate = document.querySelectorAll('.start-date') + const endDate = document.querySelectorAll('.end-date') + const inRangeDate = document.querySelectorAll('.in-range') + expect(startDate.length).toBe(1) + expect(endDate.length).toBe(1) + expect(inRangeDate.length).toBeGreaterThan(28) + const vm = wrapper.vm as any + expect(vm.value[0].getTime() < vm.value[1].getTime()).toBeTruthy() + }) + + it('unlink:true', async () => { + const wrapper = _mount(``, () => ({ value: [new Date(2000, 9, 1), new Date(2000, 11, 2)] })) + const inputs = wrapper.findAll('input') + inputs[0].trigger('blur') + inputs[0].trigger('focus') + await nextTick() + const panels = document.querySelectorAll('.el-date-range-picker__content') + const left = panels[0].querySelector('.el-date-range-picker__header') + const right = panels[1].querySelector('.is-right .el-date-range-picker__header') + expect(left.textContent).toBe('2000 October') + expect(right.textContent).toBe('2000 December'); + (panels[1].querySelector('.el-icon-d-arrow-right') as HTMLElement).click() + await nextTick(); + (panels[1].querySelector('.el-icon-arrow-right') as HTMLElement).click() + await nextTick() + expect(left.textContent).toBe('2000 October') + expect(right.textContent).toBe('2002 January') + }) + + it('daylight saving time highlight', async() => { + // Run test with environment variable TZ=Australia/Sydney + // The following test uses Australian Eastern Daylight Time (AEDT) + // AEST -> AEDT shift happened on 2016-10-02 02:00:00 + const wrapper = _mount(``, () => ({ value: [new Date(2016, 9, 1), new Date(2016, 9, 3)] })) + + const inputs = wrapper.findAll('input') + inputs[0].trigger('blur') + inputs[0].trigger('focus') + await nextTick() + + const startDate = document.querySelectorAll('.start-date') + const endDate = document.querySelectorAll('.end-date') + expect(startDate.length).toBe(1) + expect(endDate.length).toBe(1) + }) +}) + +describe('MonthRange', () => { + it('works', async () => { + const wrapper = _mount(``, () => ({ value: '' })) + + const inputs = wrapper.findAll('input') + inputs[0].trigger('blur') + inputs[0].trigger('focus') + await nextTick() + const panels = document.querySelectorAll('.el-date-range-picker__content') + expect(panels.length).toBe(2) + const p0 = panels[0].querySelector('td:not(.disabled)') + p0.click() + await nextTick() + const p1 = (panels[1].querySelector('td:not(.disabled)')) + p1.click() + await nextTick() + inputs[0].trigger('blur') + inputs[0].trigger('focus') + // correct highlight + const startDate = document.querySelectorAll('.start-date') + const endDate = document.querySelectorAll('.end-date') + const inRangeDate = document.querySelectorAll('.in-range') + expect(startDate.length).toBe(1) + expect(endDate.length).toBe(1) + expect(inRangeDate.length).toBeGreaterThan(0) + // value is array + const vm = wrapper.vm as any + expect(Array.isArray(vm.value)).toBeTruthy() + // input text is something like date string + expect(inputs[0].element.value.length).toBe(7) + expect(inputs[1].element.value.length).toBe(7) + // reverse selection + p1.click() + await nextTick() + p0.click() + await nextTick() + expect(vm.value[0].getTime() < vm.value[1].getTime()).toBeTruthy() + }) + + it('type:monthrange unlink:true', async () => { + const wrapper = _mount(``, () => ({ value: [new Date(2000, 9), new Date(2002, 11)] })) + + const inputs = wrapper.findAll('input') + inputs[0].trigger('blur') + inputs[0].trigger('focus') + await nextTick() + const panels = document.querySelectorAll('.el-date-range-picker__content') + const left = panels[0].querySelector('.el-date-range-picker__header') + const right = panels[1].querySelector('.is-right .el-date-range-picker__header') + expect(left.textContent).toContain(2000) + expect(right.textContent).toContain(2002); + (panels[1].querySelector('.el-icon-d-arrow-right') as HTMLElement).click() + await nextTick() + expect(left.textContent).toContain(2000) + expect(right.textContent).toContain(2003) + }) + + it('daylight saving time highlight', async () => { + const wrapper = _mount(``, () => ({ value: [new Date(2016, 6), new Date(2016, 12)] })) + + const inputs = wrapper.findAll('input') + inputs[0].trigger('blur') + inputs[0].trigger('focus') + await nextTick() + const startDate = document.querySelectorAll('.start-date') + const endDate = document.querySelectorAll('.end-date') + expect(startDate.length).toBe(1) + expect(endDate.length).toBe(1) + }) +}) + diff --git a/packages/date-picker/__tests__/date-time-picker.spec.ts b/packages/date-picker/__tests__/date-time-picker.spec.ts new file mode 100644 index 0000000000..3bbe52fbf1 --- /dev/null +++ b/packages/date-picker/__tests__/date-time-picker.spec.ts @@ -0,0 +1,480 @@ +import { triggerEvent } from '@element-plus/test-utils' +import { mount } from '@vue/test-utils' +import dayjs from 'dayjs' +import { nextTick } from 'vue' +import DatePicker from '../src/date-picker' + +const formatStr = 'YYYY-MM-DD HH:mm:ss' +const makeRange = (start, end) => { + const result = [] + for (let i = start; i <= end; i++) { + result.push(i) + } + return result +} +const _mount = (template: string, data = () => ({}), otherObj?) => mount({ + components: { + 'el-date-picker': DatePicker, + }, + template, + data, + ...otherObj, +}, { + global: { + provide: { + elForm: {}, + elFormItem: {}, + }, + }, +}) + +afterEach(() => { + document.documentElement.innerHTML = '' +}) + + +describe('Datetime Picker', () => { + + it('both picker show correct formated value (extract date-format and time-format from format property', async () => { + const wrapper = _mount(``, () => ({ + value: new Date(2018, 2, 5, 10, 15, 24), + format: 'YYYY/MM/DD HH:mm A', + })) + const input = wrapper.find('input') + input.trigger('blur') + input.trigger('focus') + await nextTick() + const dateInput = document.querySelector('.el-date-picker__time-header > span:nth-child(1) input') + const timeInput = document.querySelector('.el-date-picker__time-header > span:nth-child(2) input'); + (timeInput as HTMLElement).focus() + await nextTick() + // both input shows correct value + expect((dateInput as HTMLInputElement).value).toBe('2018/03/05') + expect((timeInput as HTMLInputElement).value).toBe('10:15 AM') + wrapper.setProps({ + format: 'MM-DD-YYYY HH a', + }) + await nextTick() + expect((dateInput as HTMLInputElement).value).toBe('03-05-2018') + expect((timeInput as HTMLInputElement).value).toBe('10 am') + }) + + it('both picker show correct value', async () => { + const wrapper = _mount(``, () => ({ + value: new Date(2000, 9, 1, 10, 0, 1), + })) + + const input = wrapper.find('input') + input.trigger('blur') + input.trigger('focus') + await nextTick() + const dateInput = document.querySelector('.el-date-picker__time-header > span:nth-child(1) input') + const timeInput = document.querySelector('.el-date-picker__time-header > span:nth-child(2) input'); + (timeInput as HTMLElement).focus() + await nextTick() + // both input shows correct value + expect((dateInput as HTMLInputElement).value).toBe('2000-10-01') + expect((timeInput as HTMLInputElement).value).toBe('10:00:01') + // time spinner highlight is correct + let spinners = document.querySelectorAll('.el-time-spinner ul li.active') as any + expect(spinners[0].textContent).toBe('10') + expect(spinners[1].textContent).toBe('00') + expect(spinners[2].textContent).toBe('01') + wrapper.setProps({ + modelValue: new Date(2001, 10, 2, 11, 1, 2), + }) + await nextTick() + spinners = document.querySelectorAll('.el-time-spinner ul li.active') as any + expect((dateInput as HTMLInputElement).value).toBe('2001-11-02') + expect((timeInput as HTMLInputElement).value).toBe('11:01:02') + expect(spinners[0].textContent).toBe('11') + expect(spinners[1].textContent).toBe('01') + expect(spinners[2].textContent).toBe('02') + }) + + it('click now button', async () => { + const wrapper = _mount(``, () => ({ + value: '', + })) + const input = wrapper.find('input') + input.trigger('blur') + input.trigger('focus') + await nextTick(); + (document.querySelector('.el-picker-panel__link-btn') as HTMLElement).click() + await nextTick() + const vm = wrapper.vm as any + // test if is current time (deviation 10 seconds) + expect(dayjs(vm.value).diff(dayjs()) < 10).toBeTruthy() + }) + + it('timepicker select && input time && input date', async () => { + const wrapper = _mount(``, () => ({ + value: '', + })) + const vm = wrapper.vm as any + expect(vm.value).toBe('') + const input = wrapper.find('input') + input.trigger('blur') + input.trigger('focus') + await nextTick() + const input_ = document.querySelectorAll('.el-date-picker__editor-wrap input')[1]; + (input_ as HTMLElement).focus() + await nextTick() + const timePanel = document.querySelector('.el-time-panel') + expect(timePanel.querySelector('.el-time-spinner').innerHTML).not.toBeNull() + const button = document.querySelector('.el-time-panel .confirm') as HTMLElement + button.click() + await nextTick() + expect(vm.value).not.toBe('') + const timeInput = document.querySelectorAll('.el-date-picker__editor-wrap input')[1] as HTMLInputElement + timeInput.value = '20:30:33' + timeInput.dispatchEvent(new Event('change')) + await nextTick() + const valueResult = dayjs(vm.value) + expect(valueResult.hour()).toBe(20) + expect(valueResult.minute()).toBe(30) + expect(valueResult.second()).toBe(33) + const dateInput = document.querySelector('.el-date-picker__editor-wrap input') as HTMLInputElement + dateInput.value = '2017-02-02' + dateInput.dispatchEvent(new Event('change')) + await nextTick() + const valueResult2 = dayjs(vm.value) + expect(valueResult2.year()).toBe(2017) + expect(valueResult2.month()).toBe(1) + expect(valueResult2.date()).toBe(2) + }) + + it('now button: can not choose disabled date', async () => { + let isDisable = true + const wrapper = _mount(``, () => ({ + value: '', + disabledDate() { + return isDisable + }, + })) + const input = wrapper.find('input') + input.trigger('blur') + input.trigger('focus') + await nextTick() + // click now button + const btn = document.querySelector('.el-picker-panel__footer .el-button--text') as HTMLElement + btn.click() + await nextTick() + const vm = wrapper.vm as any + expect(vm.value).toBe('') + isDisable = false + await nextTick() + btn.click() + await nextTick() + expect(vm.value).not.toBe('') + }) + + it('confirm button honors picked date', async () => { + const wrapper = _mount(``, () => ({ + value: new Date(2000, 9, 1, 12, 0, 0), // 2010-10-01 12:00:00 + })) + const input = wrapper.find('input') + input.trigger('blur') + input.trigger('focus') + await nextTick(); + // changed month / year should not effect picked time + (document.querySelector('.el-date-picker__header .el-icon-arrow-right') as HTMLElement).click(); + (document.querySelector('.el-date-picker__header .el-icon-d-arrow-right') as HTMLElement).click(); + // click confirm button + (document.querySelector('.el-picker-panel__footer .el-button--default') as HTMLElement).click() + const vm = wrapper.vm as any + expect(dayjs(vm.value).format(formatStr)).toBe('2000-10-01 12:00:00') + }) + + it('selectableRange', async () => { + const disabledHoursArr = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,23] + const wrapper = _mount(``, () => ({ + value: new Date(2019, 0, 1, 18, 50) }), + { + methods: { + disabledHours() { + return disabledHoursArr + }, + disabledMinutes (hour) { + // ['17:30:00 - 18:30:00', '18:50:00 - 20:30:00', '21:00:00 - 22:00:00'] + if (hour === 17) { + return makeRange(0, 29) + } + if (hour === 18) { + return makeRange(31, 49) + } + if (hour === 20) { + return makeRange(31, 59) + } + if (hour === 22) { + return makeRange(1, 59) + } + }, + disabledSeconds(hour, minute) { + if (hour === 18 && minute === 30) { + return makeRange(1, 59) + } + if (hour === 20 && minute === 30) { + return makeRange(1, 59) + } + if (hour === 22 && minute === 0) { + return makeRange(1, 59) + } + }, + }, + }) + const input = wrapper.find('input') + input.trigger('blur') + input.trigger('focus') + await nextTick() + const input1 = document.querySelectorAll('.el-date-picker__editor-wrap input')[1] as HTMLInputElement + input1.blur() + input1.focus() + await nextTick() + const list = document.querySelectorAll('.el-time-spinner__list') + const hoursEl = list[0] + const disabledHours = [].slice + .call(hoursEl.querySelectorAll('.disabled')) + .map(node => Number(node.textContent)) + expect(disabledHours).toStrictEqual(disabledHoursArr) + const minutesEl = list[1] + const disabledMinutes = [].slice + .call(minutesEl.querySelectorAll('.disabled')) + .map(node => Number(node.textContent)) + expect(disabledMinutes.length).toBe(19) + }) +}) + +describe('Datetimerange', () => { + + it('select daterange and default Time and input format', async () => { + const wrapper = _mount(``, () => ({ + value: [new Date(2000, 10, 8, 10, 10), new Date(2000, 10, 11, 10, 10)], + })) + const input = wrapper.find('input') + input.trigger('blur') + input.trigger('focus') + await nextTick() + const pickers = document.querySelectorAll('.el-date-range-picker__content') + const leftCell = pickers[0].querySelector('td.available') + const rightCell = pickers[1].querySelector('td.available') + triggerEvent(leftCell, 'mousemove', true) + triggerEvent(leftCell, 'click', true) + await nextTick() + triggerEvent(rightCell, 'mousemove', true) + triggerEvent(rightCell, 'click', true) + await nextTick(); + (document.querySelector('.el-picker-panel__footer .el-button--default') as HTMLElement).click() + await nextTick() + const vm = wrapper.vm as any + expect(vm.value.map(_ => dayjs(_).format(formatStr))) + .toStrictEqual(['2000-11-01 01:01:01', '2000-12-01 01:01:01']) + const pickerss = document.querySelectorAll('.el-date-range-picker__time-header .el-date-range-picker__editors-wrap') + const left = { + dateInput: pickerss[0].querySelector('.el-date-range-picker__time-picker-wrap:nth-child(1) input'), + timeInput: pickerss[0].querySelector('.el-date-range-picker__time-picker-wrap:nth-child(2) input'), + } + const right = { + dateInput: pickerss[1].querySelector('.el-date-range-picker__time-picker-wrap:nth-child(1) input'), + timeInput: pickerss[1].querySelector('.el-date-range-picker__time-picker-wrap:nth-child(2) input'), + } + await nextTick() + // both input shows correct value + expect((left.dateInput as HTMLInputElement).value).toBe('2000/11/01') + expect((left.timeInput as HTMLInputElement).value).toBe('01:01 AM') + expect((right.dateInput as HTMLInputElement).value).toBe('2000/12/01') + expect((right.timeInput as HTMLInputElement).value).toBe('01:01 AM') + }) + + it('input date', async () => { + const wrapper = _mount(``, () => ({ + value: '', + })) + const input = wrapper.find('input') + input.trigger('blur') + input.trigger('focus') + await nextTick() + const pickerss = document.querySelectorAll('.el-date-range-picker__time-header .el-date-range-picker__editors-wrap') + const leftDateInput = pickerss[0].querySelector('.el-date-range-picker__time-picker-wrap:nth-child(1) input') as HTMLInputElement + const rightDateInput = pickerss[0].querySelector('.el-date-range-picker__time-picker-wrap:nth-child(1) input') as HTMLInputElement + leftDateInput.value = '1999-03-04' + triggerEvent(leftDateInput, 'input', true) + triggerEvent(leftDateInput, 'change', true) + await nextTick() + const pickers = document.querySelectorAll('.el-date-range-picker__content') + const leftCell = pickers[0].querySelector('td.available') + const rightCell = pickers[1].querySelector('td.available') + triggerEvent(leftCell, 'mousemove', true) + triggerEvent(leftCell, 'click', true) + await nextTick() + triggerEvent(rightCell, 'mousemove', true) + triggerEvent(rightCell, 'click', true) + await nextTick() + const btn = document.querySelector('.el-picker-panel__footer .el-button--default') as HTMLElement + btn.click() + await nextTick() + const vm = wrapper.vm as any + expect(vm.value.map(_ => dayjs(_).format(formatStr))) + .toStrictEqual(['1999-03-01 00:00:00','1999-04-01 00:00:00']) + // input date when minDate > maxDate + rightDateInput.value = '1998-01-01' + triggerEvent(rightDateInput, 'input', true) + triggerEvent(rightDateInput, 'change', true) + await nextTick() + btn.click() + await nextTick() + expect(dayjs(vm.value[0]).isBefore(vm.value[1])).toBeTruthy() + }) + + + it('select time', async () => { + const wrapper = _mount(``, () => ({ + value: '', + })) + const vm = wrapper.vm as any + expect(vm.value).toBe('') + const input = wrapper.find('input') + input.trigger('blur') + input.trigger('focus') + await nextTick() + const timeInput = document.querySelectorAll('.el-date-range-picker__editors-wrap input')[1] as HTMLInputElement + timeInput.blur() + timeInput.focus() + timeInput.blur() + await nextTick() + const button = document.querySelector('.el-date-range-picker__time-picker-wrap .el-time-panel .confirm') as HTMLElement + button.click() + await nextTick() + const btn = document.querySelector('.el-picker-panel__footer .el-button--default') as HTMLElement + btn.click() + await nextTick() + expect(vm.value).not.toBe('') + }) + + it('confirm honors disabledDate', async () => { + const wrapper = _mount(``, () => ({ + value: '', + disabledDate: date => { + return date.getTime() < new Date(2000, 9, 1) // 2000-10-01 + }, + })) + const vm = wrapper.vm as any + const input = wrapper.find('input') + input.trigger('blur') + input.trigger('focus') + await nextTick() + // simulate user input of invalid date + const pickerss = document.querySelectorAll('.el-date-range-picker__time-header .el-date-range-picker__editors-wrap') + const leftDateInput = pickerss[0].querySelector('.el-date-range-picker__time-picker-wrap:nth-child(1) input') as HTMLInputElement + leftDateInput.value = '2000-09-01' + triggerEvent(leftDateInput, 'input', true) + triggerEvent(leftDateInput, 'change', true) + await nextTick() + const btn = document.querySelector('.el-picker-panel__footer .el-button--default') as HTMLElement + expect(btn.getAttribute('disabled')).not.toBeUndefined() // invalid input disables button + btn.click() + await nextTick() + const rangePanel = document.querySelector('.el-date-range-picker') + expect(rangePanel.getAttribute('visible')).toBe('true') // popper still open + expect(vm.value).toBe('') + leftDateInput.value = '2001-09-01' + triggerEvent(leftDateInput, 'input', true) + triggerEvent(leftDateInput, 'change', true) + await nextTick() + expect(btn.getAttribute('disabled')).not.toBeUndefined() + btn.click() + await nextTick() + expect(rangePanel.getAttribute('visible')).toBe('false') // popper dismiss + expect(vm.value).not.toBe('') + }) + + it('selectableRange', async () => { + const disabledHoursArr = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,23] + const disabledHoursRightArr = [0,1,2] + const wrapper = _mount(``, () => ({ + value: '' }), + { + methods: { + disabledHours(role) { + if (role === 'end') { + return disabledHoursRightArr + } + return disabledHoursArr + }, + }, + }) + const input = wrapper.find('input') + input.trigger('blur') + input.trigger('focus') + await nextTick() + const pickerss = document.querySelectorAll('.el-date-range-picker__time-header .el-date-range-picker__editors-wrap') + const leftDateInput = pickerss[0].querySelector('.el-date-range-picker__time-picker-wrap:nth-child(2) input') as HTMLInputElement + const rightDateInput = pickerss[1].querySelector('.el-date-range-picker__time-picker-wrap:nth-child(2) input') as HTMLInputElement + leftDateInput.blur() + leftDateInput.focus() + await nextTick() + const listleft = document.querySelectorAll('.el-date-range-picker__editors-wrap .el-time-spinner__list') + const hoursEl = listleft[0] + const disabledHours = [].slice + .call(hoursEl.querySelectorAll('.disabled')) + .map(node => Number(node.textContent)) + expect(disabledHours).toStrictEqual(disabledHoursArr) + const button = document.querySelector('.el-date-range-picker__time-picker-wrap .el-time-panel .confirm') as HTMLElement + button.click() + await nextTick() + rightDateInput.blur() + rightDateInput.focus() + await nextTick() + const listright = document.querySelectorAll('.el-date-range-picker__editors-wrap.is-right .el-time-spinner__list') + const hoursEl2 = listright[0] + const disabledHours2 = [].slice + .call(hoursEl2.querySelectorAll('.disabled')) + .map(node => Number(node.textContent)) + expect(disabledHours2).toStrictEqual(disabledHoursRightArr) + }) +}) diff --git a/packages/date-picker/index.ts b/packages/date-picker/index.ts new file mode 100644 index 0000000000..1065531739 --- /dev/null +++ b/packages/date-picker/index.ts @@ -0,0 +1,5 @@ +import { App } from 'vue' +import DatePicker from './src/date-picker' +export default (app: App): void => { + app.component(DatePicker.name, DatePicker) +} diff --git a/packages/date-picker/package.json b/packages/date-picker/package.json new file mode 100644 index 0000000000..7d0944c99b --- /dev/null +++ b/packages/date-picker/package.json @@ -0,0 +1,12 @@ +{ + "name": "@element-plus/date-picker", + "version": "0.0.0", + "main": "dist/index.js", + "license": "MIT", + "peerDependencies": { + "vue": "^3.0.0-rc.9" + }, + "devDependencies": { + "@vue/test-utils": "^2.0.0-beta.3" + } +} diff --git a/packages/date-picker/src/date-picker-com/basic-date-table.vue b/packages/date-picker/src/date-picker-com/basic-date-table.vue new file mode 100644 index 0000000000..39ae9cec3b --- /dev/null +++ b/packages/date-picker/src/date-picker-com/basic-date-table.vue @@ -0,0 +1,385 @@ + + + diff --git a/packages/date-picker/src/date-picker-com/basic-month-table.vue b/packages/date-picker/src/date-picker-com/basic-month-table.vue new file mode 100644 index 0000000000..135f6e9594 --- /dev/null +++ b/packages/date-picker/src/date-picker-com/basic-month-table.vue @@ -0,0 +1,222 @@ + + + diff --git a/packages/date-picker/src/date-picker-com/basic-year-table.vue b/packages/date-picker/src/date-picker-com/basic-year-table.vue new file mode 100644 index 0000000000..b05ae00e31 --- /dev/null +++ b/packages/date-picker/src/date-picker-com/basic-year-table.vue @@ -0,0 +1,112 @@ + + + diff --git a/packages/date-picker/src/date-picker-com/panel-date-pick.vue b/packages/date-picker/src/date-picker-com/panel-date-pick.vue new file mode 100644 index 0000000000..8c10ecaf86 --- /dev/null +++ b/packages/date-picker/src/date-picker-com/panel-date-pick.vue @@ -0,0 +1,585 @@ + + + + diff --git a/packages/date-picker/src/date-picker-com/panel-date-range.vue b/packages/date-picker/src/date-picker-com/panel-date-range.vue new file mode 100644 index 0000000000..9fea4fb29b --- /dev/null +++ b/packages/date-picker/src/date-picker-com/panel-date-range.vue @@ -0,0 +1,666 @@ + + + + diff --git a/packages/date-picker/src/date-picker-com/panel-month-range.vue b/packages/date-picker/src/date-picker-com/panel-month-range.vue new file mode 100644 index 0000000000..ceaca72082 --- /dev/null +++ b/packages/date-picker/src/date-picker-com/panel-month-range.vue @@ -0,0 +1,289 @@ + + + diff --git a/packages/date-picker/src/date-picker.ts b/packages/date-picker/src/date-picker.ts new file mode 100644 index 0000000000..6295c241bd --- /dev/null +++ b/packages/date-picker/src/date-picker.ts @@ -0,0 +1,53 @@ +import { DEFAULT_FORMATS_DATE, DEFAULT_FORMATS_DATEPICKER } from '@element-plus/time-picker/src/common/constant' +import Picker from '@element-plus/time-picker/src/common/picker.vue' +import DatePickPanel from './date-picker-com/panel-date-pick.vue' +import DateRangePickPanel from './date-picker-com/panel-date-range.vue' +import MonthRangePickPanel from './date-picker-com/panel-month-range.vue' +import dayjs from 'dayjs' +import customParseFormat from 'dayjs/plugin/customParseFormat' +import advancedFormat from 'dayjs/plugin/advancedFormat' +import localeData from 'dayjs/plugin/localeData' +import weekOfYear from 'dayjs/plugin/weekOfYear' +import weekYear from 'dayjs/plugin/weekYear' +import isLeapYear from 'dayjs/plugin/isLeapYear' +import isSameOrAfter from 'dayjs/plugin/isSameOrAfter' +import isSameOrBefore from 'dayjs/plugin/isSameOrBefore' +import { h } from 'vue' +dayjs.extend(isLeapYear) +dayjs.extend(localeData) +dayjs.extend(advancedFormat) +dayjs.extend(customParseFormat) +dayjs.extend(weekOfYear) +dayjs.extend(weekYear) +dayjs.extend(isSameOrAfter) +dayjs.extend(isSameOrBefore) + +const getPanel = function(type) { + if (type === 'daterange' || type === 'datetimerange') { + return DateRangePickPanel + } else if (type === 'monthrange') { + return MonthRangePickPanel + } + return DatePickPanel +} + +export default { + name: 'ElDatePicker', + props: { + type: { + type: String, + default: 'date', + }, + }, + setup(props) { + const format = DEFAULT_FORMATS_DATEPICKER[props.type] || DEFAULT_FORMATS_DATE + return () => h(Picker, { + format, + type: props.type, + ...props, + }, + { + default: scopedProps => h(getPanel(props.type), scopedProps), + }) + }, +} diff --git a/packages/element-plus/index.ts b/packages/element-plus/index.ts index ae9c37f88c..d429ea0ac5 100644 --- a/packages/element-plus/index.ts +++ b/packages/element-plus/index.ts @@ -28,6 +28,7 @@ import ElSteps from '@element-plus/steps' import ElCollapse from '@element-plus/collapse' import ElPopper from '@element-plus/popper' import ElTimePicker from '@element-plus/time-picker' +import ElDatePicker from '@element-plus/date-picker' import ElTabs from '@element-plus/tabs' import ElTooltip from '@element-plus/tooltip' import ElSlider from '@element-plus/slider' @@ -71,6 +72,7 @@ export { ElRadio, ElCollapse, ElTimePicker, + ElDatePicker, ElTabs, ElTooltip, ElSlider, @@ -116,6 +118,7 @@ const install = (app: App): void => { ElCollapse(app) ElPopper(app) ElTimePicker(app) + ElDatePicker(app) ElTabs(app) ElTooltip(app) ElSlider(app) diff --git a/packages/input/src/index.vue b/packages/input/src/index.vue index 22148fa975..698961c77f 100644 --- a/packages/input/src/index.vue +++ b/packages/input/src/index.vue @@ -161,8 +161,8 @@ export default defineComponent({ default: 'text', }, size: { - type: String as PropType<'large' | 'medium' | 'small' | 'mini'>, - validator: (val: string) => ['large', 'medium', 'small', 'mini'].includes(val), + type: String as PropType<'large' | 'medium' | 'small' | 'mini' | null>, + validator: (val: string) => !val || ['large', 'medium', 'small', 'mini'].includes(val), }, resize: { type: String as PropType<'none' | 'both' | 'horizontal' | 'vertical'>, diff --git a/packages/test-utils/index.ts b/packages/test-utils/index.ts index 274699762a..bb108a0551 100644 --- a/packages/test-utils/index.ts +++ b/packages/test-utils/index.ts @@ -3,3 +3,4 @@ export { default as defineGetter } from './define-getter' export { default as makeScroll } from './make-scroll' export { default as sleep } from './sleep' export { default as tick } from './tick' +export { default as triggerEvent } from './trigger-event' diff --git a/packages/test-utils/trigger-event.ts b/packages/test-utils/trigger-event.ts new file mode 100644 index 0000000000..664c9f1931 --- /dev/null +++ b/packages/test-utils/trigger-event.ts @@ -0,0 +1,27 @@ +/** + * Trigger event + * mouseenter, mouseleave, mouseover, keyup, change, click + * @param {Element} elm + * @param {String} name + * @param {*} opts + */ +const triggerEvent = (elm, name, ...opts) => { + let eventName + + if (/^mouse|click/.test(name)) { + eventName = 'MouseEvents' + } else if (/^key/.test(name)) { + eventName = 'KeyboardEvent' + } else { + eventName = 'HTMLEvents' + } + const evt = document.createEvent(eventName) + + evt.initEvent(name, ...opts) + elm.dispatchEvent + ? elm.dispatchEvent(evt) + : elm.fireEvent('on' + name, evt) + + return elm +} +export default triggerEvent diff --git a/packages/theme-chalk/src/date-picker/picker-panel.scss b/packages/theme-chalk/src/date-picker/picker-panel.scss index 70fed3b0d5..131c8d3a66 100644 --- a/packages/theme-chalk/src/date-picker/picker-panel.scss +++ b/packages/theme-chalk/src/date-picker/picker-panel.scss @@ -1,6 +1,7 @@ @import "../common/var"; @include b(picker-panel) { + position: relative; color: $--color-text-regular; border: 1px solid $--datepicker-border-color; box-shadow: $--box-shadow-light; diff --git a/packages/time-picker/src/common/constant.ts b/packages/time-picker/src/common/constant.ts index 41241d8643..a240a51eeb 100644 --- a/packages/time-picker/src/common/constant.ts +++ b/packages/time-picker/src/common/constant.ts @@ -1,12 +1,12 @@ -// daterange: 'YYYY-MM-DD', -// monthrange: 'YYYY-MM', -// datetimerange: 'yyyy-MM-DD HH:mm:ss', export const DEFAULT_FORMATS_TIME = 'HH:mm:ss' export const DEFAULT_FORMATS_DATE = 'YYYY-MM-DD' export const DEFAULT_FORMATS_DATEPICKER = { - 'date': DEFAULT_FORMATS_DATE, - 'week': 'YYYYwWW', - 'year': 'YYYY', - 'month': 'YYYY-MM', - 'datetime': 'YYYY-MM-DD HH:mm:ss', + date: DEFAULT_FORMATS_DATE, + week: 'gggg[w]ww', + year: 'YYYY', + month: 'YYYY-MM', + datetime: `${DEFAULT_FORMATS_DATE} ${DEFAULT_FORMATS_TIME}`, + monthrange: 'YYYY-MM', + daterange: DEFAULT_FORMATS_DATE, + datetimerange: `${DEFAULT_FORMATS_DATE} ${DEFAULT_FORMATS_TIME}`, } diff --git a/packages/time-picker/src/common/date-utils.ts b/packages/time-picker/src/common/date-utils.ts new file mode 100644 index 0000000000..f7d69188b8 --- /dev/null +++ b/packages/time-picker/src/common/date-utils.ts @@ -0,0 +1,16 @@ +export const rangeArr = n => { + return Array.from(Array(n).keys()) +} + +export const extractDateFormat = format => { + return format + .replace(/\W?m{1,2}|\W?ZZ/g, '') + .replace(/\W?h{1,2}|\W?s{1,3}|\W?a/gi, '') + .trim() +} + +export const extractTimeFormat = format => { + return format + .replace(/\W?D{1,2}|\W?Do|\W?d{1,4}|\W?M{1,4}|\W?Y{2,4}/g, '') + .trim() +} diff --git a/packages/time-picker/src/common/picker.vue b/packages/time-picker/src/common/picker.vue index e7a0d9e4f7..9241519cb1 100644 --- a/packages/time-picker/src/common/picker.vue +++ b/packages/time-picker/src/common/picker.vue @@ -3,6 +3,7 @@ @@ -128,7 +130,6 @@ import { ClickOutside } from '@element-plus/directives' import ElInput from '@element-plus/input/src/index.vue' import { Popper as ElPopper } from '@element-plus/popper' import { EVENT_CODE } from '@element-plus/utils/aria' -import mitt from 'mitt' // Date object and string const dateEquals = function(a, b) { const aIsDate = a instanceof Date @@ -166,6 +167,7 @@ interface PickerOptions { parseUserInput: any formatToString: any getRangeAvaliableTime: any + getDefaultValue: any panelReady: boolean } export default defineComponent({ @@ -232,7 +234,9 @@ export default defineComponent({ endPlaceholder: String, defaultValue: { type: [Date, Array] as PropType, - default: new Date(), + }, + defaultTime: { + type: [Date, Array] as PropType, }, isRange: { type: Boolean, @@ -240,20 +244,30 @@ export default defineComponent({ }, disabledHours: { type: Function, - default: null, }, disabledMinutes: { type: Function, - default: null, }, disabledSeconds: { type: Function, - default: null, + }, + disabledDate: { + type: Function, + }, + cellClassName: { + type: Function, + }, + shortcuts: { + type: Array, + default: () => ([]), + }, + arrowControl: { + type: Boolean, + default: false, }, }, emits: ['update:modelValue', 'change', 'focus', 'blur'], setup(props, ctx) { - const oldValue = ref(props.modelValue) const refContainer = ref(null) const pickerVisible = ref(false) const valueOnOpen = ref(null) @@ -295,17 +309,14 @@ export default defineComponent({ _inputs[1].focus() } } - const onPick = (date: any = '', visible = false, useOldValue = false) => { + const onPick = (date: any = '', visible = false) => { pickerVisible.value = visible let result - if (useOldValue) { - result = oldValue.value + if (Array.isArray(date)) { + result = date.map(_ => _.toDate()) } else { - if (Array.isArray(date)) { - result = date.map(_ => _.toDate()) - } else { - result = date.toDate() - } + // clear btn emit null + result = date ? date.toDate() : date } userInput.value = null emitInput(result) @@ -323,26 +334,18 @@ export default defineComponent({ const parsedValue = computed(() => { let result - if (isRangeInput.value) { - if (!props.modelValue) { - if (Array.isArray(props.defaultValue)) { - result = (props.defaultValue as Array).map(_=> dayjs(_)) - } else { - result = [ - dayjs(props.defaultValue as Date), - dayjs(props.defaultValue as Date).add(60,'m'), - ] - } - } else { - result = (props.modelValue as Array).map(_=> dayjs(_)) + if (valueIsEmpty.value) { + if (pickerOptions.value.getDefaultValue) { + result = pickerOptions.value.getDefaultValue() } } else { - if (!props.modelValue) { - result = dayjs(props.defaultValue as Date) + if (Array.isArray(props.modelValue)) { + result = props.modelValue.map(_=>dayjs(_)) } else { result = dayjs(props.modelValue as Date) } } + if (pickerOptions.value.getRangeAvaliableTime) { result = pickerOptions.value.getRangeAvaliableTime(result) } @@ -351,7 +354,8 @@ export default defineComponent({ const displayValue = computed(() => { if (!pickerOptions.value.panelReady) return - if (!pickerVisible.value && !props.modelValue) return + if (!isTimePicker.value && valueIsEmpty.value) return + if (!pickerVisible.value && valueIsEmpty.value) return const formattedValue = formatDayjsToString(parsedValue.value) if (Array.isArray(userInput.value)) { return [ @@ -362,14 +366,27 @@ export default defineComponent({ return userInput.value } if (formattedValue) { - return props.type === 'dates' + return isDatesPicker.value ? (formattedValue as Array).join(', ') : formattedValue } return '' }) + + const isTimeLikePicker = computed(() => { + return props.type.indexOf('time') !== -1 + }) + + const isTimePicker = computed(() => { + return props.type.indexOf('time') === 0 + }) + + const isDatesPicker = computed(() => { + return props.type === 'dates' + }) + const triggerClass = computed(() => { - return props.prefixIcon || (props.type.indexOf('time') !== -1 ? 'el-icon-time' : 'el-icon-date') + return props.prefixIcon || (isTimeLikePicker.value ? 'el-icon-time' : 'el-icon-date') }) const showClose = ref(false) const onClearIconClick = event =>{ @@ -383,7 +400,7 @@ export default defineComponent({ } } const valueIsEmpty = computed(() => { - return !props.modelValue + return !props.modelValue || (Array.isArray(props.modelValue) && !props.modelValue.length) }) const onMouseEnter = () => { if (props.readonly || pickerDisabled.value) return @@ -410,7 +427,7 @@ export default defineComponent({ pickerVisible.value = false } - const userInput =ref(null) + const userInput = ref(null) const handleChange = () => { if (userInput.value) { @@ -434,10 +451,12 @@ export default defineComponent({ } const parseUserInputToDayjs = value => { + if (!value) return null return pickerOptions.value.parseUserInput(value) } const formatDayjsToString = value => { + if (!value) return null return pickerOptions.value.formatToString(value) } @@ -535,16 +554,16 @@ export default defineComponent({ } const pickerOptions = ref({} as PickerOptions) - const pickerHub = mitt() - pickerHub.on('SetPickerOption', e => { + const onSetPickerOption = e => { pickerOptions.value[e[0]] = e[1] pickerOptions.value.panelReady = true - }) + } + provide('EP_PICKER_BASE', { - hub: pickerHub, props, }) return { + isDatesPicker, handleEndChange, handleStartChange, handleStartInput, @@ -568,6 +587,7 @@ export default defineComponent({ setSelectionRange, refContainer, pickerDisabled, + onSetPickerOption, } }, }) diff --git a/packages/time-picker/src/time-picker-com/basic-time-spinner.vue b/packages/time-picker/src/time-picker-com/basic-time-spinner.vue index c77f0b13dd..551de1e3bc 100644 --- a/packages/time-picker/src/time-picker-com/basic-time-spinner.vue +++ b/packages/time-picker/src/time-picker-com/basic-time-spinner.vue @@ -59,7 +59,6 @@ import { nextTick, computed, onMounted, - inject, Ref, PropType, watch, @@ -97,9 +96,18 @@ export default defineComponent({ type: String, default: '', // 'a': am/pm; 'A': AM/PM }, + disabledHours: { + type: Function, + }, + disabledMinutes: { + type: Function, + }, + disabledSeconds: { + type: Function, + }, }, - emits: ['change', 'select-range'], + emits: ['change', 'select-range', 'set-option'], setup(props, ctx) { // data @@ -312,18 +320,17 @@ export default defineComponent({ return `list${item.charAt(0).toUpperCase() + item.slice(1)}Ref` } - const pickerPanel = inject('EP_TIMEPICK_PANEL') as any - pickerPanel.hub.emit('SetOption',[`${props.role}_scrollDown`, scrollDown]) - pickerPanel.hub.emit('SetOption',[`${props.role}_emitSelectRange`, emitSelectRange]) + ctx.emit('set-option',[`${props.role}_scrollDown`, scrollDown]) + ctx.emit('set-option',[`${props.role}_emitSelectRange`, emitSelectRange]) const { getHoursList, getMinutesList, getSecondsList, } = getTimeLists( - pickerPanel.methods.disabledHours, - pickerPanel.methods.disabledMinutes, - pickerPanel.methods.disabledSeconds, + props.disabledHours, + props.disabledMinutes, + props.disabledSeconds, ) watch(() => props.spinnerDate, () => { diff --git a/packages/time-picker/src/time-picker-com/panel-time-pick.vue b/packages/time-picker/src/time-picker-com/panel-time-pick.vue index 5015c512a4..fc580a995b 100644 --- a/packages/time-picker/src/time-picker-com/panel-time-pick.vue +++ b/packages/time-picker/src/time-picker-com/panel-time-pick.vue @@ -7,12 +7,16 @@
@@ -42,12 +46,10 @@ import { ref, computed, inject, - provide, PropType, } from 'vue' import { EVENT_CODE } from '@element-plus/utils/aria' import { t } from '@element-plus/locale' -import mitt from 'mitt' import TimeSpinner from './basic-time-spinner.vue' import dayjs, { Dayjs } from 'dayjs' import { getAvaliableArrs } from './useTimePicker' @@ -59,32 +61,31 @@ export default defineComponent({ props: { visible: { - type: [Boolean], + type: Boolean, default: false, }, + datetimeRole: { + type: String, + }, parsedValue: { - type: Dayjs as PropType, - default: '', + type: [Object, String] as PropType, }, arrowControl: { - type: [Boolean], + type: Boolean, default: false, }, - pickerOptions: { - type: Object, - default: () => ({}), - }, format: { type: String, default: '', }, }, - emits: ['pick', 'select-range'], + emits: ['pick', 'select-range', 'set-picker-option'], setup(props, ctx) { // data const selectionRange = ref([0, 2]) + const oldValue = ref(props.parsedValue) // computed const showSeconds = computed(() => { return props.format.includes('ss') @@ -101,7 +102,7 @@ export default defineComponent({ return parsedDate.isSame(result) } const handleCancel = () => { - ctx.emit('pick', '', false, true) + ctx.emit('pick', oldValue.value, false) } const handleConfirm = (visible = false, first) => { if (first) return @@ -157,11 +158,11 @@ export default defineComponent({ let avaliableArr const method = avaliableMap[_] if (_ === 'minute') { - avaliableArr = method(result.hour()) + avaliableArr = method(result.hour(), props.datetimeRole) } else if (_ === 'second') { - avaliableArr = method(result.hour(), result.minute()) + avaliableArr = method(result.hour(), result.minute(), props.datetimeRole) } else { - avaliableArr = method() + avaliableArr = method(props.datetimeRole) } if (avaliableArr && avaliableArr.length && !avaliableArr.includes(result[_]())) { result = result[_](avaliableArr[0]) @@ -181,31 +182,30 @@ export default defineComponent({ return value.format(props.format) } - const pickerBase = inject('EP_PICKER_BASE') as any - pickerBase.hub.emit('SetPickerOption', ['isValidValue', isValidValue]) - pickerBase.hub.emit('SetPickerOption', ['formatToString', formatToString]) - pickerBase.hub.emit('SetPickerOption', ['parseUserInput', parseUserInput]) - pickerBase.hub.emit('SetPickerOption',['handleKeydown', handleKeydown]) - pickerBase.hub.emit('SetPickerOption',['getRangeAvaliableTime', getRangeAvaliableTime]) - const timePickeOptions = {} as any - const pickerHub = mitt() - pickerHub.on('SetOption', e => { - timePickeOptions[e[0]] = e[1] - }) + const getDefaultValue = () => { + return dayjs(defaultValue) + } - const { disabledHours, disabledMinutes, disabledSeconds } = pickerBase.props + ctx.emit('set-picker-option', ['isValidValue', isValidValue]) + ctx.emit('set-picker-option', ['formatToString', formatToString]) + ctx.emit('set-picker-option', ['parseUserInput', parseUserInput]) + ctx.emit('set-picker-option',['handleKeydown', handleKeydown]) + ctx.emit('set-picker-option',['getRangeAvaliableTime', getRangeAvaliableTime]) + ctx.emit('set-picker-option',['getDefaultValue', getDefaultValue]) + const timePickeOptions = {} as any + const onSetOption = e => { + timePickeOptions[e[0]] = e[1] + } + const pickerBase = inject('EP_PICKER_BASE') as any + const { disabledHours, disabledMinutes, disabledSeconds, defaultValue } = pickerBase.props const { getAvaliableHours, getAvaliableMinutes, getAvaliableSeconds, } = getAvaliableArrs(disabledHours, disabledMinutes, disabledSeconds) - provide('EP_TIMEPICK_PANEL', { - hub: pickerHub, - methods: { - disabledHours, disabledMinutes, disabledSeconds, - }, - }) + return { + onSetOption, t, handleConfirm, handleChange, @@ -213,6 +213,9 @@ export default defineComponent({ amPmMode, showSeconds, handleCancel, + disabledHours, + disabledMinutes, + disabledSeconds, } }, }) diff --git a/packages/time-picker/src/time-picker-com/panel-time-range.vue b/packages/time-picker/src/time-picker-com/panel-time-range.vue index 47a945bbb0..34d960bfc7 100644 --- a/packages/time-picker/src/time-picker-com/panel-time-range.vue +++ b/packages/time-picker/src/time-picker-com/panel-time-range.vue @@ -20,7 +20,11 @@ :am-pm-mode="amPmMode" :arrow-control="arrowControl" :spinner-date="minDate" + :disabled-hours="disabledHours_" + :disabled-minutes="disabledMinutes_" + :disabled-seconds="disabledSeconds_" @change="handleMinChange" + @set-option="onSetOption" @select-range="setMinSelectionRange" /> @@ -38,7 +42,11 @@ :am-pm-mode="amPmMode" :arrow-control="arrowControl" :spinner-date="maxDate" + :disabled-hours="disabledHours_" + :disabled-minutes="disabledMinutes_" + :disabled-seconds="disabledSeconds_" @change="handleMaxChange" + @set-option="onSetOption" @select-range="setMaxSelectionRange" /> @@ -72,10 +80,8 @@ import { computed, PropType, inject, - provide, } from 'vue' import dayjs, { Dayjs } from 'dayjs' -import mitt from 'mitt' import union from 'lodash/union' import { t } from '@element-plus/locale' import { EVENT_CODE } from '@element-plus/utils/aria' @@ -103,8 +109,7 @@ export default defineComponent({ default: false, }, parsedValue: { - type: Array as PropType>, - default: '', + type: [Array, String] as PropType>, }, format: { type: String, @@ -112,13 +117,14 @@ export default defineComponent({ }, }, - emits: ['pick', 'select-range'], + emits: ['pick', 'select-range', 'set-picker-option'], setup(props, ctx) { const minDate = computed(() => props.parsedValue[0]) const maxDate = computed(() => props.parsedValue[1]) + const oldValue = ref(props.parsedValue) const handleCancel = () =>{ - ctx.emit('pick', null, null, true) + ctx.emit('pick', oldValue.value, null) } const showSeconds = computed(() => { return props.format.includes('ss') @@ -290,31 +296,33 @@ export default defineComponent({ return value.format(props.format) } - const pickerBase = inject('EP_PICKER_BASE') as any - pickerBase.hub.emit('SetPickerOption',['formatToString', formatToString]) - pickerBase.hub.emit('SetPickerOption',['parseUserInput', parseUserInput]) - pickerBase.hub.emit('SetPickerOption',['isValidValue', isValidValue]) - pickerBase.hub.emit('SetPickerOption',['handleKeydown', handleKeydown]) - pickerBase.hub.emit('SetPickerOption',['getRangeAvaliableTime', getRangeAvaliableTime]) + const getDefaultValue = () => { + if (Array.isArray(defaultValue)) { + return defaultValue.map(_=> dayjs(_)) + } + return [ + dayjs(defaultValue), + dayjs(defaultValue).add(60,'m'), + ] + } + + ctx.emit('set-picker-option',['formatToString', formatToString]) + ctx.emit('set-picker-option',['parseUserInput', parseUserInput]) + ctx.emit('set-picker-option',['isValidValue', isValidValue]) + ctx.emit('set-picker-option',['handleKeydown', handleKeydown]) + ctx.emit('set-picker-option',['getDefaultValue', getDefaultValue]) + ctx.emit('set-picker-option',['getRangeAvaliableTime', getRangeAvaliableTime]) const timePickeOptions = {} as any - const pickerHub = mitt() - pickerHub.on('SetOption', e => { + const onSetOption = e => { timePickeOptions[e[0]] = e[1] - }) + } - const { disabledHours, disabledMinutes, disabledSeconds } = pickerBase.props - - provide('EP_TIMEPICK_PANEL', { - hub: pickerHub, - methods: { - disabledHours: disabledHours_, - disabledMinutes: disabledMinutes_, - disabledSeconds: disabledSeconds_, - }, - }) + const pickerBase = inject('EP_PICKER_BASE') as any + const { disabledHours, disabledMinutes, disabledSeconds, defaultValue } = pickerBase.props return { + onSetOption, setMaxSelectionRange, setMinSelectionRange, btnConfirmDisabled, @@ -329,6 +337,9 @@ export default defineComponent({ handleMaxChange, minSelectableRange, maxSelectableRange, + disabledHours_, + disabledMinutes_, + disabledSeconds_, } }, }) diff --git a/packages/utils/aria.ts b/packages/utils/aria.ts index 8ceaa3fe74..4fc62e3ce9 100644 --- a/packages/utils/aria.ts +++ b/packages/utils/aria.ts @@ -2,10 +2,10 @@ export const EVENT_CODE = { tab: 'Tab', enter: 'Enter', space: 'Space', - left: 'ArrowLeft', - up: 'ArrowUp', - right: 'ArrowRight', - down: 'ArrowDown', + left: 'ArrowLeft', // 37 + up: 'ArrowUp', // 38 + right: 'ArrowRight', // 39 + down: 'ArrowDown', // 40 esc: 'Escape', delete: 'Delete', backspace: 'Backspace', diff --git a/website/docs/en-US/date-picker.md b/website/docs/en-US/date-picker.md index 128ad46d0f..2440217697 100644 --- a/website/docs/en-US/date-picker.md +++ b/website/docs/en-US/date-picker.md @@ -25,7 +25,9 @@ Basic date picker measured by 'day'. v-model="value2" type="date" placeholder="Pick a day" - :picker-options="pickerOptions"> + :disabled-date="disabledDate" + :shortcuts="shortcuts" + >
@@ -34,31 +36,27 @@ Basic date picker measured by 'day'. export default { data() { return { - pickerOptions: { - disabledDate(time) { - return time.getTime() > Date.now(); - }, - shortcuts: [{ - text: 'Today', - onClick(picker) { - picker.$emit('pick', new Date()); - } - }, { - text: 'Yesterday', - onClick(picker) { - const date = new Date(); - date.setTime(date.getTime() - 3600 * 1000 * 24); - picker.emit('pick', date); - } - }, { - text: 'A week ago', - onClick(picker) { - const date = new Date(); - date.setTime(date.getTime() - 3600 * 1000 * 24 * 7); - picker.emit('pick', date); - } - }] + disabledDate(time) { + return time.getTime() > Date.now() }, + shortcuts: [{ + text: 'Today', + value: new Date(), + }, { + text: 'Yesterday', + value: (() => { + const date = new Date() + date.setTime(date.getTime() - 3600 * 1000 * 24) + return date + })(), + }, { + text: 'A week ago', + value: (() => { + const date = new Date() + date.setTime(date.getTime() - 3600 * 1000 * 24 * 7) + return date + })(), + }], value1: '', value2: '', }; @@ -81,7 +79,7 @@ You can choose week, month, year or multiple dates by extending the standard dat @@ -157,7 +155,8 @@ Picking a date range is supported. range-separator="To" start-placeholder="Start date" end-placeholder="End date" - :picker-options="pickerOptions"> + :shortcuts="shortcuts" + >
@@ -166,33 +165,31 @@ Picking a date range is supported. export default { data() { return { - pickerOptions: { - shortcuts: [{ - text: 'Last week', - onClick(picker) { - const end = new Date(); - const start = new Date(); - start.setTime(start.getTime() - 3600 * 1000 * 24 * 7); - picker.$emit('pick', [start, end]); - } - }, { - text: 'Last month', - onClick(picker) { - const end = new Date(); - const start = new Date(); - start.setTime(start.getTime() - 3600 * 1000 * 24 * 30); - picker.$emit('pick', [start, end]); - } - }, { - text: 'Last 3 months', - onClick(picker) { - const end = new Date(); - const start = new Date(); - start.setTime(start.getTime() - 3600 * 1000 * 24 * 90); - picker.$emit('pick', [start, end]); - } - }] - }, + shortcuts: [{ + text: 'Last week', + value: (() => { + const end = new Date() + const start = new Date() + start.setTime(start.getTime() - 3600 * 1000 * 24 * 7) + return [start, end] + })(), + }, { + text: 'Last month', + value: (() => { + const end = new Date() + const start = new Date() + start.setTime(start.getTime() - 3600 * 1000 * 24 * 30) + return [start, end] + })(), + }, { + text: 'Last 3 months', + value: (() => { + const end = new Date() + const start = new Date() + start.setTime(start.getTime() - 3600 * 1000 * 24 * 90) + return [start, end] + })(), + }], value1: '', value2: '' }; @@ -230,7 +227,8 @@ Picking a month range is supported. range-separator="To" start-placeholder="Start month" end-placeholder="End month" - :picker-options="pickerOptions"> + :shortcuts="shortcuts" + >
@@ -239,29 +237,25 @@ Picking a month range is supported. export default { data() { return { - pickerOptions: { - shortcuts: [{ - text: 'This month', - onClick(picker) { - picker.$emit('pick', [new Date(), new Date()]); - } - }, { - text: 'This year', - onClick(picker) { - const end = new Date(); - const start = new Date(new Date().getFullYear(), 0); - picker.$emit('pick', [start, end]); - } - }, { - text: 'Last 6 months', - onClick(picker) { - const end = new Date(); - const start = new Date(); - start.setMonth(start.getMonth() - 6); - picker.$emit('pick', [start, end]); - } - }] - }, + shortcuts: [{ + text: 'This month', + value: [new Date(), new Date()], + }, { + text: 'This year', + value: (() => { + const end = new Date() + const start = new Date(new Date().getFullYear(), 0) + return [start, end] + })(), + }, { + text: 'Last 6 months', + value: (() => { + const end = new Date() + const start = new Date() + start.setMonth(start.getMonth() - 6) + return [start, end] + })(), + }], value1: '', value2: '' }; @@ -286,7 +280,7 @@ If type is `daterange`, `default-value` sets the left side calendar. v-model="value1" type="date" placeholder="Pick a date" - default-value="2010-10-01"> + :default-value="new Date(2010, 9, 1)">
@@ -297,7 +291,7 @@ If type is `daterange`, `default-value` sets the left side calendar. align="right" start-placeholder="Start Date" end-placeholder="End Date" - default-value="2010-10-01"> + :default-value="[new Date(2010, 9, 1), new Date(2010, 10, 1)]">
@@ -358,29 +352,7 @@ Pay attention to capitalization v-model="value1" type="date" placeholder="Pick a Date" - format="yyyy/MM/dd"> -
- -
- Use value-format -
Value: {{ value2 }}
- - -
-
- Timestamp -
Value:{{ value3 }}
- + format="YYYY/MM/DD">
@@ -413,7 +385,7 @@ When picking a date range, you can assign the time part for start date and end d type="daterange" start-placeholder="Start date" end-placeholder="End date" - :default-time="['00:00:00', '23:59:59']"> + :default-time="[new Date(2000, 1, 1, 0 , 0,0), new Date(2000, 2, 1, 23 , 59,59)]">
diff --git a/website/docs/es/date-picker.md b/website/docs/es/date-picker.md index f9195a0bd3..127e7132ed 100644 --- a/website/docs/es/date-picker.md +++ b/website/docs/es/date-picker.md @@ -26,7 +26,9 @@ Date Picker básico por "día". v-model="value2" type="date" placeholder="Pick a day" - :picker-options="pickerOptions"> + :disabled-date="disabledDate" + :shortcuts="shortcuts" + >
@@ -35,31 +37,27 @@ Date Picker básico por "día". export default { data() { return { - pickerOptions: { - disabledDate(time) { - return time.getTime() > Date.now(); - }, - shortcuts: [{ - text: 'Today', - onClick(picker) { - picker.$emit('pick', new Date()); - } - }, { - text: 'Yesterday', - onClick(picker) { - const date = new Date(); - date.setTime(date.getTime() - 3600 * 1000 * 24); - picker.emit('pick', date); - } - }, { - text: 'A week ago', - onClick(picker) { - const date = new Date(); - date.setTime(date.getTime() - 3600 * 1000 * 24 * 7); - picker.emit('pick', date); - } - }] + disabledDate(time) { + return time.getTime() > Date.now() }, + shortcuts: [{ + text: 'Today', + value: new Date(), + }, { + text: 'Yesterday', + value: (() => { + const date = new Date() + date.setTime(date.getTime() - 3600 * 1000 * 24) + return date + })(), + }, { + text: 'A week ago', + value: (() => { + const date = new Date() + date.setTime(date.getTime() - 3600 * 1000 * 24 * 7) + return date + })(), + }], value1: '', value2: '', }; @@ -83,7 +81,7 @@ Puede elegir la semana, el mes, el año o varias fechas ampliando el componente @@ -159,7 +157,8 @@ Se soporta la selección de un rango de fechas. range-separator="To" start-placeholder="Start date" end-placeholder="End date" - :picker-options="pickerOptions"> + :shortcuts="shortcuts" + >
@@ -168,33 +167,31 @@ Se soporta la selección de un rango de fechas. export default { data() { return { - pickerOptions: { - shortcuts: [{ - text: 'Last week', - onClick(picker) { - const end = new Date(); - const start = new Date(); - start.setTime(start.getTime() - 3600 * 1000 * 24 * 7); - picker.$emit('pick', [start, end]); - } - }, { - text: 'Last month', - onClick(picker) { - const end = new Date(); - const start = new Date(); - start.setTime(start.getTime() - 3600 * 1000 * 24 * 30); - picker.$emit('pick', [start, end]); - } - }, { - text: 'Last 3 months', - onClick(picker) { - const end = new Date(); - const start = new Date(); - start.setTime(start.getTime() - 3600 * 1000 * 24 * 90); - picker.$emit('pick', [start, end]); - } - }] - }, + shortcuts: [{ + text: 'Last week', + value: (() => { + const end = new Date() + const start = new Date() + start.setTime(start.getTime() - 3600 * 1000 * 24 * 7) + return [start, end] + })(), + }, { + text: 'Last month', + value: (() => { + const end = new Date() + const start = new Date() + start.setTime(start.getTime() - 3600 * 1000 * 24 * 30) + return [start, end] + })(), + }, { + text: 'Last 3 months', + value: (() => { + const end = new Date() + const start = new Date() + start.setTime(start.getTime() - 3600 * 1000 * 24 * 90) + return [start, end] + })(), + }], value1: '', value2: '' }; @@ -232,7 +229,8 @@ Se admite la selección de un intervalo de un mes. range-separator="To" start-placeholder="Start month" end-placeholder="End month" - :picker-options="pickerOptions"> + :shortcuts="shortcuts" + >
@@ -241,29 +239,25 @@ Se admite la selección de un intervalo de un mes. export default { data() { return { - pickerOptions: { - shortcuts: [{ - text: 'This month', - onClick(picker) { - picker.$emit('pick', [new Date(), new Date()]); - } - }, { - text: 'This year', - onClick(picker) { - const end = new Date(); - const start = new Date(new Date().getFullYear(), 0); - picker.$emit('pick', [start, end]); - } - }, { - text: 'Last 6 months', - onClick(picker) { - const end = new Date(); - const start = new Date(); - start.setMonth(start.getMonth() - 6); - picker.$emit('pick', [start, end]); - } - }] - }, + shortcuts: [{ + text: 'This month', + value: [new Date(), new Date()], + }, { + text: 'This year', + value: (() => { + const end = new Date() + const start = new Date(new Date().getFullYear(), 0) + return [start, end] + })(), + }, { + text: 'Last 6 months', + value: (() => { + const end = new Date() + const start = new Date() + start.setMonth(start.getMonth() - 6) + return [start, end] + })(), + }], value1: '', value2: '' }; @@ -288,7 +282,7 @@ Si el tipo es `daterange`, `default-value` establece el calendario del lado izqu v-model="value1" type="date" placeholder="Pick a date" - default-value="2010-10-01"> + :default-value="new Date(2010, 9, 1)">
@@ -299,7 +293,7 @@ Si el tipo es `daterange`, `default-value` establece el calendario del lado izqu align="right" start-placeholder="Start Date" end-placeholder="End Date" - default-value="2010-10-01"> + :default-value="[new Date(2010, 9, 1), new Date(2010, 10, 1)]">
@@ -358,29 +352,7 @@ Preste atención a la capitalización v-model="value1" type="date" placeholder="Pick a Date" - format="yyyy/MM/dd"> -
- -
- Use value-format -
Value: {{ value2 }}
- - -
-
- Timestamp -
Value:{{ value3 }}
- + format="YYYY/MM/DD">
@@ -414,7 +386,7 @@ Al seleccionar un intervalo de fechas, puede asignar la hora para la fecha de in type="daterange" start-placeholder="Start date" end-placeholder="End date" - :default-time="['00:00:00', '23:59:59']"> + :default-time="[new Date(2000, 1, 1, 0 , 0,0), new Date(2000, 2, 1, 23 , 59,59)]">
diff --git a/website/docs/fr-FR/date-picker.md b/website/docs/fr-FR/date-picker.md index faf8e6017c..38e68c67cd 100644 --- a/website/docs/fr-FR/date-picker.md +++ b/website/docs/fr-FR/date-picker.md @@ -24,7 +24,9 @@ L'unité de base du DatePicker est le jour. v-model="value2" type="date" placeholder="Choississez un jour" - :picker-options="pickerOptions"> + :disabled-date="disabledDate" + :shortcuts="shortcuts" + >
@@ -33,31 +35,27 @@ L'unité de base du DatePicker est le jour. export default { data() { return { - pickerOptions: { - disabledDate(time) { - return time.getTime() > Date.now(); - }, - shortcuts: [{ - text: 'Aujourd\'hui', - onClick(picker) { - picker.$emit('pick', new Date()); - } - }, { - text: 'Hier', - onClick(picker) { - const date = new Date(); - date.setTime(date.getTime() - 3600 * 1000 * 24); - picker.emit('pick', date); - } - }, { - text: 'Il y a une semaine', - onClick(picker) { - const date = new Date(); - date.setTime(date.getTime() - 3600 * 1000 * 24 * 7); - picker.emit('pick', date); - } - }] + disabledDate(time) { + return time.getTime() > Date.now() }, + shortcuts: [{ + text: 'Today', + value: new Date(), + }, { + text: 'Yesterday', + value: (() => { + const date = new Date() + date.setTime(date.getTime() - 3600 * 1000 * 24) + return date + })(), + }, { + text: 'A week ago', + value: (() => { + const date = new Date() + date.setTime(date.getTime() - 3600 * 1000 * 24 * 7) + return date + })(), + }], value1: '', value2: '', }; @@ -80,7 +78,7 @@ Vous pouvez sélectionner une semaine, un mois, une année ou plusieurs dates en @@ -156,7 +154,8 @@ Vous pouvez sélectionner une plage de dates. range-separator="à" start-placeholder="Date de début" end-placeholder="Date de fin" - :picker-options="pickerOptions"> + :shortcuts="shortcuts" + >
@@ -165,33 +164,31 @@ Vous pouvez sélectionner une plage de dates. export default { data() { return { - pickerOptions: { - shortcuts: [{ - text: 'Semaine dernière', - onClick(picker) { - const end = new Date(); - const start = new Date(); - start.setTime(start.getTime() - 3600 * 1000 * 24 * 7); - picker.$emit('pick', [start, end]); - } - }, { - text: 'Mois dernier', - onClick(picker) { - const end = new Date(); - const start = new Date(); - start.setTime(start.getTime() - 3600 * 1000 * 24 * 30); - picker.$emit('pick', [start, end]); - } - }, { - text: 'Trois derniers mois', - onClick(picker) { - const end = new Date(); - const start = new Date(); - start.setTime(start.getTime() - 3600 * 1000 * 24 * 90); - picker.$emit('pick', [start, end]); - } - }] - }, + shortcuts: [{ + text: 'Last week', + value: (() => { + const end = new Date() + const start = new Date() + start.setTime(start.getTime() - 3600 * 1000 * 24 * 7) + return [start, end] + })(), + }, { + text: 'Last month', + value: (() => { + const end = new Date() + const start = new Date() + start.setTime(start.getTime() - 3600 * 1000 * 24 * 30) + return [start, end] + })(), + }, { + text: 'Last 3 months', + value: (() => { + const end = new Date() + const start = new Date() + start.setTime(start.getTime() - 3600 * 1000 * 24 * 90) + return [start, end] + })(), + }], value1: '', value2: '' }; @@ -229,7 +226,8 @@ Vous pouvez sélectionner une plage de mois. range-separator="à" start-placeholder="Mois de début" end-placeholder="Mois de fin" - :picker-options="pickerOptions"> + :shortcuts="shortcuts" + >
@@ -238,29 +236,25 @@ Vous pouvez sélectionner une plage de mois. export default { data() { return { - pickerOptions: { - shortcuts: [{ - text: 'Ce mois', - onClick(picker) { - picker.$emit('pick', [new Date(), new Date()]); - } - }, { - text: 'Cette année', - onClick(picker) { - const end = new Date(); - const start = new Date(new Date().getFullYear(), 0); - picker.$emit('pick', [start, end]); - } - }, { - text: 'Les derniers 6 mois', - onClick(picker) { - const end = new Date(); - const start = new Date(); - start.setMonth(start.getMonth() - 6); - picker.$emit('pick', [start, end]); - } - }] - }, + shortcuts: [{ + text: 'This month', + value: [new Date(), new Date()], + }, { + text: 'This year', + value: (() => { + const end = new Date() + const start = new Date(new Date().getFullYear(), 0) + return [start, end] + })(), + }, { + text: 'Last 6 months', + value: (() => { + const end = new Date() + const start = new Date() + start.setMonth(start.getMonth() - 6) + return [start, end] + })(), + }], value1: '', value2: '' }; @@ -285,7 +279,7 @@ Si le type est `daterange`, `default-value` configure la panneau de gauche. v-model="value1" type="date" placeholder="Sélectionnez une date" - default-value="2010-10-01"> + :default-value="new Date(2010, 9, 1)">
@@ -296,7 +290,7 @@ Si le type est `daterange`, `default-value` configure la panneau de gauche. align="right" start-placeholder="Date de début" end-placeholder="Date de fin" - default-value="2010-10-01"> + :default-value="[new Date(2010, 9, 1), new Date(2010, 10, 1)]">
@@ -358,29 +352,7 @@ Attention à la capitalisation ! v-model="value1" type="date" placeholder="Sélectionnez une date" - format="yyyy/MM/dd"> -
- -
- Utilise value-format -
Value: {{ value2 }}
- - -
-
- Timestamp -
Value:{{ value3 }}
- + format="YYYY/MM/DD">
@@ -413,7 +385,7 @@ Lorsque vous choisissez une plage de dates, vous pouvez assigner l'horaire de d type="daterange" start-placeholder="Date de début" end-placeholder="Date de fin" - :default-time="['00:00:00', '23:59:59']"> + :default-time="[new Date(2000, 1, 1, 0 , 0,0), new Date(2000, 2, 1, 23 , 59,59)]">
diff --git a/website/docs/zh-CN/date-picker.md b/website/docs/zh-CN/date-picker.md index 8d458e5246..49ce4a9b6e 100644 --- a/website/docs/zh-CN/date-picker.md +++ b/website/docs/zh-CN/date-picker.md @@ -25,7 +25,9 @@ align="right" type="date" placeholder="选择日期" - :picker-options="pickerOptions"> + :disabled-date="disabledDate" + :shortcuts="shortcuts" + >
@@ -34,31 +36,27 @@ export default { data() { return { - pickerOptions: { - disabledDate(time) { - return time.getTime() > Date.now(); - }, - shortcuts: [{ - text: '今天', - onClick(picker) { - picker.$emit('pick', new Date()); - } - }, { - text: '昨天', - onClick(picker) { - const date = new Date(); - date.setTime(date.getTime() - 3600 * 1000 * 24); - picker.emit('pick', date); - } - }, { - text: '一周前', - onClick(picker) { - const date = new Date(); - date.setTime(date.getTime() - 3600 * 1000 * 24 * 7); - picker.emit('pick', date); - } - }] + disabledDate(time) { + return time.getTime() > Date.now() }, + shortcuts: [{ + text: 'Today', + value: new Date(), + }, { + text: 'Yesterday', + value: (() => { + const date = new Date() + date.setTime(date.getTime() - 3600 * 1000 * 24) + return date + })(), + }, { + text: 'A week ago', + value: (() => { + const date = new Date() + date.setTime(date.getTime() - 3600 * 1000 * 24 * 7) + return date + })(), + }], value1: '', value2: '', }; @@ -80,7 +78,7 @@ @@ -154,7 +152,8 @@ range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" - :picker-options="pickerOptions"> + :shortcuts="shortcuts" + >
@@ -163,33 +162,31 @@ export default { data() { return { - pickerOptions: { - shortcuts: [{ - text: '最近一周', - onClick(picker) { - const end = new Date(); - const start = new Date(); - start.setTime(start.getTime() - 3600 * 1000 * 24 * 7); - picker.$emit('pick', [start, end]); - } - }, { - text: '最近一个月', - onClick(picker) { - const end = new Date(); - const start = new Date(); - start.setTime(start.getTime() - 3600 * 1000 * 24 * 30); - picker.$emit('pick', [start, end]); - } - }, { - text: '最近三个月', - onClick(picker) { - const end = new Date(); - const start = new Date(); - start.setTime(start.getTime() - 3600 * 1000 * 24 * 90); - picker.$emit('pick', [start, end]); - } - }] - }, + shortcuts: [{ + text: '最近一周', + value: (() => { + const end = new Date() + const start = new Date() + start.setTime(start.getTime() - 3600 * 1000 * 24 * 7) + return [start, end] + })(), + }, { + text: '最近一个月', + value: (() => { + const end = new Date() + const start = new Date() + start.setTime(start.getTime() - 3600 * 1000 * 24 * 30) + return [start, end] + })(), + }, { + text: '最近三个月', + value: (() => { + const end = new Date() + const start = new Date() + start.setTime(start.getTime() - 3600 * 1000 * 24 * 90) + return [start, end] + })(), + }], value1: '', value2: '' }; @@ -227,7 +224,8 @@ range-separator="至" start-placeholder="开始月份" end-placeholder="结束月份" - :picker-options="pickerOptions"> + :shortcuts="shortcuts" + >
@@ -236,29 +234,25 @@ export default { data() { return { - pickerOptions: { - shortcuts: [{ - text: '本月', - onClick(picker) { - picker.$emit('pick', [new Date(), new Date()]); - } - }, { - text: '今年至今', - onClick(picker) { - const end = new Date(); - const start = new Date(new Date().getFullYear(), 0); - picker.$emit('pick', [start, end]); - } - }, { - text: '最近六个月', - onClick(picker) { - const end = new Date(); - const start = new Date(); - start.setMonth(start.getMonth() - 6); - picker.$emit('pick', [start, end]); - } - }] - }, + shortcuts: [{ + text: '本月', + value: [new Date(), new Date()], + }, { + text: '今年至今', + value: (() => { + const end = new Date() + const start = new Date(new Date().getFullYear(), 0) + return [start, end] + })(), + }, { + text: '最近六个月', + value: (() => { + const end = new Date() + const start = new Date() + start.setMonth(start.getMonth() - 6) + return [start, end] + })(), + }], value1: '', value2: '' }; @@ -268,6 +262,49 @@ ``` ::: +### Default Value (需要翻译) + +If user hasn't picked a date, shows today's calendar by default. You can use `default-value` to set another date. Its value should be parsable by `new Date()`. + +If type is `daterange`, `default-value` sets the left side calendar. + +:::demo +```html + + + +``` +::: ### 日期格式 @@ -311,29 +348,7 @@ v-model="value1" type="date" placeholder="选择日期" - format="yyyy 年 MM 月 dd 日"> -
- -
- 使用 value-format -
值:{{ value2 }}
- - -
-
- 时间戳 -
值:{{ value3 }}
- + format="YYYY 年 MM 月 DD 日">
@@ -366,7 +381,7 @@ type="daterange" start-placeholder="开始日期" end-placeholder="结束日期" - :default-time="['00:00:00', '23:59:59']"> + :default-time="[new Date(2000, 1, 1, 0 , 0,0), new Date(2000, 2, 1, 23 , 59,59)]">
diff --git a/website/play/index.vue b/website/play/index.vue deleted file mode 100644 index 243f8ae15c..0000000000 --- a/website/play/index.vue +++ /dev/null @@ -1,14 +0,0 @@ - - - -