@vaadin/date-picker 23.2.0-dev.53560527d → 23.2.0

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.
@@ -30,7 +30,6 @@ class DatePickerOverlayContent extends ControllerMixin(ThemableMixin(DirMixin(Po
30
30
  height: 100%;
31
31
  width: 100%;
32
32
  outline: none;
33
- background: #fff;
34
33
  }
35
34
 
36
35
  [part='overlay-header'] {
@@ -48,22 +47,14 @@ class DatePickerOverlayContent extends ControllerMixin(ThemableMixin(DirMixin(Po
48
47
  flex-grow: 1;
49
48
  }
50
49
 
51
- [part='clear-button']:not([showclear]) {
52
- display: none;
50
+ [hidden] {
51
+ display: none !important;
53
52
  }
54
53
 
55
54
  [part='years-toggle-button'] {
56
55
  display: flex;
57
56
  }
58
57
 
59
- [part='years-toggle-button'][desktop] {
60
- display: none;
61
- }
62
-
63
- :host(:not([years-visible])) [part='years-toggle-button']::before {
64
- transform: rotate(180deg);
65
- }
66
-
67
58
  #scrollers {
68
59
  display: flex;
69
60
  height: 100%;
@@ -137,27 +128,14 @@ class DatePickerOverlayContent extends ControllerMixin(ThemableMixin(DirMixin(Po
137
128
  z-index: 2;
138
129
  flex-shrink: 0;
139
130
  }
140
-
141
- [part~='overlay-header']:not([desktop]) {
142
- padding-bottom: 40px;
143
- }
144
-
145
- [part~='years-toggle-button'] {
146
- position: absolute;
147
- top: auto;
148
- right: 8px;
149
- bottom: 0;
150
- z-index: 1;
151
- padding: 8px;
152
- }
153
131
  </style>
154
132
 
155
133
  <div part="overlay-header" on-touchend="_preventDefault" desktop$="[[_desktopMode]]" aria-hidden="true">
156
134
  <div part="label">[[_formatDisplayed(selectedDate, i18n.formatDate, label)]]</div>
157
- <div part="clear-button" showclear$="[[_showClear(selectedDate)]]"></div>
135
+ <div part="clear-button" hidden$="[[!selectedDate]]"></div>
158
136
  <div part="toggle-button"></div>
159
137
 
160
- <div part="years-toggle-button" desktop$="[[_desktopMode]]" aria-hidden="true">
138
+ <div part="years-toggle-button" hidden$="[[_desktopMode]]" aria-hidden="true">
161
139
  [[_yearAfterXMonths(_visibleMonthIndex)]]
162
140
  </div>
163
141
  </div>
@@ -243,6 +221,7 @@ class DatePickerOverlayContent extends ControllerMixin(ThemableMixin(DirMixin(Po
243
221
  */
244
222
  selectedDate: {
245
223
  type: Date,
224
+ value: null,
246
225
  },
247
226
 
248
227
  /**
@@ -318,10 +297,12 @@ class DatePickerOverlayContent extends ControllerMixin(ThemableMixin(DirMixin(Po
318
297
  return this.getAttribute('dir') === 'rtl';
319
298
  }
320
299
 
300
+ get calendars() {
301
+ return [...this.shadowRoot.querySelectorAll('vaadin-month-calendar')];
302
+ }
303
+
321
304
  get focusableDateElement() {
322
- return [...this.shadowRoot.querySelectorAll('vaadin-month-calendar')]
323
- .map((calendar) => calendar.focusableDateElement)
324
- .find(Boolean);
305
+ return this.calendars.map((calendar) => calendar.focusableDateElement).find(Boolean);
325
306
  }
326
307
 
327
308
  ready() {
@@ -329,7 +310,6 @@ class DatePickerOverlayContent extends ControllerMixin(ThemableMixin(DirMixin(Po
329
310
 
330
311
  this.setAttribute('role', 'dialog');
331
312
 
332
- addListener(this, 'tap', this._stopPropagation);
333
313
  addListener(this.$.scrollers, 'track', this._track.bind(this));
334
314
  addListener(this.shadowRoot.querySelector('[part="clear-button"]'), 'tap', this._clear.bind(this));
335
315
  addListener(this.shadowRoot.querySelector('[part="today-button"]'), 'tap', this._onTodayTap.bind(this));
@@ -451,7 +431,9 @@ class DatePickerOverlayContent extends ControllerMixin(ThemableMixin(DirMixin(Po
451
431
 
452
432
  _onYearScrollTouchStart() {
453
433
  this._notTapping = false;
454
- setTimeout(() => (this._notTapping = true), 300);
434
+ setTimeout(() => {
435
+ this._notTapping = true;
436
+ }, 300);
455
437
 
456
438
  this._repositionMonthScroller();
457
439
  }
@@ -462,7 +444,9 @@ class DatePickerOverlayContent extends ControllerMixin(ThemableMixin(DirMixin(Po
462
444
 
463
445
  _doIgnoreTaps() {
464
446
  this._ignoreTaps = true;
465
- this._debouncer = Debouncer.debounce(this._debouncer, timeOut.after(300), () => (this._ignoreTaps = false));
447
+ this._debouncer = Debouncer.debounce(this._debouncer, timeOut.after(300), () => {
448
+ this._ignoreTaps = false;
449
+ });
466
450
  }
467
451
 
468
452
  _formatDisplayed(date, formatDate, label) {
@@ -493,10 +477,6 @@ class DatePickerOverlayContent extends ControllerMixin(ThemableMixin(DirMixin(Po
493
477
  this.scrollToDate(new Date(), true);
494
478
  }
495
479
 
496
- _showClear(selectedDate) {
497
- return !!selectedDate;
498
- }
499
-
500
480
  _onYearTap(e) {
501
481
  if (!this._ignoreTaps && !this._notTapping) {
502
482
  const scrollDelta =
@@ -522,6 +502,11 @@ class DatePickerOverlayContent extends ControllerMixin(ThemableMixin(DirMixin(Po
522
502
 
523
503
  this._targetPosition = targetPosition;
524
504
 
505
+ let revealResolve;
506
+ this._revealPromise = new Promise((resolve) => {
507
+ revealResolve = resolve;
508
+ });
509
+
525
510
  // http://gizma.com/easing/
526
511
  const easingFunction = (t, b, c, d) => {
527
512
  t /= d / 2;
@@ -562,7 +547,9 @@ class DatePickerOverlayContent extends ControllerMixin(ThemableMixin(DirMixin(Po
562
547
 
563
548
  this.$.monthScroller.position = this._targetPosition;
564
549
  this._targetPosition = undefined;
565
- this.__tryFocusDate();
550
+
551
+ revealResolve();
552
+ this._revealPromise = undefined;
566
553
  }
567
554
 
568
555
  setTimeout(this._repositionYearScroller.bind(this), 1);
@@ -776,23 +763,32 @@ class DatePickerOverlayContent extends ControllerMixin(ThemableMixin(DirMixin(Po
776
763
  switch (section) {
777
764
  case 'calendar':
778
765
  if (event.shiftKey) {
779
- // Return focus back to the input field.
780
766
  event.preventDefault();
781
- this.__focusInput();
767
+
768
+ if (this.hasAttribute('fullscreen')) {
769
+ // Trap focus in the overlay
770
+ this.$.cancelButton.focus();
771
+ } else {
772
+ this.__focusInput();
773
+ }
782
774
  }
783
775
  break;
784
776
  case 'today':
785
777
  if (event.shiftKey) {
786
- // Browser returns focus back to the calendar.
787
- // We need to move the scroll to focused date.
788
- setTimeout(() => this.revealDate(this.focusedDate), 1);
778
+ event.preventDefault();
779
+ this.focusDateElement();
789
780
  }
790
781
  break;
791
782
  case 'cancel':
792
783
  if (!event.shiftKey) {
793
- // Return focus back to the input field.
794
784
  event.preventDefault();
795
- this.__focusInput();
785
+
786
+ if (this.hasAttribute('fullscreen')) {
787
+ // Trap focus in the overlay
788
+ this.focusDateElement();
789
+ } else {
790
+ this.__focusInput();
791
+ }
796
792
  }
797
793
  break;
798
794
  default:
@@ -801,28 +797,12 @@ class DatePickerOverlayContent extends ControllerMixin(ThemableMixin(DirMixin(Po
801
797
  }
802
798
 
803
799
  __onTodayButtonKeyDown(event) {
804
- if (this.hasAttribute('fullscreen')) {
805
- // Do not prevent closing on Esc
806
- if (event.key !== 'Escape') {
807
- event.stopPropagation();
808
- }
809
- return;
810
- }
811
-
812
800
  if (event.key === 'Tab') {
813
801
  this._onTabKeyDown(event, 'today');
814
802
  }
815
803
  }
816
804
 
817
805
  __onCancelButtonKeyDown(event) {
818
- if (this.hasAttribute('fullscreen')) {
819
- // Do not prevent closing on Esc
820
- if (event.key !== 'Escape') {
821
- event.stopPropagation();
822
- }
823
- return;
824
- }
825
-
826
806
  if (event.key === 'Tab') {
827
807
  this._onTabKeyDown(event, 'cancel');
828
808
  }
@@ -851,15 +831,29 @@ class DatePickerOverlayContent extends ControllerMixin(ThemableMixin(DirMixin(Po
851
831
  if (!keepMonth) {
852
832
  this._focusedMonthDate = dateToFocus.getDate();
853
833
  }
854
- await this.focusDateElement();
834
+ await this.focusDateElement(false);
855
835
  }
856
836
 
857
- async focusDateElement() {
837
+ async focusDateElement(reveal = true) {
858
838
  this.__pendingDateFocus = this.focusedDate;
859
839
 
860
- await new Promise((resolve) => {
861
- requestAnimationFrame(resolve);
862
- });
840
+ // Wait for `vaadin-month-calendar` elements to be rendered
841
+ if (!this.calendars.length) {
842
+ await new Promise((resolve) => {
843
+ setTimeout(resolve);
844
+ });
845
+ }
846
+
847
+ // Reveal focused date unless it has been just set,
848
+ // which triggers `revealDate()` in the observer.
849
+ if (reveal) {
850
+ this.revealDate(this.focusedDate);
851
+ }
852
+
853
+ if (this._revealPromise) {
854
+ // Wait for focused date to be scrolled into view.
855
+ await this._revealPromise;
856
+ }
863
857
 
864
858
  this.__tryFocusDate();
865
859
  }
@@ -957,10 +951,6 @@ class DatePickerOverlayContent extends ControllerMixin(ThemableMixin(DirMixin(Po
957
951
  todayMidnight.setDate(today.getDate());
958
952
  return this._dateAllowed(todayMidnight, min, max);
959
953
  }
960
-
961
- _stopPropagation(e) {
962
- e.stopPropagation();
963
- }
964
954
  }
965
955
 
966
956
  customElements.define(DatePickerOverlayContent.is, DatePickerOverlayContent);
@@ -31,12 +31,19 @@ export type DatePickerInvalidChangedEvent = CustomEvent<{ value: boolean }>;
31
31
  */
32
32
  export type DatePickerValueChangedEvent = CustomEvent<{ value: string }>;
33
33
 
34
+ /**
35
+ * Fired whenever the field is validated.
36
+ */
37
+ export type DatePickerValidatedEvent = CustomEvent<{ valid: boolean }>;
38
+
34
39
  export interface DatePickerCustomEventMap {
35
40
  'opened-changed': DatePickerOpenedChangedEvent;
36
41
 
37
42
  'invalid-changed': DatePickerInvalidChangedEvent;
38
43
 
39
44
  'value-changed': DatePickerValueChangedEvent;
45
+
46
+ validated: DatePickerValidatedEvent;
40
47
  }
41
48
 
42
49
  export interface DatePickerEventMap extends HTMLElementEventMap, DatePickerCustomEventMap {
@@ -127,24 +134,25 @@ export interface DatePickerEventMap extends HTMLElementEventMap, DatePickerCusto
127
134
  * Note: the `theme` attribute value set on `<vaadin-date-picker>` is
128
135
  * propagated to the internal components listed above.
129
136
  *
130
- * See [Styling Components](https://vaadin.com/docs/latest/ds/customization/styling-components) documentation.
137
+ * See [Styling Components](https://vaadin.com/docs/latest/styling/custom-theme/styling-components) documentation.
131
138
  *
132
139
  * @fires {Event} change - Fired when the user commits a value change.
133
140
  * @fires {CustomEvent} invalid-changed - Fired when the `invalid` property changes.
134
141
  * @fires {CustomEvent} opened-changed - Fired when the `opened` property changes.
135
142
  * @fires {CustomEvent} value-changed - Fired when the `value` property changes.
143
+ * @fires {CustomEvent} validated - Fired whenever the field is validated.
136
144
  */
137
145
  declare class DatePicker extends DatePickerMixin(InputControlMixin(ThemableMixin(ElementMixin(HTMLElement)))) {
138
146
  addEventListener<K extends keyof DatePickerEventMap>(
139
147
  type: K,
140
148
  listener: (this: DatePicker, ev: DatePickerEventMap[K]) => void,
141
- options?: boolean | AddEventListenerOptions,
149
+ options?: AddEventListenerOptions | boolean,
142
150
  ): void;
143
151
 
144
152
  removeEventListener<K extends keyof DatePickerEventMap>(
145
153
  type: K,
146
154
  listener: (this: DatePicker, ev: DatePickerEventMap[K]) => void,
147
- options?: boolean | EventListenerOptions,
155
+ options?: EventListenerOptions | boolean,
148
156
  ): void;
149
157
  }
150
158
 
@@ -102,12 +102,13 @@ registerStyles('vaadin-date-picker', [inputFieldShared, datePickerStyles], { mod
102
102
  * Note: the `theme` attribute value set on `<vaadin-date-picker>` is
103
103
  * propagated to the internal components listed above.
104
104
  *
105
- * See [Styling Components](https://vaadin.com/docs/latest/ds/customization/styling-components) documentation.
105
+ * See [Styling Components](https://vaadin.com/docs/latest/styling/custom-theme/styling-components) documentation.
106
106
  *
107
107
  * @fires {Event} change - Fired when the user commits a value change.
108
108
  * @fires {CustomEvent} invalid-changed - Fired when the `invalid` property changes.
109
109
  * @fires {CustomEvent} opened-changed - Fired when the `opened` property changes.
110
110
  * @fires {CustomEvent} value-changed - Fired when the `value` property changes.
111
+ * @fires {CustomEvent} validated - Fired whenever the field is validated.
111
112
  *
112
113
  * @extends HTMLElement
113
114
  * @mixes ElementMixin
@@ -161,7 +162,7 @@ class DatePicker extends DatePickerMixin(InputControlMixin(ThemableMixin(Element
161
162
  fullscreen$="[[_fullscreen]]"
162
163
  theme$="[[__getOverlayTheme(_theme, _overlayInitialized)]]"
163
164
  on-vaadin-overlay-open="_onOverlayOpened"
164
- on-vaadin-overlay-close="_onOverlayClosed"
165
+ on-vaadin-overlay-closing="_onOverlayClosed"
165
166
  restore-focus-on-close
166
167
  restore-focus-node="[[inputElement]]"
167
168
  disable-upgrade
@@ -221,11 +222,6 @@ class DatePicker extends DatePickerMixin(InputControlMixin(ThemableMixin(Element
221
222
 
222
223
  /** @private */
223
224
  _onVaadinOverlayClose(e) {
224
- if (this._openedWithFocusRing && this.hasAttribute('focused')) {
225
- this.setAttribute('focus-ring', '');
226
- } else if (!this.hasAttribute('focused')) {
227
- this.blur();
228
- }
229
225
  if (e.detail.sourceEvent && e.detail.sourceEvent.composedPath().includes(this)) {
230
226
  e.preventDefault();
231
227
  }
@@ -155,7 +155,7 @@ class InfiniteScroller extends PolymerElement {
155
155
  // Once the first set of items start fading in, stamp the rest
156
156
  this._buffers.forEach((buffer) => {
157
157
  [].forEach.call(buffer.children, (insertionPoint) => this._ensureStampedInstance(insertionPoint._itemWrapper));
158
- }, this);
158
+ });
159
159
 
160
160
  if (!this._buffers[0].translateY) {
161
161
  this._reset();
@@ -318,7 +318,7 @@ class InfiniteScroller extends PolymerElement {
318
318
  }
319
319
  }, 1); // Wait for first reset
320
320
  }
321
- }, this);
321
+ });
322
322
 
323
323
  setTimeout(() => {
324
324
  afterNextRender(this, this._finishInit.bind(this));
@@ -356,7 +356,7 @@ class InfiniteScroller extends PolymerElement {
356
356
  });
357
357
  buffer.updated = true;
358
358
  }
359
- }, this);
359
+ });
360
360
  }
361
361
 
362
362
  _isVisible(element, container) {
@@ -250,7 +250,9 @@ class MonthCalendar extends FocusMixin(ThemableMixin(PolymerElement)) {
250
250
 
251
251
  _onMonthGridTouchStart() {
252
252
  this._notTapping = false;
253
- setTimeout(() => (this._notTapping = true), 300);
253
+ setTimeout(() => {
254
+ this._notTapping = true;
255
+ }, 300);
254
256
  }
255
257
 
256
258
  _dateAdd(date, delta) {
@@ -11,7 +11,6 @@ registerStyles(
11
11
  css`
12
12
  :host {
13
13
  position: relative;
14
- background-color: transparent;
15
14
  /* Background for the year scroller, placed here as we are using a mask image on the actual years part */
16
15
  background-image: linear-gradient(var(--lumo-shade-5pct), var(--lumo-shade-5pct));
17
16
  background-size: 57px 100%;
@@ -119,17 +118,10 @@ registerStyles(
119
118
 
120
119
  [part='toolbar'] {
121
120
  padding: var(--lumo-space-s);
122
- box-shadow: 0 -1px 0 0 var(--lumo-contrast-10pct);
123
121
  border-bottom-left-radius: var(--lumo-border-radius-l);
124
122
  margin-right: 57px;
125
123
  }
126
124
 
127
- @supports (mask-image: linear-gradient(#000, #000)) or (-webkit-mask-image: linear-gradient(#000, #000)) {
128
- [part='toolbar'] {
129
- box-shadow: none;
130
- }
131
- }
132
-
133
125
  /* Today and Cancel buttons */
134
126
 
135
127
  [part='toolbar'] [part\$='button'] {
@@ -162,8 +154,6 @@ registerStyles(
162
154
  /* Very narrow screen (year scroller initially hidden) */
163
155
 
164
156
  [part='years-toggle-button'] {
165
- position: relative;
166
- right: auto;
167
157
  display: flex;
168
158
  align-items: center;
169
159
  height: var(--lumo-size-s);
@@ -181,10 +171,6 @@ registerStyles(
181
171
  color: var(--lumo-primary-contrast-color);
182
172
  }
183
173
 
184
- [part='years-toggle-button']::before {
185
- content: none;
186
- }
187
-
188
174
  /* TODO magic number (same as used for iron-media-query in vaadin-date-picker-overlay-content) */
189
175
  @media screen and (max-width: 374px) {
190
176
  :host {
@@ -151,9 +151,9 @@ registerStyles(
151
151
  { moduleId: 'lumo-month-calendar' },
152
152
  );
153
153
 
154
- const $_documentContainer = document.createElement('template');
154
+ const template = document.createElement('template');
155
155
 
156
- $_documentContainer.innerHTML = `
156
+ template.innerHTML = `
157
157
  <style>
158
158
  @keyframes vaadin-date-picker-month-calendar-focus-date {
159
159
  50% {
@@ -163,4 +163,4 @@ $_documentContainer.innerHTML = `
163
163
  </style>
164
164
  `;
165
165
 
166
- document.head.appendChild($_documentContainer.content);
166
+ document.head.appendChild(template.content);
@@ -13,9 +13,6 @@ registerStyles(
13
13
  font-size: var(--material-body-font-size);
14
14
  -webkit-text-size-adjust: 100%;
15
15
  line-height: 1.4;
16
-
17
- /* FIXME(platosha): fix the core styles and remove this override. */
18
- background: transparent;
19
16
  }
20
17
 
21
18
  :host([fullscreen]) {
@@ -36,11 +33,6 @@ registerStyles(
36
33
  box-shadow: var(--material-shadow-elevation-4dp);
37
34
  }
38
35
 
39
- /* FIXME(platosha): fix the core styles and remove this override. */
40
- [part='overlay-header']:not([desktop]) {
41
- padding-bottom: 8px;
42
- }
43
-
44
36
  [part='label'] {
45
37
  padding: 0 8px;
46
38
  flex: auto;
@@ -54,11 +46,6 @@ registerStyles(
54
46
  width: 24px;
55
47
  height: 24px;
56
48
  text-align: center;
57
- }
58
-
59
- [part='clear-button'],
60
- [part='toggle-button'],
61
- [part='years-toggle-button'] {
62
49
  padding: 8px;
63
50
  color: var(--material-secondary-text-color);
64
51
  }
@@ -78,7 +65,6 @@ registerStyles(
78
65
  }
79
66
 
80
67
  [part='years-toggle-button'] {
81
- position: static;
82
68
  padding: 4px 8px;
83
69
  font-size: var(--material-body-font-size);
84
70
  font-weight: 500;
@@ -87,11 +73,6 @@ registerStyles(
87
73
  color: var(--material-secondary-text-color);
88
74
  }
89
75
 
90
- [part='years-toggle-button']::before {
91
- content: '';
92
- display: none;
93
- }
94
-
95
76
  [part='years-toggle-button']::after {
96
77
  content: var(--material-icons-play);
97
78
  display: inline-block;