@lion/ui 0.3.3 → 0.3.5

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.
Files changed (85) hide show
  1. package/components/calendar/src/LionCalendar.js +121 -65
  2. package/components/calendar/src/calendarStyle.js +25 -1
  3. package/components/calendar/src/utils/createDay.js +2 -0
  4. package/components/calendar/src/utils/dayTemplate.js +19 -32
  5. package/components/calendar/src/utils/getDayMonthYear.js +28 -0
  6. package/components/calendar/test/lion-calendar.test.js +118 -108
  7. package/components/calendar/test/utils/dayTemplate.test.js +8 -4
  8. package/components/calendar/test/utils/snapshots/monthTemplate_en-GB_Sunday_2018-12.js +210 -126
  9. package/components/calendar/test-helpers/DayObject.js +2 -2
  10. package/components/calendar/types/day.ts +1 -0
  11. package/components/input-datepicker/src/LionInputDatepicker.js +34 -2
  12. package/components/input-file/src/LionInputFile.js +5 -7
  13. package/components/input-file/test/lion-input-file.test.js +4 -0
  14. package/components/overlays/src/ArrowMixin.js +3 -1
  15. package/components/overlays/test/ArrowMixin.test.js +14 -0
  16. package/custom-elements.json +323 -31
  17. package/dist-types/components/calendar/src/LionCalendar.d.ts +22 -15
  18. package/dist-types/components/calendar/src/LionCalendar.d.ts.map +1 -1
  19. package/dist-types/components/calendar/src/calendarStyle.d.ts.map +1 -1
  20. package/dist-types/components/calendar/src/utils/createDay.d.ts +2 -1
  21. package/dist-types/components/calendar/src/utils/createDay.d.ts.map +1 -1
  22. package/dist-types/components/calendar/src/utils/dayTemplate.d.ts.map +1 -1
  23. package/dist-types/components/calendar/src/utils/getDayMonthYear.d.ts +13 -0
  24. package/dist-types/components/calendar/src/utils/getDayMonthYear.d.ts.map +1 -0
  25. package/dist-types/components/calendar/types/day.d.ts +1 -0
  26. package/dist-types/components/calendar/types/day.d.ts.map +1 -1
  27. package/dist-types/components/input-datepicker/src/LionInputDatepicker.d.ts +6 -0
  28. package/dist-types/components/input-datepicker/src/LionInputDatepicker.d.ts.map +1 -1
  29. package/dist-types/components/input-file/src/LionInputFile.d.ts +6 -0
  30. package/dist-types/components/input-file/src/LionInputFile.d.ts.map +1 -1
  31. package/dist-types/components/overlays/src/ArrowMixin.d.ts.map +1 -1
  32. package/dist-types/tsconfig.tsbuildinfo +1 -1
  33. package/docs/components/calendar/use-cases.md +39 -0
  34. package/docs/components/checkbox-group/overview.md +2 -2
  35. package/docs/components/collapsible/overview.md +1 -1
  36. package/docs/components/combobox/overview.md +1 -1
  37. package/docs/components/combobox/use-cases.md +1 -1
  38. package/docs/components/dialog/overview.md +1 -1
  39. package/docs/components/fieldset/overview.md +5 -5
  40. package/docs/components/form/overview.md +3 -3
  41. package/docs/components/icon/use-cases.md +1 -1
  42. package/docs/components/input/overview.md +1 -1
  43. package/docs/components/input-amount/overview.md +3 -3
  44. package/docs/components/input-date/overview.md +3 -3
  45. package/docs/components/input-datepicker/overview.md +5 -5
  46. package/docs/components/input-datepicker/use-cases.md +2 -0
  47. package/docs/components/input-email/overview.md +2 -2
  48. package/docs/components/input-file/overview.md +1 -1
  49. package/docs/components/input-iban/overview.md +2 -2
  50. package/docs/components/input-range/overview.md +2 -2
  51. package/docs/components/input-stepper/overview.md +1 -1
  52. package/docs/components/input-tel/overview.md +1 -1
  53. package/docs/components/input-tel/use-cases.md +6 -6
  54. package/docs/components/input-tel-dropdown/overview.md +1 -1
  55. package/docs/components/radio-group/overview.md +3 -3
  56. package/docs/components/select-rich/use-cases.md +1 -1
  57. package/docs/components/tabs/examples.md +1 -1
  58. package/docs/fundamentals/index.md +4 -4
  59. package/docs/fundamentals/node-tools/providence-analytics/LocalConfiguration.md +1 -1
  60. package/docs/fundamentals/node-tools/providence-analytics/QueryResult.md +1 -1
  61. package/docs/fundamentals/node-tools/providence-analytics/analyzer.md +1 -1
  62. package/docs/fundamentals/node-tools/providence-analytics/dashboard.md +1 -1
  63. package/docs/fundamentals/node-tools/providence-analytics/overview.md +3 -3
  64. package/docs/fundamentals/node-tools/publish-docs/overview.md +3 -3
  65. package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +2 -2
  66. package/docs/fundamentals/rationales/accessibility.md +1 -1
  67. package/docs/fundamentals/systems/core/SlotMixin.md +1 -1
  68. package/docs/fundamentals/systems/core/overview.md +1 -1
  69. package/docs/fundamentals/systems/form/formatting-and-parsing.md +4 -4
  70. package/docs/fundamentals/systems/form/model-value.md +1 -1
  71. package/docs/fundamentals/systems/form/overview.md +28 -28
  72. package/docs/fundamentals/systems/form/validate.md +1 -1
  73. package/docs/fundamentals/systems/localize/overview.md +4 -4
  74. package/docs/fundamentals/systems/overlays/configuration.md +2 -2
  75. package/docs/fundamentals/systems/overlays/overview.md +5 -5
  76. package/docs/fundamentals/systems/overlays/use-cases.md +2 -2
  77. package/docs/fundamentals/tools/helpers/overview.md +1 -1
  78. package/docs/fundamentals/tools/singleton-manager/overview.md +4 -4
  79. package/docs/guides/how-to/create-a-custom-field.md +5 -5
  80. package/docs/guides/how-to/create-a-form.md +4 -4
  81. package/docs/guides/how-to/extend-a-native-input.md +2 -2
  82. package/docs/guides/index.md +8 -8
  83. package/docs/guides/principles/index.md +5 -5
  84. package/docs/guides/principles/styling.md +1 -1
  85. package/package.json +1 -1
@@ -15,6 +15,7 @@ import { dayTemplate } from './utils/dayTemplate.js';
15
15
  import { getFirstDayNextMonth } from './utils/getFirstDayNextMonth.js';
16
16
  import { getLastDayPreviousMonth } from './utils/getLastDayPreviousMonth.js';
17
17
  import { isSameDate } from './utils/isSameDate.js';
18
+ import { getDayMonthYear } from './utils/getDayMonthYear.js';
18
19
 
19
20
  /**
20
21
  * @typedef {import('../types/day.js').Day} Day
@@ -22,6 +23,17 @@ import { isSameDate } from './utils/isSameDate.js';
22
23
  * @typedef {import('../types/day.js').Month} Month
23
24
  */
24
25
 
26
+ const isDayButton = /** @param {HTMLElement} el */ el =>
27
+ el.classList.contains('calendar__day-button');
28
+
29
+ /**
30
+ * @param {HTMLElement} el
31
+ * @returns {boolean}
32
+ */
33
+ function isDisabledDayButton(el) {
34
+ return el.getAttribute('aria-disabled') === 'true';
35
+ }
36
+
25
37
  /**
26
38
  * @customElement lion-calendar
27
39
  */
@@ -213,19 +225,19 @@ export class LionCalendar extends LocalizeMixin(LitElement) {
213
225
  }
214
226
 
215
227
  goToNextMonth() {
216
- this.__modifyDate(1, { dateType: 'centralDate', type: 'Month', mode: 'both' });
228
+ this.__modifyDate(1, { dateType: 'centralDate', type: 'Month' });
217
229
  }
218
230
 
219
231
  goToPreviousMonth() {
220
- this.__modifyDate(-1, { dateType: 'centralDate', type: 'Month', mode: 'both' });
232
+ this.__modifyDate(-1, { dateType: 'centralDate', type: 'Month' });
221
233
  }
222
234
 
223
235
  goToNextYear() {
224
- this.__modifyDate(1, { dateType: 'centralDate', type: 'FullYear', mode: 'both' });
236
+ this.__modifyDate(1, { dateType: 'centralDate', type: 'FullYear' });
225
237
  }
226
238
 
227
239
  goToPreviousYear() {
228
- this.__modifyDate(-1, { dateType: 'centralDate', type: 'FullYear', mode: 'both' });
240
+ this.__modifyDate(-1, { dateType: 'centralDate', type: 'FullYear' });
229
241
  }
230
242
 
231
243
  /**
@@ -238,9 +250,7 @@ export class LionCalendar extends LocalizeMixin(LitElement) {
238
250
  }
239
251
 
240
252
  focusCentralDate() {
241
- const button = /** @type {HTMLElement} */ (
242
- this.shadowRoot?.querySelector('button[tabindex="0"]')
243
- );
253
+ const button = /** @type {HTMLElement} */ (this.shadowRoot?.querySelector('[tabindex="0"]'));
244
254
  button.focus();
245
255
  this.__focusedDate = this.centralDate;
246
256
  }
@@ -328,13 +338,8 @@ export class LionCalendar extends LocalizeMixin(LitElement) {
328
338
  return;
329
339
  }
330
340
 
331
- const map = {
332
- disableDates: () => this.__disableDatesChanged(),
333
- centralDate: () => this.__centralDateChanged(),
334
- __focusedDate: () => this.__focusedDateChanged(),
335
- };
336
- if (map[name]) {
337
- map[name]();
341
+ if (name === '__focusedDate') {
342
+ this.__focusedDateChanged();
338
343
  }
339
344
 
340
345
  const updateDataOn = ['centralDate', 'minDate', 'maxDate', 'selectedDate', 'disableDates'];
@@ -362,10 +367,8 @@ export class LionCalendar extends LocalizeMixin(LitElement) {
362
367
  */
363
368
  __calculateInitialCentralDate() {
364
369
  if (this.centralDate === this.__today && this.selectedDate) {
365
- // initialised with selectedDate only if user didn't provide another one
370
+ // initialized with selectedDate only if user didn't provide another one
366
371
  this.centralDate = this.selectedDate;
367
- } else {
368
- this.__ensureValidCentralDate();
369
372
  }
370
373
  /** @type {Date} */
371
374
  this.__initialCentralDate = this.centralDate;
@@ -581,6 +584,35 @@ export class LionCalendar extends LocalizeMixin(LitElement) {
581
584
  return `${this.msgLit(`lion-calendar:${mode}${type}`)}, ${month} ${year}`;
582
585
  }
583
586
 
587
+ /**
588
+ *
589
+ * @private
590
+ */
591
+ __getSelectableDateRange() {
592
+ const newMinDate = createDay(new Date(this.minDate));
593
+ const newMaxDate = createDay(new Date(this.maxDate));
594
+
595
+ const getSelectableDate = (/** @type {import("../types/day.js").Day} */ date) => {
596
+ const { dayNumber, monthName, year } = getDayMonthYear(
597
+ date,
598
+ getWeekdayNames({
599
+ locale: this.__getLocale(),
600
+ style: 'long',
601
+ firstDayOfWeek: this.firstDayOfWeek,
602
+ }),
603
+ );
604
+ return `${dayNumber} ${monthName} ${year}`;
605
+ };
606
+
607
+ const earliestSelectableDate = getSelectableDate(newMinDate);
608
+ const latestSelectableDate = getSelectableDate(newMaxDate);
609
+
610
+ return {
611
+ earliestSelectableDate,
612
+ latestSelectableDate,
613
+ };
614
+ }
615
+
584
616
  /**
585
617
  *
586
618
  * @param {Day} _day
@@ -605,13 +637,27 @@ export class LionCalendar extends LocalizeMixin(LitElement) {
605
637
  day.tabindex = day.central ? '0' : '-1';
606
638
  day.ariaPressed = day.selected ? 'true' : 'false';
607
639
  day.ariaCurrent = day.today ? 'date' : undefined;
640
+ day.disabledInfo = '';
608
641
 
609
642
  if (this.minDate && normalizeDateTime(day.date) < normalizeDateTime(this.minDate)) {
610
643
  day.disabled = true;
644
+ // TODO: turn this into a translated string
645
+ day.disabledInfo = `This date is unavailable. Earliest date to select is ${
646
+ this.__getSelectableDateRange().earliestSelectableDate
647
+ }. Please select another date.`;
611
648
  }
612
649
 
613
650
  if (this.maxDate && normalizeDateTime(day.date) > normalizeDateTime(this.maxDate)) {
614
651
  day.disabled = true;
652
+ // TODO: turn this into a translated string
653
+ day.disabledInfo = `This date is unavailable. Latest date to select is ${
654
+ this.__getSelectableDateRange().latestSelectableDate
655
+ }. Please select another date.`;
656
+ }
657
+
658
+ if (day.disabled) {
659
+ // TODO: turn this into a translated string
660
+ day.disabledInfo = `This date is unavailable. Please select another date`;
615
661
  }
616
662
 
617
663
  return this.dayPreprocessor(day);
@@ -641,15 +687,6 @@ export class LionCalendar extends LocalizeMixin(LitElement) {
641
687
  return data;
642
688
  }
643
689
 
644
- /**
645
- * @private
646
- */
647
- __disableDatesChanged() {
648
- if (this.__connectedCallbackDone) {
649
- this.__ensureValidCentralDate();
650
- }
651
- }
652
-
653
690
  /**
654
691
  * @param {Date} selectedDate
655
692
  * @private
@@ -669,28 +706,37 @@ export class LionCalendar extends LocalizeMixin(LitElement) {
669
706
  /**
670
707
  * @private
671
708
  */
672
- __centralDateChanged() {
673
- if (this.__connectedCallbackDone) {
674
- this.__ensureValidCentralDate();
709
+ __focusedDateChanged() {
710
+ if (this.__focusedDate) {
711
+ this.centralDate = this.__focusedDate;
675
712
  }
676
713
  }
677
714
 
678
715
  /**
679
- * @private
716
+ * @param {Date} [date]
717
+ * @returns
680
718
  */
681
- __focusedDateChanged() {
682
- if (this.__focusedDate) {
683
- this.centralDate = this.__focusedDate;
684
- }
719
+ findNextEnabledDate(date) {
720
+ const _date = date || this.centralDate;
721
+ return this.__findBestEnabledDateFor(_date, { mode: 'future' });
685
722
  }
686
723
 
687
724
  /**
688
- * @private
725
+ * @param {Date} [date]
726
+ * @returns
689
727
  */
690
- __ensureValidCentralDate() {
691
- if (!this.__isEnabledDate(this.centralDate)) {
692
- this.centralDate = this.__findBestEnabledDateFor(this.centralDate);
693
- }
728
+ findPreviousEnabledDate(date) {
729
+ const _date = date || this.centralDate;
730
+ return this.__findBestEnabledDateFor(_date, { mode: 'past' });
731
+ }
732
+
733
+ /**
734
+ * @param {Date} [date]
735
+ * @returns
736
+ */
737
+ findNearestEnabledDate(date) {
738
+ const _date = date || this.centralDate;
739
+ return this.__findBestEnabledDateFor(_date, { mode: 'both' });
694
740
  }
695
741
 
696
742
  /**
@@ -750,11 +796,8 @@ export class LionCalendar extends LocalizeMixin(LitElement) {
750
796
  * @private
751
797
  */
752
798
  __clickDateDelegation(ev) {
753
- const isDayButton = /** @param {HTMLElement} el */ el =>
754
- el.classList.contains('calendar__day-button');
755
-
756
- const el = /** @type {HTMLElement & { date: Date }} */ (ev.composedPath()[0]);
757
- if (isDayButton(el)) {
799
+ const el = /** @type {HTMLElement & { date: Date }} */ (ev.target);
800
+ if (isDayButton(el) && !isDisabledDayButton(el)) {
758
801
  this.__dateSelectedByUser(el.date);
759
802
  }
760
803
  }
@@ -763,9 +806,6 @@ export class LionCalendar extends LocalizeMixin(LitElement) {
763
806
  * @private
764
807
  */
765
808
  __focusDateDelegation() {
766
- const isDayButton = /** @param {HTMLElement} el */ el =>
767
- el.classList.contains('calendar__day-button');
768
-
769
809
  if (
770
810
  !this.__focusedDate &&
771
811
  isDayButton(/** @type {HTMLElement} el */ (this.shadowRoot?.activeElement))
@@ -780,9 +820,6 @@ export class LionCalendar extends LocalizeMixin(LitElement) {
780
820
  * @private
781
821
  */
782
822
  __blurDateDelegation() {
783
- const isDayButton = /** @param {HTMLElement} el */ el =>
784
- el.classList.contains('calendar__day-button');
785
-
786
823
  setTimeout(() => {
787
824
  if (
788
825
  this.shadowRoot?.activeElement &&
@@ -793,42 +830,65 @@ export class LionCalendar extends LocalizeMixin(LitElement) {
793
830
  }, 1);
794
831
  }
795
832
 
833
+ /**
834
+ * @param {HTMLElement & { date: Date }} el
835
+ * @private
836
+ */
837
+ __dayButtonSelection(el) {
838
+ if (isDayButton(el)) {
839
+ this.__dateSelectedByUser(el.date);
840
+ }
841
+ }
842
+
796
843
  /**
797
844
  * @param {KeyboardEvent} ev
798
845
  * @private
799
846
  */
800
847
  __keyboardNavigationEvent(ev) {
801
- const preventedKeys = ['ArrowUp', 'ArrowDown', 'PageDown', 'PageUp'];
848
+ const preventedKeys = [
849
+ 'ArrowLeft',
850
+ 'ArrowUp',
851
+ 'ArrowRight',
852
+ 'ArrowDown',
853
+ 'PageDown',
854
+ 'PageUp',
855
+ ' ',
856
+ 'Enter',
857
+ ];
802
858
 
803
859
  if (preventedKeys.includes(ev.key)) {
804
860
  ev.preventDefault();
805
861
  }
806
862
 
807
863
  switch (ev.key) {
864
+ case ' ':
865
+ case 'Enter':
866
+ this.__dayButtonSelection(/** @type {HTMLElement & { date: Date }} */ (ev.target));
867
+ break;
808
868
  case 'ArrowUp':
809
- this.__modifyDate(-7, { dateType: '__focusedDate', type: 'Date', mode: 'past' });
869
+ this.__modifyDate(-7, { dateType: '__focusedDate', type: 'Date' });
810
870
  break;
811
871
  case 'ArrowDown':
812
- this.__modifyDate(7, { dateType: '__focusedDate', type: 'Date', mode: 'future' });
872
+ this.__modifyDate(7, { dateType: '__focusedDate', type: 'Date' });
813
873
  break;
814
874
  case 'ArrowLeft':
815
- this.__modifyDate(-1, { dateType: '__focusedDate', type: 'Date', mode: 'past' });
875
+ this.__modifyDate(-1, { dateType: '__focusedDate', type: 'Date' });
816
876
  break;
817
877
  case 'ArrowRight':
818
- this.__modifyDate(1, { dateType: '__focusedDate', type: 'Date', mode: 'future' });
878
+ this.__modifyDate(1, { dateType: '__focusedDate', type: 'Date' });
819
879
  break;
820
880
  case 'PageDown':
821
881
  if (ev.altKey === true) {
822
- this.__modifyDate(1, { dateType: '__focusedDate', type: 'FullYear', mode: 'future' });
882
+ this.__modifyDate(1, { dateType: '__focusedDate', type: 'FullYear' });
823
883
  } else {
824
- this.__modifyDate(1, { dateType: '__focusedDate', type: 'Month', mode: 'future' });
884
+ this.__modifyDate(1, { dateType: '__focusedDate', type: 'Month' });
825
885
  }
826
886
  break;
827
887
  case 'PageUp':
828
888
  if (ev.altKey === true) {
829
- this.__modifyDate(-1, { dateType: '__focusedDate', type: 'FullYear', mode: 'past' });
889
+ this.__modifyDate(-1, { dateType: '__focusedDate', type: 'FullYear' });
830
890
  } else {
831
- this.__modifyDate(-1, { dateType: '__focusedDate', type: 'Month', mode: 'past' });
891
+ this.__modifyDate(-1, { dateType: '__focusedDate', type: 'Month' });
832
892
  }
833
893
  break;
834
894
  case 'Tab':
@@ -844,11 +904,10 @@ export class LionCalendar extends LocalizeMixin(LitElement) {
844
904
  * @param {Object} opts
845
905
  * @param {string} opts.dateType
846
906
  * @param {string} opts.type
847
- * @param {string} opts.mode
848
907
  * @private
849
908
  */
850
- __modifyDate(modify, { dateType, type, mode }) {
851
- let tmpDate = new Date(this.centralDate);
909
+ __modifyDate(modify, { dateType, type }) {
910
+ const tmpDate = new Date(this.centralDate);
852
911
  // if we're not working with days, reset
853
912
  // day count to first day of the month
854
913
  if (type !== 'Date') {
@@ -861,9 +920,6 @@ export class LionCalendar extends LocalizeMixin(LitElement) {
861
920
  const maxDays = new Date(tmpDate.getFullYear(), tmpDate.getMonth() + 1, 0).getDate();
862
921
  tmpDate.setDate(Math.min(this.centralDate.getDate(), maxDays));
863
922
  }
864
- if (!this.__isEnabledDate(tmpDate)) {
865
- tmpDate = this.__findBestEnabledDateFor(tmpDate, { mode });
866
- }
867
923
  this[dateType] = tmpDate;
868
924
  }
869
925
 
@@ -54,6 +54,16 @@ export const calendarStyle = css`
54
54
  padding: 0;
55
55
  min-width: 40px;
56
56
  min-height: 40px;
57
+ /** give div[role=button][aria-disabled] same display type as native btn */
58
+ display: inline-flex;
59
+ justify-content: center;
60
+ align-items: center;
61
+ box-sizing: border-box;
62
+ }
63
+
64
+ .calendar__day-button:focus {
65
+ border: 1px solid blue;
66
+ outline: none;
57
67
  }
58
68
 
59
69
  .calendar__day-button__text {
@@ -77,9 +87,23 @@ export const calendarStyle = css`
77
87
  border: 1px solid green;
78
88
  }
79
89
 
80
- .calendar__day-button[disabled] {
90
+ .calendar__day-button[aria-disabled='true'] {
81
91
  background-color: #fff;
82
92
  color: #eee;
83
93
  outline: none;
84
94
  }
95
+
96
+ .u-sr-only {
97
+ position: absolute;
98
+ top: 0;
99
+ width: 1px;
100
+ height: 1px;
101
+ overflow: hidden;
102
+ clip-path: inset(100%);
103
+ clip: rect(1px, 1px, 1px, 1px);
104
+ white-space: nowrap;
105
+ border: 0;
106
+ margin: 0;
107
+ padding: 0;
108
+ }
85
109
  `;
@@ -16,6 +16,7 @@ export function createDay(
16
16
  today = false,
17
17
  future = false,
18
18
  disabled = false,
19
+ disabledInfo = '',
19
20
  } = {},
20
21
  ) {
21
22
  return {
@@ -34,5 +35,6 @@ export function createDay(
34
35
  tabindex: '-1',
35
36
  ariaPressed: 'false',
36
37
  ariaCurrent: undefined,
38
+ disabledInfo,
37
39
  };
38
40
  }
@@ -1,20 +1,7 @@
1
1
  import { html } from 'lit';
2
2
  import { ifDefined } from 'lit/directives/if-defined.js';
3
+ import { defaultMonthLabels, getDayMonthYear } from './getDayMonthYear.js';
3
4
 
4
- const defaultMonthLabels = [
5
- 'January',
6
- 'February',
7
- 'March',
8
- 'April',
9
- 'May',
10
- 'June',
11
- 'July',
12
- 'August',
13
- 'September',
14
- 'October',
15
- 'November',
16
- 'December',
17
- ];
18
5
  const firstWeekDays = [1, 2, 3, 4, 5, 6, 7];
19
6
  const lastDaysOfYear = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
20
7
 
@@ -24,10 +11,15 @@ const lastDaysOfYear = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
24
11
  * @param {{ weekdays: string[], monthsLabels?: string[] }} opts
25
12
  */
26
13
  export function dayTemplate(day, { weekdays, monthsLabels = defaultMonthLabels }) {
27
- const dayNumber = day.date.getDate();
28
- const monthName = monthsLabels[day.date.getMonth()];
29
- const year = day.date.getFullYear();
30
- const weekdayName = day.weekOrder ? weekdays[day.weekOrder] : weekdays[0];
14
+ const { dayNumber, monthName, year, weekdayName } = getDayMonthYear(day, weekdays, monthsLabels);
15
+
16
+ function __getFullDate() {
17
+ return `${monthName} ${year} ${weekdayName}`;
18
+ }
19
+
20
+ function __getAccessibleMessage() {
21
+ return `${day.disabledInfo}`;
22
+ }
31
23
 
32
24
  const firstDay = dayNumber === 1;
33
25
  const endOfFirstWeek = day.weekOrder === 6 && firstWeekDays.includes(dayNumber);
@@ -57,20 +49,14 @@ export function dayTemplate(day, { weekdays, monthsLabels = defaultMonthLabels }
57
49
  ?start-of-last-week=${startOfLastWeek}
58
50
  ?last-day=${lastDay}
59
51
  >
60
- <button
52
+ <div
53
+ role="button"
61
54
  .date=${day.date}
62
55
  class="calendar__day-button"
63
- tabindex=${ifDefined(Number(day.tabindex))}
64
- aria-label=${`${dayNumber} ${monthName} ${year} ${weekdayName}`}
65
- aria-pressed=${
66
- /** @type {'true'|'false'|'mixed'|'undefined'} */ (ifDefined(day.ariaPressed))
67
- }
68
- aria-current=${
69
- /** @type {'page'|'step'|'location'|'date'|'time'|'true'|'false'} */ (
70
- ifDefined(day.ariaCurrent)
71
- )
72
- }
73
- ?disabled=${day.disabled}
56
+ tabindex=${ifDefined(day.tabindex)}
57
+ aria-pressed=${ifDefined(day.ariaPressed)}
58
+ aria-current=${ifDefined(day.ariaCurrent)}
59
+ aria-disabled=${day.disabled ? 'true' : 'false'}
74
60
  ?selected=${day.selected}
75
61
  ?past=${day.past}
76
62
  ?today=${day.today}
@@ -79,8 +65,9 @@ export function dayTemplate(day, { weekdays, monthsLabels = defaultMonthLabels }
79
65
  ?current-month=${day.currentMonth}
80
66
  ?next-month=${day.nextMonth}
81
67
  >
82
- <span class="calendar__day-button__text"> ${day.date.getDate()} </span>
83
- </button>
68
+ <span class="calendar__day-button__text">${dayNumber}</span>
69
+ <span class="u-sr-only">${__getFullDate()} ${__getAccessibleMessage()}</span>
70
+ </div>
84
71
  </td>
85
72
  `;
86
73
  }
@@ -0,0 +1,28 @@
1
+ export const defaultMonthLabels = [
2
+ 'January',
3
+ 'February',
4
+ 'March',
5
+ 'April',
6
+ 'May',
7
+ 'June',
8
+ 'July',
9
+ 'August',
10
+ 'September',
11
+ 'October',
12
+ 'November',
13
+ 'December',
14
+ ];
15
+
16
+ /**
17
+ * @param {import('../../types/day.js').Day} day
18
+ * @param {string[]} weekdays
19
+ * @param {string[] } monthsLabels
20
+ */
21
+ export function getDayMonthYear(day, weekdays, monthsLabels = defaultMonthLabels) {
22
+ const dayNumber = day.date.getDate();
23
+ const monthName = monthsLabels[day.date.getMonth()];
24
+ const year = day.date.getFullYear();
25
+ const weekdayName = day.weekOrder ? weekdays[day.weekOrder] : weekdays[0];
26
+
27
+ return { dayNumber, monthName, year, weekdayName };
28
+ }