@vaadin/date-picker 24.2.0-dev.f254716fe → 24.2.0-rc1

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.
@@ -5,76 +5,25 @@
5
5
  */
6
6
  import '@polymer/polymer/lib/elements/dom-repeat.js';
7
7
  import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
8
- import { FocusMixin } from '@vaadin/a11y-base/src/focus-mixin.js';
9
- import { addListener } from '@vaadin/component-base/src/gestures.js';
10
- import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
11
- import { dateAllowed, dateEquals, getISOWeekNumber } from './vaadin-date-picker-helper.js';
8
+ import { defineCustomElement } from '@vaadin/component-base/src/define.js';
9
+ import { registerStyles, ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
10
+ import { dateAllowed, dateEquals } from './vaadin-date-picker-helper.js';
11
+ import { MonthCalendarMixin } from './vaadin-month-calendar-mixin.js';
12
+ import { monthCalendarStyles } from './vaadin-month-calendar-styles.js';
13
+
14
+ registerStyles('vaadin-month-calendar', monthCalendarStyles, {
15
+ moduleId: 'vaadin-month-calendar-styles',
16
+ });
12
17
 
13
18
  /**
19
+ * @customElement
14
20
  * @extends HTMLElement
15
21
  * @private
16
22
  */
17
- class MonthCalendar extends FocusMixin(ThemableMixin(PolymerElement)) {
23
+ class MonthCalendar extends MonthCalendarMixin(ThemableMixin(PolymerElement)) {
18
24
  static get template() {
19
25
  return html`
20
- <style>
21
- :host {
22
- display: block;
23
- }
24
-
25
- #monthGrid {
26
- width: 100%;
27
- border-collapse: collapse;
28
- }
29
-
30
- #days-container tr,
31
- #weekdays-container tr {
32
- display: flex;
33
- }
34
-
35
- [part~='date'] {
36
- outline: none;
37
- }
38
-
39
- [part~='disabled'] {
40
- pointer-events: none;
41
- }
42
-
43
- [part='week-number'][hidden],
44
- [part='weekday'][hidden] {
45
- display: none;
46
- }
47
-
48
- [part='weekday'],
49
- [part~='date'] {
50
- width: calc(100% / 7);
51
- padding: 0;
52
- font-weight: normal;
53
- }
54
-
55
- [part='weekday']:empty,
56
- [part='week-number'] {
57
- width: 12.5%;
58
- flex-shrink: 0;
59
- padding: 0;
60
- }
61
-
62
- :host([week-numbers]) [part='weekday']:not(:empty),
63
- :host([week-numbers]) [part~='date'] {
64
- width: 12.5%;
65
- }
66
-
67
- @media (forced-colors: active) {
68
- [part~='date'][part~='focused'] {
69
- outline: 1px solid;
70
- }
71
- [part~='date'][part~='selected'] {
72
- outline: 3px solid;
73
- }
74
- }
75
- </style>
76
-
77
- <div part="month-header" id="month-header" aria-hidden="true">[[_getTitle(month, i18n.monthNames)]]</div>
26
+ <div part="month-header" id="month-header" aria-hidden="true">[[_getTitle(month, i18n)]]</div>
78
27
  <table
79
28
  id="monthGrid"
80
29
  role="grid"
@@ -84,15 +33,8 @@ class MonthCalendar extends FocusMixin(ThemableMixin(PolymerElement)) {
84
33
  >
85
34
  <thead id="weekdays-container">
86
35
  <tr role="row" part="weekdays">
87
- <th
88
- part="weekday"
89
- aria-hidden="true"
90
- hidden$="[[!_showWeekSeparator(showWeekNumbers, i18n.firstDayOfWeek)]]"
91
- ></th>
92
- <template
93
- is="dom-repeat"
94
- items="[[_getWeekDayNames(i18n.weekdays, i18n.weekdaysShort, showWeekNumbers, i18n.firstDayOfWeek)]]"
95
- >
36
+ <th part="weekday" aria-hidden="true" hidden$="[[!_showWeekSeparator(showWeekNumbers, i18n)]]"></th>
37
+ <template is="dom-repeat" items="[[_getWeekDayNames(i18n, showWeekNumbers)]]">
96
38
  <th role="columnheader" part="weekday" scope="col" abbr$="[[item.weekDay]]" aria-hidden="true">
97
39
  [[item.weekDayShort]]
98
40
  </th>
@@ -102,11 +44,7 @@ class MonthCalendar extends FocusMixin(ThemableMixin(PolymerElement)) {
102
44
  <tbody id="days-container">
103
45
  <template is="dom-repeat" items="[[_weeks]]" as="week">
104
46
  <tr role="row">
105
- <td
106
- part="week-number"
107
- aria-hidden="true"
108
- hidden$="[[!_showWeekSeparator(showWeekNumbers, i18n.firstDayOfWeek)]]"
109
- >
47
+ <td part="week-number" aria-hidden="true" hidden$="[[!_showWeekSeparator(showWeekNumbers, i18n)]]">
110
48
  [[__getWeekNumber(week)]]
111
49
  </td>
112
50
  <template is="dom-repeat" items="[[week]]">
@@ -135,65 +73,13 @@ class MonthCalendar extends FocusMixin(ThemableMixin(PolymerElement)) {
135
73
 
136
74
  static get properties() {
137
75
  return {
138
- /**
139
- * A `Date` object defining the month to be displayed. Only year and
140
- * month properties are actually used.
141
- */
142
- month: {
143
- type: Date,
144
- value: new Date(),
145
- },
146
-
147
- /**
148
- * A `Date` object for the currently selected date.
149
- */
150
- selectedDate: {
151
- type: Date,
152
- notify: true,
153
- },
154
-
155
- /**
156
- * A `Date` object for the currently focused date.
157
- */
158
- focusedDate: Date,
159
-
160
- showWeekNumbers: {
161
- type: Boolean,
162
- value: false,
163
- },
164
-
165
- i18n: {
166
- type: Object,
167
- },
168
-
169
- /**
170
- * Flag stating whether taps on the component should be ignored.
171
- */
172
- ignoreTaps: Boolean,
173
-
174
- _notTapping: Boolean,
175
-
176
- /**
177
- * The earliest date that can be selected. All earlier dates will be disabled.
178
- */
179
- minDate: {
180
- type: Date,
181
- value: null,
182
- },
183
-
184
- /**
185
- * The latest date that can be selected. All later dates will be disabled.
186
- */
187
- maxDate: {
188
- type: Date,
189
- value: null,
190
- },
191
-
76
+ /** @protected */
192
77
  _days: {
193
78
  type: Array,
194
- computed: '_getDays(month, i18n.firstDayOfWeek, minDate, maxDate)',
79
+ computed: '_getDays(month, i18n, minDate, maxDate)',
195
80
  },
196
81
 
82
+ /** @protected */
197
83
  _weeks: {
198
84
  type: Array,
199
85
  computed: '_getWeeks(_days)',
@@ -208,177 +94,19 @@ class MonthCalendar extends FocusMixin(ThemableMixin(PolymerElement)) {
208
94
  }
209
95
 
210
96
  static get observers() {
211
- return [
212
- '_showWeekNumbersChanged(showWeekNumbers, i18n.firstDayOfWeek)',
213
- '__focusedDateChanged(focusedDate, _days)',
214
- ];
215
- }
216
-
217
- get focusableDateElement() {
218
- return [...this.shadowRoot.querySelectorAll('[part~=date]')].find((datePart) => {
219
- return dateEquals(datePart.date, this.focusedDate);
220
- });
221
- }
222
-
223
- /** @protected */
224
- ready() {
225
- super.ready();
226
- addListener(this.$.monthGrid, 'tap', this._handleTap.bind(this));
227
- }
228
-
229
- /* Returns true if all the dates in the month are out of the allowed range */
230
- _isDisabled(month, minDate, maxDate) {
231
- // First day of the month
232
- const firstDate = new Date(0, 0);
233
- firstDate.setFullYear(month.getFullYear());
234
- firstDate.setMonth(month.getMonth());
235
- firstDate.setDate(1);
236
-
237
- // Last day of the month
238
- const lastDate = new Date(0, 0);
239
- lastDate.setFullYear(month.getFullYear());
240
- lastDate.setMonth(month.getMonth() + 1);
241
- lastDate.setDate(0);
242
-
243
- if (
244
- minDate &&
245
- maxDate &&
246
- minDate.getMonth() === maxDate.getMonth() &&
247
- minDate.getMonth() === month.getMonth() &&
248
- maxDate.getDate() - minDate.getDate() >= 0
249
- ) {
250
- return false;
251
- }
252
-
253
- return !dateAllowed(firstDate, minDate, maxDate) && !dateAllowed(lastDate, minDate, maxDate);
254
- }
255
-
256
- _getTitle(month, monthNames) {
257
- if (month === undefined || monthNames === undefined) {
258
- return;
259
- }
260
- return this.i18n.formatTitle(monthNames[month.getMonth()], month.getFullYear());
261
- }
262
-
263
- _onMonthGridTouchStart() {
264
- this._notTapping = false;
265
- setTimeout(() => {
266
- this._notTapping = true;
267
- }, 300);
268
- }
269
-
270
- _dateAdd(date, delta) {
271
- date.setDate(date.getDate() + delta);
272
- }
273
-
274
- _applyFirstDayOfWeek(weekDayNames, firstDayOfWeek) {
275
- if (weekDayNames === undefined || firstDayOfWeek === undefined) {
276
- return;
277
- }
278
-
279
- return weekDayNames.slice(firstDayOfWeek).concat(weekDayNames.slice(0, firstDayOfWeek));
280
- }
281
-
282
- _getWeekDayNames(weekDayNames, weekDayNamesShort, showWeekNumbers, firstDayOfWeek) {
283
- if (
284
- weekDayNames === undefined ||
285
- weekDayNamesShort === undefined ||
286
- showWeekNumbers === undefined ||
287
- firstDayOfWeek === undefined
288
- ) {
289
- return;
290
- }
291
- weekDayNames = this._applyFirstDayOfWeek(weekDayNames, firstDayOfWeek);
292
- weekDayNamesShort = this._applyFirstDayOfWeek(weekDayNamesShort, firstDayOfWeek);
293
- weekDayNames = weekDayNames.map((day, index) => {
294
- return {
295
- weekDay: day,
296
- weekDayShort: weekDayNamesShort[index],
297
- };
298
- });
299
-
300
- return weekDayNames;
97
+ return ['_showWeekNumbersChanged(showWeekNumbers, i18n)'];
301
98
  }
302
99
 
303
- __focusedDateChanged(focusedDate, days) {
304
- if (days.some((date) => dateEquals(date, focusedDate))) {
305
- this.removeAttribute('aria-hidden');
306
- } else {
307
- this.setAttribute('aria-hidden', 'true');
308
- }
309
- }
310
-
311
- _getDate(date) {
312
- return date ? date.getDate() : '';
313
- }
314
-
315
- _showWeekNumbersChanged(showWeekNumbers, firstDayOfWeek) {
316
- if (showWeekNumbers && firstDayOfWeek === 1) {
100
+ /** @private */
101
+ _showWeekNumbersChanged(showWeekNumbers, i18n) {
102
+ if (showWeekNumbers && i18n && i18n.firstDayOfWeek === 1) {
317
103
  this.setAttribute('week-numbers', '');
318
104
  } else {
319
105
  this.removeAttribute('week-numbers');
320
106
  }
321
107
  }
322
108
 
323
- _showWeekSeparator(showWeekNumbers, firstDayOfWeek) {
324
- // Currently only supported for locales that start the week on Monday.
325
- return showWeekNumbers && firstDayOfWeek === 1;
326
- }
327
-
328
- _isToday(date) {
329
- return dateEquals(new Date(), date);
330
- }
331
-
332
- _getDays(month, firstDayOfWeek) {
333
- if (month === undefined || firstDayOfWeek === undefined) {
334
- return;
335
- }
336
- // First day of the month (at midnight).
337
- const date = new Date(0, 0);
338
- date.setFullYear(month.getFullYear());
339
- date.setMonth(month.getMonth());
340
- date.setDate(1);
341
-
342
- // Rewind to first day of the week.
343
- while (date.getDay() !== firstDayOfWeek) {
344
- this._dateAdd(date, -1);
345
- }
346
-
347
- const days = [];
348
- const startMonth = date.getMonth();
349
- const targetMonth = month.getMonth();
350
- while (date.getMonth() === targetMonth || date.getMonth() === startMonth) {
351
- days.push(date.getMonth() === targetMonth ? new Date(date.getTime()) : null);
352
-
353
- // Advance to next day.
354
- this._dateAdd(date, 1);
355
- }
356
- return days;
357
- }
358
-
359
- _getWeeks(days) {
360
- return days.reduce((acc, day, i) => {
361
- if (i % 7 === 0) {
362
- acc.push([]);
363
- }
364
- acc[acc.length - 1].push(day);
365
- return acc;
366
- }, []);
367
- }
368
-
369
- _handleTap(e) {
370
- if (!this.ignoreTaps && !this._notTapping && e.target.date && !e.target.hasAttribute('disabled')) {
371
- this.selectedDate = e.target.date;
372
- this.dispatchEvent(
373
- new CustomEvent('date-tap', { detail: { date: e.target.date }, bubbles: true, composed: true }),
374
- );
375
- }
376
- }
377
-
378
- _preventDefault(e) {
379
- e.preventDefault();
380
- }
381
-
109
+ /** @private */
382
110
  __getDatePart(date, focusedDate, selectedDate, minDate, maxDate) {
383
111
  const result = ['date'];
384
112
 
@@ -401,32 +129,29 @@ class MonthCalendar extends FocusMixin(ThemableMixin(PolymerElement)) {
401
129
  return result.join(' ');
402
130
  }
403
131
 
404
- __getWeekNumber(days) {
405
- const date = days.reduce((acc, d) => {
406
- return !acc && d ? d : acc;
407
- });
408
-
409
- return getISOWeekNumber(date);
410
- }
411
-
132
+ /** @private */
412
133
  __isDayFocused(date, focusedDate) {
413
134
  return dateEquals(date, focusedDate);
414
135
  }
415
136
 
137
+ /** @private */
416
138
  __isDaySelected(date, selectedDate) {
417
139
  return dateEquals(date, selectedDate);
418
140
  }
419
141
 
142
+ /** @private */
420
143
  __getDayAriaSelected(date, selectedDate) {
421
144
  if (this.__isDaySelected(date, selectedDate)) {
422
145
  return 'true';
423
146
  }
424
147
  }
425
148
 
149
+ /** @private */
426
150
  __isDayDisabled(date, minDate, maxDate) {
427
151
  return !dateAllowed(date, minDate, maxDate);
428
152
  }
429
153
 
154
+ /** @private */
430
155
  __getDayAriaDisabled(date, min, max) {
431
156
  if (date === undefined || min === undefined || max === undefined) {
432
157
  return;
@@ -437,22 +162,7 @@ class MonthCalendar extends FocusMixin(ThemableMixin(PolymerElement)) {
437
162
  }
438
163
  }
439
164
 
440
- __getDayAriaLabel(date) {
441
- if (!date) {
442
- return '';
443
- }
444
-
445
- let ariaLabel = `${this._getDate(date)} ${this.i18n.monthNames[date.getMonth()]} ${date.getFullYear()}, ${
446
- this.i18n.weekdays[date.getDay()]
447
- }`;
448
-
449
- if (this._isToday(date)) {
450
- ariaLabel += `, ${this.i18n.today}`;
451
- }
452
-
453
- return ariaLabel;
454
- }
455
-
165
+ /** @private */
456
166
  __getDayTabindex(date, focusedDate) {
457
167
  if (this.__isDayFocused(date, focusedDate)) {
458
168
  return '0';
@@ -462,4 +172,4 @@ class MonthCalendar extends FocusMixin(ThemableMixin(PolymerElement)) {
462
172
  }
463
173
  }
464
174
 
465
- customElements.define(MonthCalendar.is, MonthCalendar);
175
+ defineCustomElement(MonthCalendar);