@vaadin/date-picker 23.0.0 → 23.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/date-picker",
3
- "version": "23.0.0",
3
+ "version": "23.0.3",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -34,21 +34,21 @@
34
34
  "dependencies": {
35
35
  "@open-wc/dedupe-mixin": "^1.3.0",
36
36
  "@polymer/polymer": "^3.2.0",
37
- "@vaadin/button": "^23.0.0",
38
- "@vaadin/component-base": "^23.0.0",
39
- "@vaadin/field-base": "^23.0.0",
40
- "@vaadin/input-container": "^23.0.0",
41
- "@vaadin/vaadin-lumo-styles": "^23.0.0",
42
- "@vaadin/vaadin-material-styles": "^23.0.0",
43
- "@vaadin/vaadin-overlay": "^23.0.0",
44
- "@vaadin/vaadin-themable-mixin": "^23.0.0"
37
+ "@vaadin/button": "^23.0.3",
38
+ "@vaadin/component-base": "^23.0.3",
39
+ "@vaadin/field-base": "^23.0.3",
40
+ "@vaadin/input-container": "^23.0.3",
41
+ "@vaadin/vaadin-lumo-styles": "^23.0.3",
42
+ "@vaadin/vaadin-material-styles": "^23.0.3",
43
+ "@vaadin/vaadin-overlay": "^23.0.3",
44
+ "@vaadin/vaadin-themable-mixin": "^23.0.3"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@esm-bundle/chai": "^4.3.4",
48
- "@vaadin/dialog": "^23.0.0",
49
- "@vaadin/polymer-legacy-adapter": "^23.0.0",
48
+ "@vaadin/dialog": "^23.0.3",
49
+ "@vaadin/polymer-legacy-adapter": "^23.0.3",
50
50
  "@vaadin/testing-helpers": "^0.3.2",
51
51
  "sinon": "^9.2.0"
52
52
  },
53
- "gitHead": "e5ce38429a14de1448d732614e359fb32b2c42e0"
53
+ "gitHead": "3f010a4167c9e04405c9dfab098da0821e02a601"
54
54
  }
@@ -83,7 +83,7 @@ class DatePickerLight extends ThemableMixin(DatePickerMixin(PolymerElement)) {
83
83
  i18n="[[i18n]]"
84
84
  fullscreen$="[[_fullscreen]]"
85
85
  label="[[label]]"
86
- selected-date="{{_selectedDate}}"
86
+ selected-date="[[_selectedDate]]"
87
87
  slot="dropdown-content"
88
88
  focused-date="{{_focusedDate}}"
89
89
  show-week-numbers="[[showWeekNumbers]]"
@@ -394,7 +394,7 @@ export const DatePickerMixin = (subclass) =>
394
394
  if (this.autoOpenDisabled) {
395
395
  const parsedDate = this._getParsedDate();
396
396
  if (this._isValidDate(parsedDate)) {
397
- this._selectedDate = parsedDate;
397
+ this._selectDate(parsedDate);
398
398
  }
399
399
  }
400
400
 
@@ -434,6 +434,25 @@ export const DatePickerMixin = (subclass) =>
434
434
  this.opened = false;
435
435
  }
436
436
 
437
+ /**
438
+ * Override Polymer lifecycle callback to dispatch `change` event if needed.
439
+ * This is necessary to ensure `change` is fired after `value-changed`.
440
+ *
441
+ * @param {!Object} currentProps Current accessor values
442
+ * @param {?Object} changedProps Properties changed since the last call
443
+ * @param {?Object} oldProps Previous values for each changed property
444
+ * @protected
445
+ * @override
446
+ */
447
+ _propertiesChanged(currentProps, changedProps, oldProps) {
448
+ super._propertiesChanged(currentProps, changedProps, oldProps);
449
+
450
+ if ('value' in changedProps && this.__dispatchChange) {
451
+ this.dispatchEvent(new CustomEvent('change', { bubbles: true }));
452
+ this.__dispatchChange = false;
453
+ }
454
+ }
455
+
437
456
  /**
438
457
  * Opens the dropdown.
439
458
  */
@@ -462,6 +481,20 @@ export const DatePickerMixin = (subclass) =>
462
481
  this._overlayContent.addEventListener('close', this._close.bind(this));
463
482
  this._overlayContent.addEventListener('focus-input', this._focusAndSelect.bind(this));
464
483
 
484
+ // User confirmed selected date by clicking the calendar.
485
+ this._overlayContent.addEventListener('date-tap', (e) => {
486
+ this.__userConfirmedDate = true;
487
+
488
+ this._selectDate(e.detail.date);
489
+ });
490
+
491
+ // User confirmed selected date by pressing Enter or Today.
492
+ this._overlayContent.addEventListener('date-selected', (e) => {
493
+ this.__userConfirmedDate = true;
494
+
495
+ this._selectDate(e.detail.date);
496
+ });
497
+
465
498
  // Keep focus attribute in focusElement for styling
466
499
  this._overlayContent.addEventListener('focus', () => {
467
500
  this._setFocused(true);
@@ -508,6 +541,24 @@ export const DatePickerMixin = (subclass) =>
508
541
  return inputValid && minMaxValid && inputValidity;
509
542
  }
510
543
 
544
+ /**
545
+ * Select date on user interaction and set the flag
546
+ * to fire change event if necessary.
547
+ *
548
+ * @param {Date} dateToSelect
549
+ * @protected
550
+ */
551
+ _selectDate(dateToSelect) {
552
+ const value = this._formatISO(dateToSelect);
553
+
554
+ // Only set flag if the value will change.
555
+ if (this.value !== value) {
556
+ this.__dispatchChange = true;
557
+ }
558
+
559
+ this._selectedDate = dateToSelect;
560
+ }
561
+
511
562
  /** @private */
512
563
  _close(e) {
513
564
  if (e) {
@@ -609,9 +660,6 @@ export const DatePickerMixin = (subclass) =>
609
660
  if (selectedDate === undefined || formatDate === undefined) {
610
661
  return;
611
662
  }
612
- if (this.__userInputOccurred) {
613
- this.__dispatchChange = true;
614
- }
615
663
  const value = this._formatISO(selectedDate);
616
664
 
617
665
  this.__keepInputValue || this._applyInputValue(selectedDate);
@@ -620,8 +668,6 @@ export const DatePickerMixin = (subclass) =>
620
668
  this.validate();
621
669
  this.value = value;
622
670
  }
623
- this.__userInputOccurred = false;
624
- this.__dispatchChange = false;
625
671
  this._ignoreFocusedDateChange = true;
626
672
  this._focusedDate = selectedDate;
627
673
  this._ignoreFocusedDateChange = false;
@@ -632,7 +678,6 @@ export const DatePickerMixin = (subclass) =>
632
678
  if (focusedDate === undefined || formatDate === undefined) {
633
679
  return;
634
680
  }
635
- this.__userInputOccurred = true;
636
681
  if (!this._ignoreFocusedDateChange && !this._noInput) {
637
682
  this._applyInputValue(focusedDate);
638
683
  }
@@ -665,10 +710,6 @@ export const DatePickerMixin = (subclass) =>
665
710
 
666
711
  /** @private */
667
712
  _valueChanged(value, oldValue) {
668
- if (this.__dispatchChange) {
669
- this.dispatchEvent(new CustomEvent('change', { bubbles: true }));
670
- this.__dispatchChange = false;
671
- }
672
713
  this._handleDateChange('_selectedDate', value, oldValue);
673
714
 
674
715
  this._toggleHasValue(!!value);
@@ -751,14 +792,15 @@ export const DatePickerMixin = (subclass) =>
751
792
  const parsedDate = this._getParsedDate(inputValue);
752
793
 
753
794
  if (this._isValidDate(parsedDate)) {
754
- this._selectedDate = parsedDate;
795
+ this._selectDate(parsedDate);
755
796
  } else {
756
797
  this.__keepInputValue = true;
798
+ this._selectDate(null);
757
799
  this._selectedDate = null;
758
800
  this.__keepInputValue = false;
759
801
  }
760
802
  } else if (this._focusedDate) {
761
- this._selectedDate = this._focusedDate;
803
+ this._selectDate(this._focusedDate);
762
804
  }
763
805
  this._ignoreFocusedDateChange = false;
764
806
  }
@@ -774,7 +816,12 @@ export const DatePickerMixin = (subclass) =>
774
816
  this._touchPrevented = [];
775
817
  }
776
818
 
777
- this._selectParsedOrFocusedDate();
819
+ // No need to select date on close if it was confirmed by the user.
820
+ if (this.__userConfirmedDate) {
821
+ this.__userConfirmedDate = false;
822
+ } else {
823
+ this._selectParsedOrFocusedDate();
824
+ }
778
825
 
779
826
  if (this._nativeInput && this._nativeInput.selectionStart) {
780
827
  this._nativeInput.selectionStart = this._nativeInput.selectionEnd;
@@ -903,7 +950,7 @@ export const DatePickerMixin = (subclass) =>
903
950
  const isValidDate = this._isValidDate(parsedDate);
904
951
  if (this.opened) {
905
952
  if (this._overlayInitialized && this._overlayContent.focusedDate && isValidDate) {
906
- this._selectedDate = this._overlayContent.focusedDate;
953
+ this._selectDate(this._overlayContent.focusedDate);
907
954
  }
908
955
  this.close();
909
956
  } else if (!isValidDate && this.inputElement.value !== '') {
@@ -926,7 +973,7 @@ export const DatePickerMixin = (subclass) =>
926
973
  } else if (this.autoOpenDisabled) {
927
974
  // Do not restore selected date if Esc was pressed after clearing input field
928
975
  if (this.inputElement.value === '') {
929
- this._selectedDate = null;
976
+ this._selectDate(null);
930
977
  }
931
978
  this._applyInputValue(this._selectedDate);
932
979
  } else {
@@ -237,8 +237,7 @@ class DatePickerOverlayContent extends ControllerMixin(ThemableMixin(DirMixin(Po
237
237
  * The value for this element.
238
238
  */
239
239
  selectedDate: {
240
- type: Date,
241
- notify: true
240
+ type: Date
242
241
  },
243
242
 
244
243
  /**
@@ -370,6 +369,17 @@ class DatePickerOverlayContent extends ControllerMixin(ThemableMixin(DirMixin(Po
370
369
  this._scrollToPosition(this._differenceInMonths(date, this._originDate), animate);
371
370
  }
372
371
 
372
+ /**
373
+ * Select a date and fire event indicating user interaction.
374
+ * @protected
375
+ */
376
+ _selectDate(dateToSelect) {
377
+ this.selectedDate = dateToSelect;
378
+ this.dispatchEvent(
379
+ new CustomEvent('date-selected', { detail: { date: dateToSelect }, bubbles: true, composed: true })
380
+ );
381
+ }
382
+
373
383
  _focusedDateChanged(focusedDate) {
374
384
  this.revealDate(focusedDate);
375
385
  }
@@ -460,7 +470,7 @@ class DatePickerOverlayContent extends ControllerMixin(ThemableMixin(DirMixin(Po
460
470
  if (Math.abs(this.$.monthScroller.position - this._differenceInMonths(today, this._originDate)) < 0.001) {
461
471
  // Select today only if the month scroller is positioned approximately
462
472
  // at the beginning of the current month
463
- this.selectedDate = today;
473
+ this._selectDate(today);
464
474
  this._close();
465
475
  } else {
466
476
  this._scrollToCurrentMonth();
@@ -659,7 +669,7 @@ class DatePickerOverlayContent extends ControllerMixin(ThemableMixin(DirMixin(Po
659
669
  }
660
670
 
661
671
  _clear() {
662
- this.selectedDate = '';
672
+ this._selectDate('');
663
673
  }
664
674
 
665
675
  _close() {
@@ -683,10 +693,10 @@ class DatePickerOverlayContent extends ControllerMixin(ThemableMixin(DirMixin(Po
683
693
 
684
694
  __toggleDate(date) {
685
695
  if (dateEquals(date, this.selectedDate)) {
686
- this.selectedDate = '';
696
+ this._clear();
687
697
  this.focusedDate = date;
688
698
  } else {
689
- this.selectedDate = date;
699
+ this._selectDate(date);
690
700
  }
691
701
  }
692
702
 
@@ -711,7 +721,7 @@ class DatePickerOverlayContent extends ControllerMixin(ThemableMixin(DirMixin(Po
711
721
  handled = true;
712
722
  break;
713
723
  case 'Enter':
714
- this.selectedDate = this.focusedDate;
724
+ this._selectDate(this.focusedDate);
715
725
  this._close();
716
726
  handled = true;
717
727
  break;
@@ -171,7 +171,7 @@ class DatePicker extends DatePickerMixin(InputControlMixin(ThemableMixin(Element
171
171
  i18n="[[i18n]]"
172
172
  fullscreen$="[[_fullscreen]]"
173
173
  label="[[label]]"
174
- selected-date="{{_selectedDate}}"
174
+ selected-date="[[_selectedDate]]"
175
175
  slot="dropdown-content"
176
176
  focused-date="{{_focusedDate}}"
177
177
  show-week-numbers="[[showWeekNumbers]]"
@@ -42,19 +42,11 @@ class MonthCalendar extends FocusMixin(ThemableMixin(PolymerElement)) {
42
42
  display: flex;
43
43
  }
44
44
 
45
- [part='week-numbers'] {
46
- display: flex;
47
- flex-direction: column;
48
- justify-content: space-between;
49
- flex-shrink: 0;
50
- }
51
-
52
45
  [part='date'] {
53
46
  outline: none;
54
47
  }
55
48
 
56
49
  [part='week-number'][hidden],
57
- [part='week-numbers'][hidden],
58
50
  [part='weekday'][hidden] {
59
51
  display: none;
60
52
  }
@@ -69,7 +61,7 @@ class MonthCalendar extends FocusMixin(ThemableMixin(PolymerElement)) {
69
61
  }
70
62
 
71
63
  [part='weekday']:empty,
72
- [part='week-numbers'] {
64
+ [part='week-number'] {
73
65
  width: 12.5%;
74
66
  flex-shrink: 0;
75
67
  }
@@ -369,7 +361,9 @@ class MonthCalendar extends FocusMixin(ThemableMixin(PolymerElement)) {
369
361
  _handleTap(e) {
370
362
  if (!this.ignoreTaps && !this._notTapping && e.target.date && !e.target.hasAttribute('disabled')) {
371
363
  this.selectedDate = e.target.date;
372
- this.dispatchEvent(new CustomEvent('date-tap', { bubbles: true, composed: true }));
364
+ this.dispatchEvent(
365
+ new CustomEvent('date-tap', { detail: { date: e.target.date }, bubbles: true, composed: true })
366
+ );
373
367
  }
374
368
  }
375
369
 
@@ -33,7 +33,7 @@ registerStyles(
33
33
 
34
34
  [part='weekdays'],
35
35
  [part='weekday'],
36
- [part='week-numbers'] {
36
+ [part='week-number'] {
37
37
  font-size: var(--lumo-font-size-xxs);
38
38
  line-height: 1;
39
39
  color: var(--lumo-secondary-text-color);
@@ -43,9 +43,8 @@ registerStyles(
43
43
  margin-bottom: var(--lumo-space-s);
44
44
  }
45
45
 
46
- /* TODO should have part="week-number" for the cell in weekdays-container */
47
46
  [part='weekday']:empty,
48
- [part='week-numbers'] {
47
+ [part='week-number'] {
49
48
  width: var(--lumo-size-xs);
50
49
  }
51
50
 
@@ -107,8 +106,7 @@ registerStyles(
107
106
  }
108
107
  }
109
108
 
110
- /* TODO should not rely on the role attribute */
111
- [part='date'][role='button']:not([disabled]):not([selected]):hover::before {
109
+ [part='date']:not(:empty):not([disabled]):not([selected]):hover::before {
112
110
  background-color: var(--lumo-primary-color-10pct);
113
111
  }
114
112
 
@@ -130,7 +128,7 @@ registerStyles(
130
128
  display: none;
131
129
  }
132
130
 
133
- [part='date'][role='button']:not([disabled]):active::before {
131
+ [part='date']:not(:empty):not([disabled]):active::before {
134
132
  display: block;
135
133
  }
136
134