@lion/ui 0.10.0 → 0.11.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.
- package/components/button/src/LionButton.js +5 -1
- package/components/button/test-suites/LionButton.suite.js +1 -1
- package/components/calendar/src/LionCalendar.js +5 -14
- package/components/calendar/test/lion-calendar.test.js +88 -0
- package/components/calendar/translations/bg.js +5 -0
- package/components/calendar/translations/cs.js +5 -0
- package/components/calendar/translations/de.js +5 -0
- package/components/calendar/translations/en.js +5 -0
- package/components/calendar/translations/es.js +5 -0
- package/components/calendar/translations/fr.js +5 -0
- package/components/calendar/translations/hu.js +5 -0
- package/components/calendar/translations/it.js +5 -0
- package/components/calendar/translations/nl.js +5 -0
- package/components/calendar/translations/pl.js +5 -0
- package/components/calendar/translations/ro.js +5 -0
- package/components/calendar/translations/ru.js +5 -0
- package/components/calendar/translations/sk.js +5 -0
- package/components/calendar/translations/uk.js +3 -0
- package/components/calendar/translations/zh.js +3 -0
- package/components/core/src/SlotMixin.js +15 -0
- package/components/core/test/SlotMixin.test.js +50 -0
- package/components/dialog/src/LionDialog.js +13 -0
- package/components/dialog/test/lion-dialog.test.js +56 -0
- package/components/form-core/src/choice-group/ChoiceInputMixin.js +3 -1
- package/components/input-amount/test/lion-input-amount.test.js +48 -1
- package/components/input-amount/test/parsers.test.js +1 -1
- package/components/input-tel-dropdown/src/LionInputTelDropdown.js +1 -1
- package/components/localize/src/number/parseNumber.js +21 -12
- package/components/localize/test/number/parseNumber.test.js +1 -1
- package/components/overlays/src/OverlayController.js +17 -1
- package/components/overlays/test/OverlayController.test.js +29 -0
- package/components/overlays/types/OverlayConfig.ts +4 -2
- package/components/select-rich/src/LionSelectRich.js +17 -1
- package/components/select-rich/test/lion-select-rich-interaction.test.js +139 -20
- package/components/validate-messages/translations/pl.js +4 -4
- package/custom-elements.json +38 -13
- package/dist-types/components/button/src/LionButton.d.ts.map +1 -1
- package/dist-types/components/calendar/src/LionCalendar.d.ts.map +1 -1
- package/dist-types/components/calendar/translations/bg.d.ts +3 -0
- package/dist-types/components/calendar/translations/cs.d.ts +3 -0
- package/dist-types/components/calendar/translations/de.d.ts +3 -0
- package/dist-types/components/calendar/translations/en.d.ts +3 -0
- package/dist-types/components/calendar/translations/es.d.ts +3 -0
- package/dist-types/components/calendar/translations/fr.d.ts +3 -0
- package/dist-types/components/calendar/translations/hu.d.ts +3 -0
- package/dist-types/components/calendar/translations/it.d.ts +3 -0
- package/dist-types/components/calendar/translations/nl.d.ts +3 -0
- package/dist-types/components/calendar/translations/pl.d.ts +3 -0
- package/dist-types/components/calendar/translations/ro.d.ts +3 -0
- package/dist-types/components/calendar/translations/ru.d.ts +3 -0
- package/dist-types/components/calendar/translations/sk.d.ts +3 -0
- package/dist-types/components/calendar/translations/uk.d.ts +3 -0
- package/dist-types/components/calendar/translations/zh.d.ts +3 -0
- package/dist-types/components/core/src/SlotMixin.d.ts.map +1 -1
- package/dist-types/components/dialog/src/LionDialog.d.ts +32 -0
- package/dist-types/components/dialog/src/LionDialog.d.ts.map +1 -1
- package/dist-types/components/form-core/src/choice-group/ChoiceInputMixin.d.ts.map +1 -1
- package/dist-types/components/input-tel-dropdown/src/LionInputTelDropdown.d.ts +1 -1
- package/dist-types/components/localize/src/number/parseNumber.d.ts.map +1 -1
- package/dist-types/components/overlays/src/OverlayController.d.ts +5 -0
- package/dist-types/components/overlays/src/OverlayController.d.ts.map +1 -1
- package/dist-types/components/overlays/types/OverlayConfig.d.ts +4 -2
- package/dist-types/components/overlays/types/OverlayConfig.d.ts.map +1 -1
- package/dist-types/components/select-rich/src/LionSelectRich.d.ts +1 -0
- package/dist-types/components/select-rich/src/LionSelectRich.d.ts.map +1 -1
- package/dist-types/tsconfig.tsbuildinfo +1 -1
- package/docs/components/checkbox-group/overview.md +2 -2
- package/docs/components/collapsible/overview.md +1 -1
- package/docs/components/combobox/overview.md +1 -1
- package/docs/components/combobox/use-cases.md +1 -1
- package/docs/components/dialog/api-table.md +5 -3
- package/docs/components/dialog/overview.md +1 -1
- package/docs/components/dialog/use-cases.md +32 -1
- package/docs/components/fieldset/overview.md +5 -5
- package/docs/components/form/overview.md +3 -3
- package/docs/components/form/use-cases.md +2 -2
- package/docs/components/icon/use-cases.md +1 -1
- package/docs/components/input/overview.md +1 -1
- package/docs/components/input-amount/overview.md +3 -3
- package/docs/components/input-date/overview.md +3 -3
- package/docs/components/input-datepicker/overview.md +5 -5
- package/docs/components/input-email/overview.md +2 -2
- package/docs/components/input-file/overview.md +1 -1
- package/docs/components/input-iban/overview.md +2 -2
- package/docs/components/input-range/overview.md +2 -2
- package/docs/components/input-stepper/overview.md +1 -1
- package/docs/components/input-tel/overview.md +1 -1
- package/docs/components/input-tel/use-cases.md +6 -6
- package/docs/components/input-tel-dropdown/overview.md +1 -1
- package/docs/components/listbox/use-cases.md +1 -1
- package/docs/components/radio-group/overview.md +3 -3
- package/docs/components/select/use-cases.md +1 -1
- package/docs/components/select-rich/use-cases.md +1 -1
- package/docs/components/tabs/examples.md +1 -1
- package/docs/fundamentals/index.md +4 -4
- package/docs/fundamentals/node-tools/publish-docs/overview.md +3 -3
- package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +2 -2
- package/docs/fundamentals/rationales/accessibility.md +1 -1
- package/docs/fundamentals/systems/core/SlotMixin.md +1 -1
- package/docs/fundamentals/systems/core/overview.md +1 -1
- package/docs/fundamentals/systems/form/formatting-and-parsing.md +4 -4
- package/docs/fundamentals/systems/form/model-value.md +1 -1
- package/docs/fundamentals/systems/form/overview.md +28 -28
- package/docs/fundamentals/systems/form/validate.md +2 -2
- package/docs/fundamentals/systems/localize/overview.md +4 -4
- package/docs/fundamentals/systems/overlays/api-table.md +35 -34
- package/docs/fundamentals/systems/overlays/configuration.md +32 -2
- package/docs/fundamentals/systems/overlays/overview.md +5 -5
- package/docs/fundamentals/systems/overlays/use-cases.md +2 -2
- package/docs/fundamentals/tools/helpers/overview.md +1 -1
- package/docs/fundamentals/tools/singleton-manager/overview.md +4 -4
- package/docs/guides/how-to/create-a-custom-field.md +5 -5
- package/docs/guides/how-to/create-a-form.md +10 -9
- package/docs/guides/how-to/extend-a-native-input.md +2 -2
- package/docs/guides/index.md +8 -8
- package/docs/guides/principles/index.md +5 -5
- package/docs/guides/principles/styling.md +1 -1
- 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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
};
|
|
@@ -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
|
/**
|
|
@@ -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
|
|
|
@@ -170,6 +170,27 @@ describe('lion-dialog', () => {
|
|
|
170
170
|
});
|
|
171
171
|
|
|
172
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
|
+
|
|
173
194
|
it('does not add [aria-expanded] to invoker button', async () => {
|
|
174
195
|
const el = await fixture(
|
|
175
196
|
html` <lion-dialog>
|
|
@@ -187,6 +208,41 @@ describe('lion-dialog', () => {
|
|
|
187
208
|
await aTimeout(0);
|
|
188
209
|
expect(invokerButton.getAttribute('aria-expanded')).to.equal(null);
|
|
189
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
|
+
});
|
|
190
246
|
});
|
|
191
247
|
|
|
192
248
|
describe('Edge cases', () => {
|
|
@@ -171,7 +171,9 @@ const ChoiceInputMixinImplementation = superclass =>
|
|
|
171
171
|
render() {
|
|
172
172
|
return html`
|
|
173
173
|
<slot name="input"></slot>
|
|
174
|
-
<div class="choice-field__graphic-container"
|
|
174
|
+
<div class="choice-field__graphic-container" aria-hidden="true">
|
|
175
|
+
${this._choiceGraphicTemplate()}
|
|
176
|
+
</div>
|
|
175
177
|
<div class="choice-field__label">
|
|
176
178
|
<slot name="label"></slot>
|
|
177
179
|
</div>
|
|
@@ -131,7 +131,7 @@ describe('<lion-input-amount>', () => {
|
|
|
131
131
|
expect(_inputNode.value).to.equal('100.12');
|
|
132
132
|
});
|
|
133
133
|
|
|
134
|
-
it('
|
|
134
|
+
it('formats with locale when formatOptions.mode is "user-edited" and value has three decimal places', async () => {
|
|
135
135
|
const el = /** @type {LionInputAmount} */ (
|
|
136
136
|
await fixture(
|
|
137
137
|
html`<lion-input-amount
|
|
@@ -154,6 +154,14 @@ describe('<lion-input-amount>', () => {
|
|
|
154
154
|
expect(el.modelValue).to.equal(123456);
|
|
155
155
|
expect(el.formattedValue).to.equal('123.456,00');
|
|
156
156
|
|
|
157
|
+
// When editing an already existing value, we interpet the separators as they are.
|
|
158
|
+
// However, only when the decimal places are 3 or more.
|
|
159
|
+
mimicUserInput(el, '123.456.00');
|
|
160
|
+
expect(parserSpy.lastCall.args[1]?.mode).to.equal('user-edited');
|
|
161
|
+
expect(formatterSpy.lastCall.args[1]?.mode).to.equal('user-edited');
|
|
162
|
+
expect(el.modelValue).to.equal(123456);
|
|
163
|
+
expect(el.formattedValue).to.equal('123.456,00');
|
|
164
|
+
|
|
157
165
|
// Formatting should only affect values that should be formatted / parsed as a consequence of user input.
|
|
158
166
|
// When a user finished editing, the default should be restored.
|
|
159
167
|
// (think of a programmatically set modelValue, that should behave idempotent, regardless of when it is set)
|
|
@@ -162,6 +170,45 @@ describe('<lion-input-amount>', () => {
|
|
|
162
170
|
expect(formatterSpy.lastCall.args[1]?.mode).to.equal('auto');
|
|
163
171
|
});
|
|
164
172
|
|
|
173
|
+
it('formats with heuristic when formatOptions.mode is "user-edited" and value has two decimal places', async () => {
|
|
174
|
+
const el = /** @type {LionInputAmount} */ (
|
|
175
|
+
await fixture(
|
|
176
|
+
html`<lion-input-amount
|
|
177
|
+
.modelValue=${64}
|
|
178
|
+
currency="EUR"
|
|
179
|
+
.formatOptions="${{ locale: 'en-GB' }}"
|
|
180
|
+
></lion-input-amount>`,
|
|
181
|
+
)
|
|
182
|
+
);
|
|
183
|
+
const parserSpy = sinon.spy(el, 'parser');
|
|
184
|
+
const formatterSpy = sinon.spy(el, 'formatter');
|
|
185
|
+
|
|
186
|
+
expect(el.formattedValue).to.equal('64.00');
|
|
187
|
+
// @ts-expect-error [allow-protected] in test
|
|
188
|
+
expect(el._inputNode.value).to.equal('64.00');
|
|
189
|
+
|
|
190
|
+
// When editing an already existing value, we interpret the separators based on decimal places when there's 1 or
|
|
191
|
+
// less separator in total (otherwise we would accidentally multiply or divide by 1000)
|
|
192
|
+
mimicUserInput(el, '64,00');
|
|
193
|
+
expect(parserSpy.lastCall.args[1]?.mode).to.equal('user-edited');
|
|
194
|
+
expect(formatterSpy.lastCall.args[1]?.mode).to.equal('user-edited');
|
|
195
|
+
expect(el.modelValue).to.equal(64);
|
|
196
|
+
expect(el.formattedValue).to.equal('64.00');
|
|
197
|
+
|
|
198
|
+
mimicUserInput(el, '64,0');
|
|
199
|
+
expect(parserSpy.lastCall.args[1]?.mode).to.equal('user-edited');
|
|
200
|
+
expect(formatterSpy.lastCall.args[1]?.mode).to.equal('user-edited');
|
|
201
|
+
expect(el.modelValue).to.equal(64);
|
|
202
|
+
expect(el.formattedValue).to.equal('64.00');
|
|
203
|
+
|
|
204
|
+
// Formatting should only affect values that should be formatted / parsed as a consequence of user input.
|
|
205
|
+
// When a user finished editing, the default should be restored.
|
|
206
|
+
// (think of a programmatically set modelValue, that should behave idempotent, regardless of when it is set)
|
|
207
|
+
el.modelValue = 1234;
|
|
208
|
+
expect(el.formattedValue).to.equal('1,234.00');
|
|
209
|
+
expect(formatterSpy.lastCall.args[1]?.mode).to.equal('auto');
|
|
210
|
+
});
|
|
211
|
+
|
|
165
212
|
it('sets inputmode attribute to decimal', async () => {
|
|
166
213
|
const el = /** @type {LionInputAmount} */ (
|
|
167
214
|
await fixture(`<lion-input-amount></lion-input-amount>`)
|
|
@@ -69,6 +69,6 @@ describe('parseAmount()', async () => {
|
|
|
69
69
|
expect(parseAmount('123.456,78', { mode: 'auto' })).to.equal(123456.78);
|
|
70
70
|
expect(
|
|
71
71
|
parseAmount('123.456,78', { mode: 'user-edited', viewValueStates: ['formatted'] }),
|
|
72
|
-
).to.equal(
|
|
72
|
+
).to.equal(123456.78);
|
|
73
73
|
});
|
|
74
74
|
});
|
|
@@ -20,25 +20,34 @@ import { getDecimalSeparator } from './getDecimalSeparator.js';
|
|
|
20
20
|
* @return {string} unparseable|withLocale|heuristic
|
|
21
21
|
*/
|
|
22
22
|
function getParseMode(value, { mode = 'auto', viewValueStates } = {}) {
|
|
23
|
-
const
|
|
23
|
+
const separatorsRe = /[., ]/g;
|
|
24
|
+
const separators = value.match(separatorsRe) || [];
|
|
25
|
+
// @ts-expect-error [wait-for-platform-types]
|
|
26
|
+
const decimalPlaces = (value.split(separatorsRe) || []).at(-1).length;
|
|
27
|
+
const isCurViewFormattedAndUserIsEditing =
|
|
28
|
+
viewValueStates?.includes('formatted') && mode === 'user-edited';
|
|
24
29
|
|
|
25
30
|
// When a user edits an existing value, we already formatted it with a certain locale.
|
|
26
|
-
// For best UX, we stick with this locale
|
|
27
|
-
|
|
28
|
-
|
|
31
|
+
// For best UX, we stick with this locale. However, we only do this when the user has
|
|
32
|
+
// entered at least 3 decimal places.
|
|
33
|
+
const shouldUseCurLocale = isCurViewFormattedAndUserIsEditing && decimalPlaces > 2;
|
|
29
34
|
|
|
30
|
-
|
|
35
|
+
const shouldUseLocale =
|
|
36
|
+
shouldUseCurLocale ||
|
|
37
|
+
!separators.length ||
|
|
38
|
+
(mode === 'auto' && separators.length === 1 && decimalPlaces >= 3);
|
|
39
|
+
if (shouldUseLocale) {
|
|
31
40
|
return 'withLocale';
|
|
32
41
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
if (separators.length === 1 || separators[0] !== separators[separators.length - 1]) {
|
|
42
|
+
|
|
43
|
+
const shouldUseHeuristic =
|
|
44
|
+
(isCurViewFormattedAndUserIsEditing && decimalPlaces <= 2) ||
|
|
45
|
+
separators.length === 1 ||
|
|
46
|
+
separators[0] !== separators[separators.length - 1];
|
|
47
|
+
if (shouldUseHeuristic) {
|
|
40
48
|
return 'heuristic';
|
|
41
49
|
}
|
|
50
|
+
|
|
42
51
|
return 'unparseable';
|
|
43
52
|
}
|
|
44
53
|
|
|
@@ -82,7 +82,7 @@ describe('parseNumber()', () => {
|
|
|
82
82
|
expect(parseNumber('123.456,78', { mode: 'auto' })).to.equal(123456.78);
|
|
83
83
|
expect(
|
|
84
84
|
parseNumber('123.456,78', { mode: 'user-edited', viewValueStates: ['formatted'] }),
|
|
85
|
-
).to.equal(
|
|
85
|
+
).to.equal(123456.78);
|
|
86
86
|
});
|
|
87
87
|
|
|
88
88
|
it('detects separators unparseable when there are 2 same ones e.g. 1.234.56', () => {
|