Skip to content

Commit 42b56bb

Browse files
feat(VDatePicker): activePicker prop (#12754)
resolves #11576
1 parent 13ab192 commit 42b56bb

File tree

7 files changed

+88
-66
lines changed

7 files changed

+88
-66
lines changed

packages/api-generator/src/locale/en/v-date-picker.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"props": {
3+
"activePicker": "Determines which picker in the date or month picker is being displayed. Allowed values: `'DATE'`, `'MONTH'`, `'YEAR'`",
34
"allowedDates": "Restricts which dates can be selected",
45
"disabled": "Disables interaction with the picker",
56
"dayFormat": "Allows you to customize the format of the day string that appears in the date table. Called with date (ISO 8601 **date** string) arguments.",
@@ -37,6 +38,7 @@
3738
"default": "Displayed below the calendar, can be used for example for adding action button (`OK` and `Cancel`)"
3839
},
3940
"events": {
41+
"update:active-picker": "The `.sync` event for `active-picker` prop",
4042
"update:picker-date": "The `.sync` event for `picker-date` prop",
4143
"<domevent>:date": "Emitted when the specified DOM event occurs on the date button",
4244
"<domevent>:month": "Emitted when the specified DOM event occurs on the month button",

packages/api-generator/src/maps/v-date-picker.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ module.exports = {
1919
name: 'update:picker-date',
2020
value: 'string',
2121
},
22+
{
23+
name: 'update:active-picker',
24+
value: 'string',
25+
},
2226
{
2327
name: '<domevent>:date',
2428
value: 'string',

packages/docs/src/examples/v-date-picker/misc-birthday.vue

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,45 @@
11
<template>
2-
<v-menu
3-
ref="menu"
4-
v-model="menu"
5-
:close-on-content-click="false"
6-
transition="scale-transition"
7-
offset-y
8-
min-width="auto"
9-
>
10-
<template v-slot:activator="{ on, attrs }">
11-
<v-text-field
2+
<div>
3+
<div class="mb-6">Active picker: <code>{{ activePicker || 'null' }}</code></div>
4+
<v-menu
5+
ref="menu"
6+
v-model="menu"
7+
:close-on-content-click="false"
8+
transition="scale-transition"
9+
offset-y
10+
min-width="auto"
11+
>
12+
<template v-slot:activator="{ on, attrs }">
13+
<v-text-field
14+
v-model="date"
15+
label="Birthday date"
16+
prepend-icon="mdi-calendar"
17+
readonly
18+
v-bind="attrs"
19+
v-on="on"
20+
></v-text-field>
21+
</template>
22+
<v-date-picker
1223
v-model="date"
13-
label="Birthday date"
14-
prepend-icon="mdi-calendar"
15-
readonly
16-
v-bind="attrs"
17-
v-on="on"
18-
></v-text-field>
19-
</template>
20-
<v-date-picker
21-
ref="picker"
22-
v-model="date"
23-
:max="new Date().toISOString().substr(0, 10)"
24-
min="1950-01-01"
25-
@change="save"
26-
></v-date-picker>
27-
</v-menu>
24+
:active-picker.sync="activePicker"
25+
:max="new Date().toISOString().substr(0, 10)"
26+
min="1950-01-01"
27+
@change="save"
28+
></v-date-picker>
29+
</v-menu>
30+
</div>
2831
</template>
2932

3033
<script>
3134
export default {
3235
data: () => ({
36+
activePicker: null,
3337
date: null,
3438
menu: false,
3539
}),
3640
watch: {
3741
menu (val) {
38-
val && setTimeout(() => (this.$refs.picker.activePicker = 'YEAR'))
42+
val && setTimeout(() => (this.activePicker = 'YEAR'))
3943
},
4044
},
4145
methods: {

packages/docs/src/pages/en/components/date-pickers.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,9 @@ You can specify events using arrays, objects or functions. To change the default
119119

120120
### Misc
121121

122-
#### Birthday picker
122+
#### Active picker
123123

124-
Starting with year picker by default, restricting dates range and closing the picker menu after selecting the day make the perfect birthday picker.
124+
You can create a birthday picker - starting with year picker by default, restricting dates range and closing the picker menu after selecting the day make the perfect birthday picker.
125125

126126
<example file="v-date-picker/misc-birthday" />
127127

packages/vuetify/src/components/VDatePicker/VDatePicker.ts

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ interface Formatters {
4343
titleDate: DatePickerFormatter | DatePickerMultipleFormatter
4444
}
4545

46+
type ActivePicker = 'DATE' | 'MONTH' | 'YEAR';
47+
4648
export default mixins(
4749
Localable,
4850
Picker,
@@ -51,6 +53,7 @@ export default mixins(
5153
name: 'v-date-picker',
5254

5355
props: {
56+
activePicker: String as PropType<ActivePicker>,
5457
allowedDates: Function as PropType<DatePickerAllowedDatesFunction | undefined>,
5558
// Function formatting the day in date picker table
5659
dayFormat: Function as PropType<DatePickerAllowedDatesFunction | undefined>,
@@ -134,7 +137,7 @@ export default mixins(
134137
data () {
135138
const now = new Date()
136139
return {
137-
activePicker: this.type.toUpperCase(),
140+
internalActivePicker: this.type.toUpperCase(),
138141
inputDay: null as number | null,
139142
inputMonth: null as number | null,
140143
inputYear: null as number | null,
@@ -244,6 +247,15 @@ export default mixins(
244247
},
245248

246249
watch: {
250+
internalActivePicker: {
251+
immediate: true,
252+
handler (val: ActivePicker) {
253+
this.$emit('update:active-picker', val)
254+
},
255+
},
256+
activePicker (val: ActivePicker) {
257+
this.internalActivePicker = val
258+
},
247259
tableDate (val: string, prev: string) {
248260
// Make a ISO 8601 strings from val and prev for comparision, otherwise it will incorrectly
249261
// compare for example '2000-9' and '2000-10'
@@ -272,7 +284,7 @@ export default mixins(
272284
}
273285
},
274286
type (type: DatePickerType) {
275-
this.activePicker = type.toUpperCase()
287+
this.internalActivePicker = type.toUpperCase()
276288

277289
if (this.value && this.value.length) {
278290
const output = this.multipleValue
@@ -334,7 +346,7 @@ export default mixins(
334346
} else {
335347
this.tableDate = `${value}-${pad((this.tableMonth || 0) + 1)}`
336348
}
337-
this.activePicker = 'MONTH'
349+
this.internalActivePicker = 'MONTH'
338350
if (this.reactive && !this.readonly && !this.isMultiple && this.isDateAllowed(this.inputDate)) {
339351
this.$emit('input', this.inputDate)
340352
}
@@ -348,7 +360,7 @@ export default mixins(
348360
}
349361

350362
this.tableDate = value
351-
this.activePicker = 'DATE'
363+
this.internalActivePicker = 'DATE'
352364
if (this.reactive && !this.readonly && !this.isMultiple && this.isDateAllowed(this.inputDate)) {
353365
this.$emit('input', this.inputDate)
354366
}
@@ -368,14 +380,14 @@ export default mixins(
368380
date: this.value ? (this.formatters.titleDate as (value: any) => string)(this.isMultiple ? this.multipleValue : this.value) : '',
369381
disabled: this.disabled,
370382
readonly: this.readonly,
371-
selectingYear: this.activePicker === 'YEAR',
383+
selectingYear: this.internalActivePicker === 'YEAR',
372384
year: this.formatters.year(this.multipleValue.length ? `${this.inputYear}` : this.tableDate),
373385
yearIcon: this.yearIcon,
374386
value: this.multipleValue[0],
375387
},
376388
slot: 'title',
377389
on: {
378-
'update:selecting-year': (value: boolean) => this.activePicker = value ? 'YEAR' : this.type.toUpperCase(),
390+
'update:selecting-year': (value: boolean) => this.internalActivePicker = value ? 'YEAR' : this.type.toUpperCase(),
379391
},
380392
})
381393
},
@@ -389,16 +401,16 @@ export default mixins(
389401
format: this.headerDateFormat,
390402
light: this.light,
391403
locale: this.locale,
392-
min: this.activePicker === 'DATE' ? this.minMonth : this.minYear,
393-
max: this.activePicker === 'DATE' ? this.maxMonth : this.maxYear,
394-
nextAriaLabel: this.activePicker === 'DATE' ? this.nextMonthAriaLabel : this.nextYearAriaLabel,
395-
prevAriaLabel: this.activePicker === 'DATE' ? this.prevMonthAriaLabel : this.prevYearAriaLabel,
404+
min: this.internalActivePicker === 'DATE' ? this.minMonth : this.minYear,
405+
max: this.internalActivePicker === 'DATE' ? this.maxMonth : this.maxYear,
406+
nextAriaLabel: this.internalActivePicker === 'DATE' ? this.nextMonthAriaLabel : this.nextYearAriaLabel,
407+
prevAriaLabel: this.internalActivePicker === 'DATE' ? this.prevMonthAriaLabel : this.prevYearAriaLabel,
396408
prevIcon: this.prevIcon,
397409
readonly: this.readonly,
398-
value: this.activePicker === 'DATE' ? `${pad(this.tableYear, 4)}-${pad(this.tableMonth + 1)}` : `${pad(this.tableYear, 4)}`,
410+
value: this.internalActivePicker === 'DATE' ? `${pad(this.tableYear, 4)}-${pad(this.tableMonth + 1)}` : `${pad(this.tableYear, 4)}`,
399411
},
400412
on: {
401-
toggle: () => this.activePicker = (this.activePicker === 'DATE' ? 'MONTH' : 'YEAR'),
413+
toggle: () => this.internalActivePicker = (this.internalActivePicker === 'DATE' ? 'MONTH' : 'YEAR'),
402414
input: (value: string) => this.tableDate = value,
403415
},
404416
})
@@ -483,15 +495,15 @@ export default mixins(
483495
})
484496
},
485497
genPickerBody (): VNode {
486-
const children = this.activePicker === 'YEAR' ? [
498+
const children = this.internalActivePicker === 'YEAR' ? [
487499
this.genYears(),
488500
] : [
489501
this.genTableHeader(),
490-
this.activePicker === 'DATE' ? this.genDateTable() : this.genMonthTable(),
502+
this.internalActivePicker === 'DATE' ? this.genDateTable() : this.genMonthTable(),
491503
]
492504

493505
return this.$createElement('div', {
494-
key: this.activePicker,
506+
key: this.internalActivePicker,
495507
}, children)
496508
},
497509
setInputDate () {

packages/vuetify/src/components/VDatePicker/__tests__/VDatePicker.date.spec.ts

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ describe('VDatePicker.ts', () => { // eslint-disable-line max-statements
153153
allowedDates: () => false,
154154
},
155155
data: () => ({
156-
activePicker: 'MONTH',
156+
internalActivePicker: 'MONTH',
157157
}),
158158
})
159159

@@ -169,7 +169,7 @@ describe('VDatePicker.ts', () => { // eslint-disable-line max-statements
169169
reactive: true,
170170
},
171171
data: () => ({
172-
activePicker: 'YEAR',
172+
internalActivePicker: 'YEAR',
173173
}),
174174
})
175175

@@ -192,7 +192,7 @@ describe('VDatePicker.ts', () => { // eslint-disable-line max-statements
192192
allowedDates: () => false,
193193
},
194194
data: () => ({
195-
activePicker: 'YEAR',
195+
internalActivePicker: 'YEAR',
196196
}),
197197
})
198198

@@ -407,7 +407,7 @@ describe('VDatePicker.ts', () => { // eslint-disable-line max-statements
407407
const button = wrapper.findAll('.v-date-picker-header__value button').at(0)
408408

409409
button.trigger('click')
410-
expect(wrapper.vm.activePicker).toBe('MONTH')
410+
expect(wrapper.vm.internalActivePicker).toBe('MONTH')
411411
})
412412

413413
it('should match snapshot with slot', async () => {
@@ -426,29 +426,29 @@ describe('VDatePicker.ts', () => { // eslint-disable-line max-statements
426426
it('should match years snapshot', async () => {
427427
const wrapper = mountFunction({
428428
data: () => ({
429-
activePicker: 'YEAR',
429+
internalActivePicker: 'YEAR',
430430
}),
431431
propsData: {
432432
type: 'date',
433433
value: '2005-11-01',
434434
},
435435
})
436436

437-
expect(wrapper.vm.activePicker).toBe('YEAR')
437+
expect(wrapper.vm.internalActivePicker).toBe('YEAR')
438438

439439
wrapper.findAll('.v-date-picker-title__date').at(0).trigger('click')
440440
await wrapper.vm.$nextTick()
441-
expect(wrapper.vm.activePicker).toBe('DATE')
441+
expect(wrapper.vm.internalActivePicker).toBe('DATE')
442442

443443
wrapper.findAll('.v-date-picker-title__year').at(0).trigger('click')
444444
await wrapper.vm.$nextTick()
445-
expect(wrapper.vm.activePicker).toBe('YEAR')
445+
expect(wrapper.vm.internalActivePicker).toBe('YEAR')
446446
})
447447

448448
it('should select year', async () => {
449449
const wrapper = mountFunction({
450450
data: () => ({
451-
activePicker: 'YEAR',
451+
internalActivePicker: 'YEAR',
452452
}),
453453
propsData: {
454454
type: 'date',
@@ -457,7 +457,7 @@ describe('VDatePicker.ts', () => { // eslint-disable-line max-statements
457457
})
458458

459459
wrapper.findAll('.v-date-picker-years li.active + li').at(0).trigger('click')
460-
expect(wrapper.vm.activePicker).toBe('MONTH')
460+
expect(wrapper.vm.internalActivePicker).toBe('MONTH')
461461
expect(wrapper.vm.tableDate).toBe('2004-11')
462462
})
463463

@@ -483,17 +483,17 @@ describe('VDatePicker.ts', () => { // eslint-disable-line max-statements
483483
wrapper.vm.$on('input', value => wrapper.setProps({ value }))
484484

485485
wrapper.setProps({ type: 'month' })
486-
expect(wrapper.vm.activePicker).toBe('MONTH')
486+
expect(wrapper.vm.internalActivePicker).toBe('MONTH')
487487
expect(wrapper.vm.value).toBe('1999-12')
488488
// TODO: uncomment when type: 'year' is implemented
489489
// wrapper.setProps({ type: 'year' })
490-
// expect(wrapper.vm.activePicker).toBe('YEAR')
490+
// expect(wrapper.vm.internalActivePicker).toBe('YEAR')
491491
// expect(wrapper.vm.inputDate).toBe('1999')
492492
// wrapper.setProps({ type: 'month' })
493-
// expect(wrapper.vm.activePicker).toBe('MONTH')
493+
// expect(wrapper.vm.internalActivePicker).toBe('MONTH')
494494
// expect(wrapper.vm.inputDate).toBe('1999-01')
495495
wrapper.setProps({ type: 'date' })
496-
expect(wrapper.vm.activePicker).toBe('DATE')
496+
expect(wrapper.vm.internalActivePicker).toBe('DATE')
497497
expect(wrapper.vm.value).toBe('1999-12-01')
498498
})
499499

@@ -578,12 +578,12 @@ describe('VDatePicker.ts', () => { // eslint-disable-line max-statements
578578

579579
expect(wrapper.html()).toMatchSnapshot()
580580
wrapper.setData({
581-
activePicker: 'MONTH',
581+
internalActivePicker: 'MONTH',
582582
})
583583
await wrapper.vm.$nextTick()
584584
expect(wrapper.html()).toMatchSnapshot()
585585
wrapper.setData({
586-
activePicker: 'YEAR',
586+
internalActivePicker: 'YEAR',
587587
})
588588
await wrapper.vm.$nextTick()
589589
expect(wrapper.html()).toMatchSnapshot()
@@ -610,7 +610,7 @@ describe('VDatePicker.ts', () => { // eslint-disable-line max-statements
610610
reactive: true,
611611
},
612612
data: () => ({
613-
activePicker: 'MONTH',
613+
internalActivePicker: 'MONTH',
614614
}),
615615
})
616616

@@ -632,7 +632,7 @@ describe('VDatePicker.ts', () => { // eslint-disable-line max-statements
632632
value: '2013-02-07',
633633
},
634634
data: () => ({
635-
activePicker: 'MONTH',
635+
internalActivePicker: 'MONTH',
636636
}),
637637
})
638638

0 commit comments

Comments
 (0)