@lion/ui 0.9.1 → 0.10.1

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 (172) hide show
  1. package/components/button/src/LionButton.js +5 -1
  2. package/components/button/test-suites/LionButton.suite.js +1 -1
  3. package/components/calendar/src/LionCalendar.js +5 -14
  4. package/components/calendar/test/lion-calendar.test.js +88 -0
  5. package/components/calendar/translations/bg.js +5 -0
  6. package/components/calendar/translations/cs.js +5 -0
  7. package/components/calendar/translations/de.js +5 -0
  8. package/components/calendar/translations/en.js +5 -0
  9. package/components/calendar/translations/es.js +5 -0
  10. package/components/calendar/translations/fr.js +5 -0
  11. package/components/calendar/translations/hu.js +5 -0
  12. package/components/calendar/translations/it.js +5 -0
  13. package/components/calendar/translations/nl.js +5 -0
  14. package/components/calendar/translations/pl.js +5 -0
  15. package/components/calendar/translations/ro.js +5 -0
  16. package/components/calendar/translations/ru.js +5 -0
  17. package/components/calendar/translations/sk.js +5 -0
  18. package/components/calendar/translations/uk.js +3 -0
  19. package/components/calendar/translations/zh.js +3 -0
  20. package/components/combobox/test/lion-combobox.test.js +2 -0
  21. package/components/core/src/SlotMixin.js +15 -0
  22. package/components/core/test/ScopedElementsMixin.test.js +3 -3
  23. package/components/core/test/SlotMixin.test.js +50 -0
  24. package/components/dialog/src/LionDialog.js +13 -0
  25. package/components/dialog/test/lion-dialog.test.js +110 -0
  26. package/components/dialog/test-helpers/test-router.js +43 -0
  27. package/components/form-core/src/FormatMixin.js +66 -18
  28. package/components/form-core/src/choice-group/ChoiceInputMixin.js +3 -1
  29. package/components/form-core/test-suites/FormatMixin.suite.js +107 -8
  30. package/components/form-core/types/FormatMixinTypes.ts +4 -1
  31. package/components/form-integrations/test/dialog-integrations.test.js +6 -2
  32. package/components/input-amount/src/parsers.js +3 -3
  33. package/components/input-amount/test/lion-input-amount.test.js +36 -2
  34. package/components/input-amount/test/parsers.test.js +11 -0
  35. package/components/input-tel-dropdown/src/LionInputTelDropdown.js +1 -1
  36. package/components/localize/src/number/getDecimalSeparator.js +1 -1
  37. package/components/localize/src/number/parseNumber.js +9 -6
  38. package/components/localize/test/number/parseNumber.test.js +11 -0
  39. package/components/localize/types/LocalizeMixinTypes.ts +3 -3
  40. package/components/overlays/src/OverlayController.js +21 -6
  41. package/components/overlays/src/OverlayMixin.js +20 -14
  42. package/components/overlays/test/OverlayController.test.js +40 -8
  43. package/components/overlays/test-suites/OverlayMixin.suite.js +184 -9
  44. package/components/overlays/types/ArrowMixinTypes.ts +11 -2
  45. package/components/overlays/types/OverlayConfig.ts +19 -15
  46. package/components/select-rich/src/LionSelectRich.js +3 -1
  47. package/components/select-rich/test/lion-select-rich.test.js +44 -0
  48. package/custom-elements.json +1340 -89
  49. package/dist-types/components/button/src/LionButton.d.ts.map +1 -1
  50. package/dist-types/components/calendar/src/LionCalendar.d.ts.map +1 -1
  51. package/dist-types/components/calendar/translations/bg.d.ts +3 -0
  52. package/dist-types/components/calendar/translations/cs.d.ts +3 -0
  53. package/dist-types/components/calendar/translations/de.d.ts +3 -0
  54. package/dist-types/components/calendar/translations/en.d.ts +3 -0
  55. package/dist-types/components/calendar/translations/es.d.ts +3 -0
  56. package/dist-types/components/calendar/translations/fr.d.ts +3 -0
  57. package/dist-types/components/calendar/translations/hu.d.ts +3 -0
  58. package/dist-types/components/calendar/translations/it.d.ts +3 -0
  59. package/dist-types/components/calendar/translations/nl.d.ts +3 -0
  60. package/dist-types/components/calendar/translations/pl.d.ts +3 -0
  61. package/dist-types/components/calendar/translations/ro.d.ts +3 -0
  62. package/dist-types/components/calendar/translations/ru.d.ts +3 -0
  63. package/dist-types/components/calendar/translations/sk.d.ts +3 -0
  64. package/dist-types/components/calendar/translations/uk.d.ts +3 -0
  65. package/dist-types/components/calendar/translations/zh.d.ts +3 -0
  66. package/dist-types/components/core/src/SlotMixin.d.ts.map +1 -1
  67. package/dist-types/components/dialog/src/LionDialog.d.ts +32 -0
  68. package/dist-types/components/dialog/src/LionDialog.d.ts.map +1 -1
  69. package/dist-types/components/dialog/test/lion-dialog.test.d.ts.map +1 -1
  70. package/dist-types/components/dialog/test-helpers/test-router.d.ts +2 -0
  71. package/dist-types/components/dialog/test-helpers/test-router.d.ts.map +1 -0
  72. package/dist-types/components/form-core/src/FormatMixin.d.ts +1 -1
  73. package/dist-types/components/form-core/src/FormatMixin.d.ts.map +1 -1
  74. package/dist-types/components/form-core/src/choice-group/ChoiceInputMixin.d.ts.map +1 -1
  75. package/dist-types/components/form-core/test-suites/FormatMixin.suite.d.ts.map +1 -1
  76. package/dist-types/components/form-core/types/FormatMixinTypes.d.ts +3 -2
  77. package/dist-types/components/form-core/types/FormatMixinTypes.d.ts.map +1 -1
  78. package/dist-types/components/form-integrations/test/dialog-integrations.test.d.ts.map +1 -1
  79. package/dist-types/components/input-amount/src/parsers.d.ts +2 -2
  80. package/dist-types/components/input-amount/src/parsers.d.ts.map +1 -1
  81. package/dist-types/components/input-amount/test/lion-input-amount.test.d.ts.map +1 -1
  82. package/dist-types/components/input-tel-dropdown/src/LionInputTelDropdown.d.ts +1 -1
  83. package/dist-types/components/localize/src/number/parseNumber.d.ts.map +1 -1
  84. package/dist-types/components/localize/types/LocalizeMixinTypes.d.ts +3 -2
  85. package/dist-types/components/localize/types/LocalizeMixinTypes.d.ts.map +1 -1
  86. package/dist-types/components/overlays/src/OverlayController.d.ts +5 -0
  87. package/dist-types/components/overlays/src/OverlayController.d.ts.map +1 -1
  88. package/dist-types/components/overlays/src/OverlayMixin.d.ts.map +1 -1
  89. package/dist-types/components/overlays/test-suites/OverlayMixin.suite.d.ts +4 -4
  90. package/dist-types/components/overlays/test-suites/OverlayMixin.suite.d.ts.map +1 -1
  91. package/dist-types/components/overlays/types/ArrowMixinTypes.d.ts +2 -2
  92. package/dist-types/components/overlays/types/ArrowMixinTypes.d.ts.map +1 -1
  93. package/dist-types/components/overlays/types/OverlayConfig.d.ts +8 -6
  94. package/dist-types/components/overlays/types/OverlayConfig.d.ts.map +1 -1
  95. package/dist-types/components/select-rich/src/LionSelectRich.d.ts +2 -1
  96. package/dist-types/components/select-rich/src/LionSelectRich.d.ts.map +1 -1
  97. package/dist-types/components/select-rich/test/lion-select-rich.test.d.ts.map +1 -1
  98. package/dist-types/tsconfig.tsbuildinfo +1 -1
  99. package/docs/components/checkbox-group/api-table.md +2 -2
  100. package/docs/components/checkbox-group/overview.md +2 -2
  101. package/docs/components/collapsible/overview.md +1 -1
  102. package/docs/components/combobox/api-table.md +1 -0
  103. package/docs/components/combobox/overview.md +1 -1
  104. package/docs/components/combobox/use-cases.md +1 -1
  105. package/docs/components/dialog/api-table.md +6 -3
  106. package/docs/components/dialog/overview.md +1 -1
  107. package/docs/components/dialog/use-cases.md +32 -1
  108. package/docs/components/fieldset/overview.md +5 -5
  109. package/docs/components/form/overview.md +3 -3
  110. package/docs/components/form/use-cases.md +2 -2
  111. package/docs/components/icon/use-cases.md +1 -1
  112. package/docs/components/input/api-table.md +1 -1
  113. package/docs/components/input/overview.md +1 -1
  114. package/docs/components/input-amount/api-table.md +1 -1
  115. package/docs/components/input-amount/overview.md +3 -3
  116. package/docs/components/input-date/api-table.md +1 -1
  117. package/docs/components/input-date/overview.md +3 -3
  118. package/docs/components/input-datepicker/api-table.md +2 -1
  119. package/docs/components/input-datepicker/overview.md +5 -5
  120. package/docs/components/input-email/api-table.md +1 -1
  121. package/docs/components/input-email/overview.md +2 -2
  122. package/docs/components/input-file/api-table.md +1 -1
  123. package/docs/components/input-file/overview.md +1 -1
  124. package/docs/components/input-iban/api-table.md +1 -1
  125. package/docs/components/input-iban/overview.md +2 -2
  126. package/docs/components/input-range/api-table.md +1 -1
  127. package/docs/components/input-range/overview.md +2 -2
  128. package/docs/components/input-stepper/api-table.md +1 -1
  129. package/docs/components/input-stepper/overview.md +1 -1
  130. package/docs/components/input-tel/api-table.md +1 -1
  131. package/docs/components/input-tel/overview.md +1 -1
  132. package/docs/components/input-tel/use-cases.md +6 -6
  133. package/docs/components/input-tel-dropdown/api-table.md +1 -1
  134. package/docs/components/input-tel-dropdown/overview.md +1 -1
  135. package/docs/components/listbox/api-table.md +1 -1
  136. package/docs/components/listbox/use-cases.md +1 -1
  137. package/docs/components/radio-group/api-table.md +1 -1
  138. package/docs/components/radio-group/overview.md +3 -3
  139. package/docs/components/select/api-table.md +1 -1
  140. package/docs/components/select/use-cases.md +1 -1
  141. package/docs/components/select-rich/api-table.md +1 -0
  142. package/docs/components/select-rich/use-cases.md +1 -1
  143. package/docs/components/switch/api-table.md +1 -1
  144. package/docs/components/tabs/examples.md +1 -1
  145. package/docs/components/textarea/api-table.md +1 -1
  146. package/docs/components/tooltip/api-table.md +1 -0
  147. package/docs/fundamentals/index.md +4 -4
  148. package/docs/fundamentals/node-tools/providence-analytics/overview.md +5 -5
  149. package/docs/fundamentals/node-tools/publish-docs/overview.md +3 -3
  150. package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +2 -2
  151. package/docs/fundamentals/rationales/accessibility.md +1 -1
  152. package/docs/fundamentals/systems/core/SlotMixin.md +1 -1
  153. package/docs/fundamentals/systems/core/overview.md +1 -1
  154. package/docs/fundamentals/systems/form/api-table.md +1 -1
  155. package/docs/fundamentals/systems/form/formatting-and-parsing.md +4 -4
  156. package/docs/fundamentals/systems/form/model-value.md +1 -1
  157. package/docs/fundamentals/systems/form/overview.md +28 -28
  158. package/docs/fundamentals/systems/form/validate.md +2 -2
  159. package/docs/fundamentals/systems/localize/overview.md +4 -4
  160. package/docs/fundamentals/systems/overlays/api-table.md +35 -34
  161. package/docs/fundamentals/systems/overlays/configuration.md +32 -2
  162. package/docs/fundamentals/systems/overlays/overview.md +5 -5
  163. package/docs/fundamentals/systems/overlays/use-cases.md +2 -2
  164. package/docs/fundamentals/tools/helpers/overview.md +1 -1
  165. package/docs/fundamentals/tools/singleton-manager/overview.md +4 -4
  166. package/docs/guides/how-to/create-a-custom-field.md +5 -5
  167. package/docs/guides/how-to/create-a-form.md +10 -9
  168. package/docs/guides/how-to/extend-a-native-input.md +2 -2
  169. package/docs/guides/index.md +8 -8
  170. package/docs/guides/principles/index.md +5 -5
  171. package/docs/guides/principles/styling.md +1 -1
  172. package/package.json +1 -1
@@ -149,7 +149,11 @@ export class LionButton extends DisabledWithTabIndexMixin(LitElement) {
149
149
  super.updated(changedProperties);
150
150
 
151
151
  if (changedProperties.has('disabled')) {
152
- this.setAttribute('aria-disabled', `${this.disabled}`); // create mixin if we need it in more places
152
+ if (this.disabled) {
153
+ this.setAttribute('aria-disabled', 'true');
154
+ } else if (this.getAttribute('aria-disabled') !== null) {
155
+ this.removeAttribute('aria-disabled');
156
+ }
153
157
  }
154
158
  }
155
159
 
@@ -40,7 +40,7 @@ export function LionButtonSuite({ klass = LionButton } = {}) {
40
40
  el.disabled = false;
41
41
  await el.updateComplete;
42
42
  expect(el.getAttribute('tabindex')).to.equal('0');
43
- expect(el.getAttribute('aria-disabled')).to.equal('false');
43
+ expect(el.getAttribute('aria-disabled')).to.not.exist;
44
44
  expect(el.hasAttribute('disabled')).to.equal(false);
45
45
 
46
46
  el.disabled = true;
@@ -658,25 +658,16 @@ export class LionCalendar extends LocalizeMixin(LitElement) {
658
658
  day.ariaCurrent = day.today ? 'date' : undefined;
659
659
  day.disabledInfo = '';
660
660
 
661
+ if (day.disabled) {
662
+ day.disabledInfo = `${this.msgLit(`lion-calendar:defaultDisabledDate`)}`;
663
+ }
661
664
  if (this.minDate && normalizeDateTime(day.date) < normalizeDateTime(this.minDate)) {
662
665
  day.disabled = true;
663
- // TODO: turn this into a translated string
664
- day.disabledInfo = `This date is unavailable. Earliest date to select is ${
665
- this.__getSelectableDateRange().earliestSelectableDate
666
- }. Please select another date.`;
666
+ day.disabledInfo = `${this.msgLit(`lion-calendar:beforeDisabledDate`, { params: this.__getSelectableDateRange().earliestSelectableDate })}`;
667
667
  }
668
-
669
668
  if (this.maxDate && normalizeDateTime(day.date) > normalizeDateTime(this.maxDate)) {
670
669
  day.disabled = true;
671
- // TODO: turn this into a translated string
672
- day.disabledInfo = `This date is unavailable. Latest date to select is ${
673
- this.__getSelectableDateRange().latestSelectableDate
674
- }. Please select another date.`;
675
- }
676
-
677
- if (day.disabled) {
678
- // TODO: turn this into a translated string
679
- day.disabledInfo = `This date is unavailable. Please select another date`;
670
+ day.disabledInfo = `${this.msgLit(`lion-calendar:afterDisabledDate`, { params: this.__getSelectableDateRange().latestSelectableDate })}`;
680
671
  }
681
672
 
682
673
  return this.dayPreprocessor(day);
@@ -896,6 +896,94 @@ describe('<lion-calendar>', () => {
896
896
  'Next year, December 2001',
897
897
  );
898
898
  });
899
+
900
+ it('disables a date with disableDates function provide a correct message', async () => {
901
+ /** @param {Date} d */
902
+ const disable15th = d => d.getDate() === 15;
903
+ const el = await fixture(html`
904
+ <lion-calendar
905
+ .selectedDate="${new Date('2000/12/01')}"
906
+ .disableDates=${disable15th}
907
+ ></lion-calendar>
908
+ `);
909
+ const elObj = new CalendarObject(el);
910
+ expect(elObj.getDayObj(15).isDisabled).to.equal(true);
911
+ expect(elObj.getDayObj(15).el).dom.to.equal(`
912
+ <div
913
+ class="calendar__day-button"
914
+ aria-disabled="true"
915
+ role="button"
916
+ tabindex="-1"
917
+ aria-pressed="false"
918
+ past=""
919
+ current-month="">
920
+ <span class="calendar__day-button__text">
921
+ 15
922
+ </span>
923
+ <span class="u-sr-only">
924
+ December 2000 Friday This date is unavailable. Please choose another date.
925
+ </span>
926
+ </div>
927
+ `);
928
+ });
929
+
930
+ it('disables days before "minDate" property provide a correct message', async () => {
931
+ const el = await fixture(html`
932
+ <lion-calendar
933
+ .selectedDate="${new Date('2000/12/31')}"
934
+ .minDate="${new Date('2000/12/09')}"
935
+ >
936
+ </lion-calendar>
937
+ `);
938
+ const elObj = new CalendarObject(el);
939
+ expect(elObj.getDayObj(1).isDisabled).to.equal(true);
940
+ expect(elObj.getDayObj(1).el).dom.to.equal(`
941
+ <div
942
+ class="calendar__day-button"
943
+ aria-disabled="true"
944
+ role="button"
945
+ tabindex="-1"
946
+ aria-pressed="false"
947
+ past=""
948
+ current-month="">
949
+ <span class="calendar__day-button__text">
950
+ 1
951
+ </span>
952
+ <span class="u-sr-only">
953
+ December 2000 Friday This date is unavailable. Earliest available date is 9 December 2000. Please choose another date.
954
+ </span>
955
+ </div>
956
+ `);
957
+ });
958
+
959
+ it('disables days after "maxDate" property provide a correct message', async () => {
960
+ const el = await fixture(html`
961
+ <lion-calendar
962
+ .selectedDate="${new Date('2000/12/31')}"
963
+ .maxDate="${new Date('2000/12/09')}"
964
+ >
965
+ </lion-calendar>
966
+ `);
967
+ const elObj = new CalendarObject(el);
968
+ expect(elObj.getDayObj(30).isDisabled).to.equal(true);
969
+ expect(elObj.getDayObj(30).el).dom.to.equal(`
970
+ <div
971
+ class="calendar__day-button"
972
+ aria-disabled="true"
973
+ role="button"
974
+ tabindex="-1"
975
+ aria-pressed="false"
976
+ past=""
977
+ current-month="">
978
+ <span class="calendar__day-button__text">
979
+ 30
980
+ </span>
981
+ <span class="u-sr-only">
982
+ December 2000 Saturday This date is unavailable. Latest available date is 9 December 2000. Please choose another date.
983
+ </span>
984
+ </div>
985
+ `);
986
+ });
899
987
  });
900
988
  });
901
989
  });
@@ -3,4 +3,9 @@ export default {
3
3
  previousMonth: 'Предишен месец',
4
4
  nextFullYear: 'Следващ година',
5
5
  previousFullYear: 'Предишен година',
6
+ defaultDisabledDate: 'Тази дата не е налична. Моля, изберете друга дата.',
7
+ beforeDisabledDate:
8
+ 'Тази дата не е налична. Най-ранната налична да е {params}. Моля, изберете друга дата.',
9
+ afterDisabledDate:
10
+ 'Тази дата не е налична. Най-късната налична дата е {params}. Моля, изберете друга дата.',
6
11
  };
@@ -3,4 +3,9 @@ export default {
3
3
  previousMonth: 'Předchozí měsíc',
4
4
  nextFullYear: 'Příští rok',
5
5
  previousFullYear: 'Předchozí rok',
6
+ defaultDisabledDate: 'Toto datum není k dispozici. Vyberte jiné datum.',
7
+ beforeDisabledDate:
8
+ 'Toto datum není k dispozici. Nejbližší dostupné datum je {params}. Vyberte jiné datum.',
9
+ afterDisabledDate:
10
+ 'Toto datum není k dispozici. Poslední dostupné datum je {params}. Vyberte jiné datum.',
6
11
  };
@@ -3,4 +3,9 @@ export default {
3
3
  previousMonth: 'Vorheriger Monat',
4
4
  nextFullYear: 'Nächstes Jahr',
5
5
  previousFullYear: 'Vorheriges Jahr',
6
+ defaultDisabledDate: 'Dieses Datum ist nicht verfügbar. Bitte wählen Sie ein anderes Datum aus.',
7
+ beforeDisabledDate:
8
+ 'Dieses Datum ist nicht verfügbar. Das früheste verfügbare Datum ist {params}. Bitte wählen Sie ein anderes Datum aus.',
9
+ afterDisabledDate:
10
+ 'Dieses Datum ist nicht verfügbar. Das späteste verfügbare Datum ist {params}. Bitte wählen Sie ein anderes Datum aus.',
6
11
  };
@@ -3,4 +3,9 @@ export default {
3
3
  previousMonth: 'Previous month',
4
4
  nextFullYear: 'Next year',
5
5
  previousFullYear: 'Previous year',
6
+ defaultDisabledDate: 'This date is unavailable. Please choose another date.',
7
+ beforeDisabledDate:
8
+ 'This date is unavailable. Earliest available date is {params}. Please choose another date.',
9
+ afterDisabledDate:
10
+ 'This date is unavailable. Latest available date is {params}. Please choose another date.',
6
11
  };
@@ -3,4 +3,9 @@ export default {
3
3
  previousMonth: 'Mes anterior',
4
4
  nextFullYear: 'Año siguiente',
5
5
  previousFullYear: 'Año anterior',
6
+ defaultDisabledDate: 'Esta fecha no está disponible. Elija otra.',
7
+ beforeDisabledDate:
8
+ 'Esta fecha no está disponible. La fecha más próxima disponible es {params}. Elija otra.',
9
+ afterDisabledDate:
10
+ 'Esta fecha no está disponible. La fecha más lejana disponible es {params}. Elija otra.',
6
11
  };
@@ -3,4 +3,9 @@ export default {
3
3
  previousMonth: 'Mois précédent',
4
4
  nextFullYear: 'An prochain',
5
5
  previousFullYear: 'An précédent',
6
+ defaultDisabledDate: "Cette date n'est pas disponible. Veuillez choisir une autre date.",
7
+ beforeDisabledDate:
8
+ "Cette date n'est pas disponible. La prochaine date disponible est la suivante : {params}. Veuillez choisir une autre date.",
9
+ afterDisabledDate:
10
+ "Cette date n'est pas disponible. La dernière date disponible est la suivante : {params}. Veuillez choisir une autre date.",
6
11
  };
@@ -3,4 +3,9 @@ export default {
3
3
  previousMonth: 'Előző hónap',
4
4
  nextFullYear: 'Következő év',
5
5
  previousFullYear: 'Előző év',
6
+ defaultDisabledDate: 'Ez a dátum nem választható. Válasszon másik dátumot.',
7
+ beforeDisabledDate:
8
+ 'Ez a dátum nem választható. A legkorábbi elérhető dátum {params}. Válasszon másik dátumot.',
9
+ afterDisabledDate:
10
+ 'Ez a dátum nem választható. A legkésőbbi elérhető dátum {params}. Válasszon másik dátumot.',
6
11
  };
@@ -3,4 +3,9 @@ export default {
3
3
  previousMonth: 'Mese precedente',
4
4
  nextFullYear: 'Anno successivo',
5
5
  previousFullYear: 'Anno precedente',
6
+ defaultDisabledDate: "Questa data non è disponibile. Scegline un'altra.",
7
+ beforeDisabledDate:
8
+ "Questa data non è disponibile. La prima data disponibile è {params}. Scegline un'altra.",
9
+ afterDisabledDate:
10
+ "Questa data non è disponibile. L'ultima data disponibile è {params}. Scegline un'altra.",
6
11
  };
@@ -3,4 +3,9 @@ export default {
3
3
  previousMonth: 'Vorige maand',
4
4
  nextFullYear: 'Volgend jaar',
5
5
  previousFullYear: 'Vorig jaar',
6
+ defaultDisabledDate: 'Deze datum is niet beschikbaar. Kies een andere datum.',
7
+ beforeDisabledDate:
8
+ 'Deze datum is niet beschikbaar. Vroegste beschikbare datum is {params}. Kies een andere datum.',
9
+ afterDisabledDate:
10
+ 'Deze datum is niet beschikbaar. Laatste beschikbare datum is {params}. Kies een andere datum.',
6
11
  };
@@ -3,4 +3,9 @@ export default {
3
3
  previousMonth: 'Poprzedni miesiąc',
4
4
  nextFullYear: 'Następny rok',
5
5
  previousFullYear: 'Poprzedni rok',
6
+ defaultDisabledDate: 'Ta data jest niedostępna. Wybierz inną datę.',
7
+ beforeDisabledDate:
8
+ 'Ta data jest niedostępna. Najwcześniejsza dostępna data to {params}. Wybierz inną datę.',
9
+ afterDisabledDate:
10
+ 'Ta data jest niedostępna. Najpóźniejsza dostępna data to {params}. Wybierz inną datę.',
6
11
  };
@@ -3,4 +3,9 @@ export default {
3
3
  previousMonth: 'Luna anterioară',
4
4
  nextFullYear: 'An viitoare',
5
5
  previousFullYear: 'An anterioară',
6
+ defaultDisabledDate: 'Această dată nu este disponibilă. Vă rugăm să alegeți altă dată.',
7
+ beforeDisabledDate:
8
+ 'Această dată nu este disponibilă. Cea mai apropiată dată disponibilă este {params}. Vă rugăm să alegeți altă dată.',
9
+ afterDisabledDate:
10
+ 'Această dată nu este disponibilă. Ultima dată disponibilă este {params}. Vă rugăm să alegeți altă dată.',
6
11
  };
@@ -3,4 +3,9 @@ export default {
3
3
  previousMonth: 'Предыдущий месяц',
4
4
  nextFullYear: 'Следующий год',
5
5
  previousFullYear: 'Предыдущий год',
6
+ defaultDisabledDate: 'Эта дата недоступна. Выберите другую дату.',
7
+ beforeDisabledDate:
8
+ 'Эта дата недоступна. Самая ранняя доступная дата — {params}. Выберите другую дату.',
9
+ afterDisabledDate:
10
+ 'Эта дата недоступна. Самая поздняя доступная дата — {params}. Выберите другую дату.',
6
11
  };
@@ -3,4 +3,9 @@ export default {
3
3
  previousMonth: 'Predchádzajúci mesiac',
4
4
  nextFullYear: 'Nasledujúci rok',
5
5
  previousFullYear: 'Predchádzajúci rok',
6
+ defaultDisabledDate: 'Tento dátum nie je k dispozícii. Vyberte iný dátum.',
7
+ beforeDisabledDate:
8
+ 'Tento dátum nie je k dispozícii. Najbližší možný dátum je {params}. Vyberte iný dátum.',
9
+ afterDisabledDate:
10
+ 'Tento dátum nie je k dispozícii. Posledný možný dátum je {params}. Vyberte iný dátum.',
6
11
  };
@@ -3,4 +3,7 @@ export default {
3
3
  previousMonth: 'Попередній місяць',
4
4
  nextFullYear: 'Наступний року',
5
5
  previousFullYear: 'Попередній року',
6
+ defaultDisabledDate: 'Ця дата недоступна. Виберіть іншу дату.',
7
+ beforeDisabledDate: 'Ця дата недоступна. Найближча доступна дата {params}. Виберіть іншу дату.',
8
+ afterDisabledDate: 'Ця дата недоступна. Остання доступна дата {params}. Виберіть іншу дату.',
6
9
  };
@@ -3,4 +3,7 @@ export default {
3
3
  previousMonth: '前一个月',
4
4
  nextFullYear: '明一年',
5
5
  previousFullYear: '前一年',
6
+ defaultDisabledDate: '此日期不可选。请选择另一个日期。',
7
+ beforeDisabledDate: '此日期不可选。最早可选日期为 {params}。请选择另一个日期。',
8
+ afterDisabledDate: '此日期不可选。最晚可选日期为 {params}。请选择另一个日期。',
6
9
  };
@@ -229,6 +229,8 @@ describe('lion-combobox', () => {
229
229
  </lion-combobox>
230
230
  `)
231
231
  );
232
+ await el.updateComplete;
233
+
232
234
  const { _inputNode } = getComboboxMembers(el);
233
235
 
234
236
  _inputNode.dispatchEvent(new KeyboardEvent('keyup', { key: 'Escape' }));
@@ -182,6 +182,21 @@ const SlotMixinImplementation = superclass =>
182
182
  // Providing all options breaks Safari: we keep host and creationScope
183
183
  const { creationScope, host } = this.renderOptions;
184
184
  render(template, rerenderTarget, { creationScope, host, renderBefore });
185
+
186
+ // Assume we had this config:
187
+ // `'my-slot': () => ({ template: myBool ? html`<div id=a></div>` : html`<span id=b></span>`, renderAsDirectHostChild: true })`
188
+ // If myBool started as true, <div id=a></div> would be rendered in first render above, a slot would be applied,
189
+ // resulting in <div id=a slot=my-slot></div>
190
+ // However, when myBool changes to false, the <span id=b></span> would be rendered as root instead...
191
+ // We need to make sure that this "replaced root" gets the slot applied as well => <span id=b slot=my-slot></span>
192
+ const isRerenderingRootOfTemplate =
193
+ renderAsDirectHostChild &&
194
+ renderBefore.previousElementSibling &&
195
+ !renderBefore.previousElementSibling.slot;
196
+
197
+ if (isRerenderingRootOfTemplate) {
198
+ renderBefore.previousElementSibling.slot = slotName;
199
+ }
185
200
  }
186
201
 
187
202
  /**
@@ -140,7 +140,7 @@ describe('ScopedElementsMixin', () => {
140
140
  }
141
141
  customElements.define('scoped-elements-host-no-reg-2', ScopedElementsHostNoReg2);
142
142
 
143
- const errorSpy = sinon.spy(console, 'error');
143
+ const errorStub = sinon.stub(console, 'error');
144
144
  /** @type {ScopedElementsHostNoReg2} */ (
145
145
  await fixture(html`<scoped-elements-host-no-reg></scoped-elements-host-no-reg>`)
146
146
  );
@@ -148,7 +148,7 @@ describe('ScopedElementsMixin', () => {
148
148
  await fixture(html`<scoped-elements-host-no-reg-2></scoped-elements-host-no-reg-2>`)
149
149
  );
150
150
 
151
- expect(errorSpy.args[0][0]).to.equal(
151
+ expect(errorStub.args[0][0]).to.equal(
152
152
  [
153
153
  'You are trying to re-register the "scoped-elements-child-no-reg" custom element with a different class via ScopedElementsMixin.',
154
154
  'This is only possible with a CustomElementRegistry.',
@@ -158,7 +158,7 @@ describe('ScopedElementsMixin', () => {
158
158
  'For more details you can visit https://open-wc.org/docs/development/scoped-elements/',
159
159
  ].join('\n'),
160
160
  );
161
- errorSpy.restore();
161
+ errorStub.restore();
162
162
  });
163
163
  });
164
164
  });
@@ -345,6 +345,56 @@ describe('SlotMixin', () => {
345
345
  expect(isActiveElement(el._focusableNode._buttonNode, { deep: true })).to.be.true;
346
346
  });
347
347
 
348
+ it('allows for switching template root in slot as a direct child', async () => {
349
+ const tagName = defineCE(
350
+ // @ts-expect-error
351
+ class extends SlotMixin(LitElement) {
352
+ static properties = { isSwitched: Boolean };
353
+
354
+ constructor() {
355
+ super();
356
+ this.isSwitched = false;
357
+ }
358
+
359
+ get slots() {
360
+ return {
361
+ ...super.slots,
362
+ 'my-root-switcher-node': () => ({
363
+ template: this.isSwitched
364
+ ? html`<div id="is-switched"></div>`
365
+ : html`<span id="is-not-switched"> </span> `,
366
+ renderAsDirectHostChild: true,
367
+ }),
368
+ };
369
+ }
370
+
371
+ render() {
372
+ return html`<slot name="my-root-switcher-node"></slot>`;
373
+ }
374
+
375
+ get _myRootSwitcherNode() {
376
+ return /** @type HTMLSpanElement */ (
377
+ Array.from(this.children).find(elm => elm.slot === 'my-root-switcher-node')
378
+ );
379
+ }
380
+ },
381
+ );
382
+ const el = /** @type {* & SlotHost} */ (await fixture(`<${tagName}></${tagName}>`));
383
+
384
+ expect(el._myRootSwitcherNode.id).to.equal('is-not-switched');
385
+ expect(el.innerHTML).to.equal(
386
+ `<!--_start_slot_my-root-switcher-node_--><!----><span id="is-not-switched" slot="my-root-switcher-node"> </span> <!--_end_slot_my-root-switcher-node_-->`,
387
+ );
388
+
389
+ el.isSwitched = true;
390
+ await el.updateComplete;
391
+
392
+ expect(el._myRootSwitcherNode.id).to.equal('is-switched');
393
+ expect(el.innerHTML).to.equal(
394
+ `<!--_start_slot_my-root-switcher-node_--><!----><div id="is-switched" slot="my-root-switcher-node"></div><!--_end_slot_my-root-switcher-node_-->`,
395
+ );
396
+ });
397
+
348
398
  describe('firstRenderOnConnected (for backwards compatibility)', () => {
349
399
  it('does render on connected when firstRenderOnConnected:true', async () => {
350
400
  // Start with elem that does not render on connectedCallback
@@ -2,6 +2,18 @@ import { html, LitElement } from 'lit';
2
2
  import { OverlayMixin, withModalDialogConfig } from '@lion/ui/overlays.js';
3
3
 
4
4
  export class LionDialog extends OverlayMixin(LitElement) {
5
+ /** @type {any} */
6
+ static get properties() {
7
+ return {
8
+ isAlertDialog: { type: Boolean, attribute: 'is-alert-dialog' },
9
+ };
10
+ }
11
+
12
+ constructor() {
13
+ super();
14
+ this.isAlertDialog = false;
15
+ }
16
+
5
17
  /**
6
18
  * @protected
7
19
  */
@@ -9,6 +21,7 @@ export class LionDialog extends OverlayMixin(LitElement) {
9
21
  _defineOverlayConfig() {
10
22
  return {
11
23
  ...withModalDialogConfig(),
24
+ isAlertDialog: this.isAlertDialog,
12
25
  };
13
26
  }
14
27
 
@@ -2,6 +2,7 @@
2
2
  import { expect, fixture as _fixture, html, unsafeStatic, aTimeout } from '@open-wc/testing';
3
3
  import { runOverlayMixinSuite } from '../../overlays/test-suites/OverlayMixin.suite.js';
4
4
  import { isActiveElement } from '../../core/test-helpers/isActiveElement.js';
5
+ import '../test-helpers/test-router.js';
5
6
  import '@lion/ui/define/lion-dialog.js';
6
7
 
7
8
  /**
@@ -169,6 +170,27 @@ describe('lion-dialog', () => {
169
170
  });
170
171
 
171
172
  describe('Accessibility', () => {
173
+ it('passes a11y audit', async () => {
174
+ const el = await fixture(html`
175
+ <lion-dialog>
176
+ <button slot="invoker">Invoker</button>
177
+ <div slot="content" class="dialog" aria-label="Dialog">Hey there</div>
178
+ </lion-dialog>
179
+ `);
180
+ await expect(el).to.be.accessible();
181
+ });
182
+
183
+ it('passes a11y audit when opened', async () => {
184
+ const el = await fixture(html`
185
+ <lion-dialog opened>
186
+ <button slot="invoker">Invoker</button>
187
+ <div slot="content" class="dialog" aria-label="Dialog">Hey there</div>
188
+ </lion-dialog>
189
+ `);
190
+ // error expected since we put role="none" on the dialog itself, which is valid but not recognized by Axe
191
+ await expect(el).to.be.accessible({ ignoredRules: ['aria-allowed-role'] });
192
+ });
193
+
172
194
  it('does not add [aria-expanded] to invoker button', async () => {
173
195
  const el = await fixture(
174
196
  html` <lion-dialog>
@@ -186,5 +208,93 @@ describe('lion-dialog', () => {
186
208
  await aTimeout(0);
187
209
  expect(invokerButton.getAttribute('aria-expanded')).to.equal(null);
188
210
  });
211
+
212
+ it('has role="dialog" by default', async () => {
213
+ const el = await fixture(
214
+ html` <lion-dialog>
215
+ <div slot="content" class="dialog">Hey there</div>
216
+ <button slot="invoker">Popup button</button>
217
+ </lion-dialog>`,
218
+ );
219
+ const contentNode = /** @type {HTMLElement} */ (el.querySelector('[slot="content"]'));
220
+
221
+ expect(contentNode.getAttribute('role')).to.equal('dialog');
222
+ });
223
+
224
+ it('has role="alertdialog" by when "is-alert-dialog" is set', async () => {
225
+ const el = await fixture(
226
+ html` <lion-dialog is-alert-dialog>
227
+ <div slot="content" class="dialog">Hey there</div>
228
+ <button slot="invoker">Popup button</button>
229
+ </lion-dialog>`,
230
+ );
231
+ const contentNode = /** @type {HTMLElement} */ (el.querySelector('[slot="content"]'));
232
+
233
+ expect(contentNode.getAttribute('role')).to.equal('alertdialog');
234
+ });
235
+
236
+ it('passes a11y audit when opened and role="alertdialog"', async () => {
237
+ const el = await fixture(html`
238
+ <lion-dialog opened is-alert-dialog>
239
+ <button slot="invoker">Invoker</button>
240
+ <div slot="content" class="dialog" aria-label="Dialog">Hey there</div>
241
+ </lion-dialog>
242
+ `);
243
+ // error expected since we put role="none" on the dialog itself, which is valid but not recognized by Axe
244
+ await expect(el).to.be.accessible({ ignoredRules: ['aria-allowed-role'] });
245
+ });
246
+ });
247
+
248
+ describe('Edge cases', () => {
249
+ it('does not lose click event handler when was detached and reattached', async () => {
250
+ const el = await fixture(html`
251
+ <test-router
252
+ .routingMap="${{
253
+ a: html`
254
+ <lion-dialog>
255
+ <div slot="content" class="dialog">Hey there</div>
256
+ <button slot="invoker">Popup button</button>
257
+ </lion-dialog>
258
+ `,
259
+ b: html` <div>B</div> `,
260
+ }}"
261
+ path="a"
262
+ ></test-router>
263
+ `);
264
+
265
+ const getDialog = () =>
266
+ /** @type {LionDialog} */ (el.shadowRoot?.querySelector('lion-dialog'));
267
+ const getInvoker = () =>
268
+ /** @type {HTMLElement} */ (getDialog().querySelector('[slot="invoker"]'));
269
+
270
+ getInvoker().click();
271
+ const dialog = getDialog();
272
+ // @ts-expect-error [allow-protected-in-tests]
273
+ await dialog._overlayCtrl._showComplete;
274
+ expect(dialog.opened).to.be.true;
275
+
276
+ dialog.close();
277
+ // @ts-expect-error [allow-protected-in-tests]
278
+ await dialog._overlayCtrl._hideComplete;
279
+ expect(dialog.opened).to.be.false;
280
+
281
+ const buttonA = /** @type {HTMLElement} */ (el.shadowRoot?.querySelector('#path-a'));
282
+ const buttonB = /** @type {HTMLElement} */ (el.shadowRoot?.querySelector('#path-b'));
283
+
284
+ buttonB.click();
285
+ await el.updateComplete;
286
+ buttonA.click();
287
+ await el.updateComplete;
288
+ await el.updateComplete;
289
+
290
+ getInvoker().click();
291
+
292
+ const dialogAfterRouteChange = getDialog();
293
+ // @ts-expect-error [allow-protected-in-tests]
294
+ expect(dialogAfterRouteChange._overlayCtrl).not.to.be.undefined;
295
+ // @ts-expect-error [allow-protected-in-tests]
296
+ await dialogAfterRouteChange._overlayCtrl._showComplete;
297
+ expect(dialogAfterRouteChange.opened).to.be.true;
298
+ });
189
299
  });
190
300
  });
@@ -0,0 +1,43 @@
1
+ import { html, LitElement } from 'lit';
2
+
3
+ class TestRouter extends LitElement {
4
+ static properties = {
5
+ routingMap: {
6
+ type: Object,
7
+ attribute: false,
8
+ },
9
+ path: { type: String },
10
+ };
11
+
12
+ constructor() {
13
+ super();
14
+
15
+ /** @type {{ [path: string]: HTMLElement }} */
16
+ this.routingMap = {};
17
+ /** @type {string} */
18
+ this.path = '';
19
+ }
20
+
21
+ render() {
22
+ return html`
23
+ <div>
24
+ <div id="selector">
25
+ ${Object.keys(this.routingMap).map(
26
+ path =>
27
+ html`<button
28
+ id="path-${path}"
29
+ @click="${() => {
30
+ this.path = path;
31
+ }}"
32
+ >
33
+ ${path}
34
+ </button>`,
35
+ )}
36
+ </div>
37
+ <div id="view">${this.routingMap[this.path]}</div>
38
+ </div>
39
+ `;
40
+ }
41
+ }
42
+
43
+ customElements.define('test-router', TestRouter);