@lion/ui 0.1.5 → 0.2.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.
- package/components/accordion/src/LionAccordion.js +2 -2
- package/components/accordion/test/lion-accordion.test.js +31 -0
- package/components/calendar/src/LionCalendar.js +13 -3
- package/components/combobox/src/LionCombobox.js +107 -14
- package/components/combobox/src/validators.js +18 -0
- package/components/combobox/test/lion-combobox.test.js +286 -184
- package/components/combobox/test/validators.test.js +62 -0
- package/components/combobox/test-helpers/combobox-helpers.js +125 -0
- package/components/form-core/types/choice-group/ChoiceGroupMixinTypes.ts +4 -3
- package/components/input-datepicker/src/LionInputDatepicker.js +9 -1
- package/components/input-iban/translations/de.js +1 -1
- package/components/listbox/src/ListboxMixin.js +6 -0
- package/components/listbox/test-suites/ListboxMixin.suite.js +15 -8
- package/components/overlays/src/OverlayController.js +27 -7
- package/components/overlays/test/OverlayController.test.js +16 -2
- package/components/switch/src/LionSwitch.js +0 -3
- package/components/switch/src/LionSwitchButton.js +14 -1
- package/components/switch/test/lion-switch-button.test.js +15 -1
- package/components/switch/test/lion-switch.test.js +21 -6
- package/components/validate-messages/src/loadDefaultFeedbackMessagesNoSideEffects.js +11 -8
- package/components/validate-messages/translations/bg.js +4 -0
- package/components/validate-messages/translations/cs.js +2 -0
- package/components/validate-messages/translations/de.js +4 -0
- package/components/validate-messages/translations/en.js +2 -0
- package/components/validate-messages/translations/es.js +4 -0
- package/components/validate-messages/translations/fr.js +4 -0
- package/components/validate-messages/translations/hu.js +2 -0
- package/components/validate-messages/translations/it.js +4 -0
- package/components/validate-messages/translations/nl.js +4 -0
- package/components/validate-messages/translations/pl.js +2 -0
- package/components/validate-messages/translations/ro.js +4 -0
- package/components/validate-messages/translations/ru.js +4 -0
- package/components/validate-messages/translations/sk.js +2 -0
- package/components/validate-messages/translations/uk.js +4 -0
- package/components/validate-messages/translations/zh.js +2 -0
- package/custom-elements.json +1365 -34
- package/dist-types/components/calendar/src/LionCalendar.d.ts +2 -0
- package/dist-types/components/calendar/src/LionCalendar.d.ts.map +1 -1
- package/dist-types/components/combobox/src/LionCombobox.d.ts +37 -13
- package/dist-types/components/combobox/src/LionCombobox.d.ts.map +1 -1
- package/dist-types/components/combobox/src/validators.d.ts +13 -0
- package/dist-types/components/combobox/src/validators.d.ts.map +1 -0
- package/dist-types/components/combobox/test/lion-combobox.test.d.ts +0 -2
- package/dist-types/components/combobox/test/lion-combobox.test.d.ts.map +1 -1
- package/dist-types/components/combobox/test/validators.test.d.ts +2 -0
- package/dist-types/components/combobox/test/validators.test.d.ts.map +1 -0
- package/dist-types/components/combobox/test-helpers/combobox-helpers.d.ts +41 -0
- package/dist-types/components/combobox/test-helpers/combobox-helpers.d.ts.map +1 -0
- package/dist-types/components/form-core/types/choice-group/ChoiceGroupMixinTypes.d.ts +4 -3
- package/dist-types/components/form-core/types/choice-group/ChoiceGroupMixinTypes.d.ts.map +1 -1
- package/dist-types/components/input-datepicker/src/LionInputDatepicker.d.ts +4 -0
- package/dist-types/components/input-datepicker/src/LionInputDatepicker.d.ts.map +1 -1
- package/dist-types/components/listbox/src/ListboxMixin.d.ts.map +1 -1
- package/dist-types/components/listbox/test-suites/ListboxMixin.suite.d.ts.map +1 -1
- package/dist-types/components/overlays/src/OverlayController.d.ts +2 -0
- package/dist-types/components/overlays/src/OverlayController.d.ts.map +1 -1
- package/dist-types/components/switch/src/LionSwitch.d.ts +0 -1
- package/dist-types/components/switch/src/LionSwitch.d.ts.map +1 -1
- package/dist-types/components/switch/src/LionSwitchButton.d.ts +3 -0
- package/dist-types/components/switch/src/LionSwitchButton.d.ts.map +1 -1
- package/dist-types/components/switch/test/lion-switch.test.d.ts +1 -1
- package/dist-types/components/switch/test/lion-switch.test.d.ts.map +1 -1
- package/dist-types/components/validate-messages/src/loadDefaultFeedbackMessagesNoSideEffects.d.ts.map +1 -1
- package/dist-types/components/validate-messages/translations/bg-BG.d.ts +2 -0
- package/dist-types/components/validate-messages/translations/bg.d.ts +3 -0
- package/dist-types/components/validate-messages/translations/cs-CZ.d.ts +2 -0
- package/dist-types/components/validate-messages/translations/cs.d.ts +3 -0
- package/dist-types/components/validate-messages/translations/de-DE.d.ts +2 -0
- package/dist-types/components/validate-messages/translations/de.d.ts +3 -0
- package/dist-types/components/validate-messages/translations/en-AU.d.ts +2 -0
- package/dist-types/components/validate-messages/translations/en-GB.d.ts +2 -0
- package/dist-types/components/validate-messages/translations/en-PH.d.ts +2 -0
- package/dist-types/components/validate-messages/translations/en-US.d.ts +2 -0
- package/dist-types/components/validate-messages/translations/en.d.ts +3 -0
- package/dist-types/components/validate-messages/translations/es-ES.d.ts +2 -0
- package/dist-types/components/validate-messages/translations/es.d.ts +3 -0
- package/dist-types/components/validate-messages/translations/fr-BE.d.ts +2 -0
- package/dist-types/components/validate-messages/translations/fr-FR.d.ts +2 -0
- package/dist-types/components/validate-messages/translations/fr.d.ts +3 -0
- package/dist-types/components/validate-messages/translations/hu-HU.d.ts +2 -0
- package/dist-types/components/validate-messages/translations/hu.d.ts +3 -0
- package/dist-types/components/validate-messages/translations/it-IT.d.ts +2 -0
- package/dist-types/components/validate-messages/translations/it.d.ts +3 -0
- package/dist-types/components/validate-messages/translations/nl-BE.d.ts +2 -0
- package/dist-types/components/validate-messages/translations/nl-NL.d.ts +2 -0
- package/dist-types/components/validate-messages/translations/nl.d.ts +3 -0
- package/dist-types/components/validate-messages/translations/pl-PL.d.ts +2 -0
- package/dist-types/components/validate-messages/translations/pl.d.ts +3 -0
- package/dist-types/components/validate-messages/translations/ro-RO.d.ts +2 -0
- package/dist-types/components/validate-messages/translations/ro.d.ts +3 -0
- package/dist-types/components/validate-messages/translations/ru-RU.d.ts +2 -0
- package/dist-types/components/validate-messages/translations/ru.d.ts +3 -0
- package/dist-types/components/validate-messages/translations/sk-SK.d.ts +2 -0
- package/dist-types/components/validate-messages/translations/sk.d.ts +3 -0
- package/dist-types/components/validate-messages/translations/uk-UA.d.ts +2 -0
- package/dist-types/components/validate-messages/translations/uk.d.ts +3 -0
- package/dist-types/components/validate-messages/translations/zh.d.ts +3 -0
- package/dist-types/exports/combobox-test-helpers.d.ts +2 -0
- package/dist-types/exports/combobox-test-helpers.d.ts.map +1 -0
- package/dist-types/exports/combobox.d.ts +1 -0
- package/dist-types/tsconfig.tsbuildinfo +1 -1
- package/docs/components/checkbox-group/overview.md +2 -2
- package/docs/components/checkbox-group/use-cases.md +1 -0
- package/docs/components/collapsible/overview.md +1 -1
- package/docs/components/combobox/overview.md +12 -2
- package/docs/components/combobox/use-cases.md +36 -1
- package/docs/components/dialog/overview.md +1 -1
- package/docs/components/fieldset/overview.md +5 -5
- package/docs/components/form/overview.md +3 -3
- 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-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/radio-group/overview.md +3 -3
- package/docs/components/select-rich/overview.md +7 -10
- package/docs/components/select-rich/use-cases.md +54 -69
- package/docs/components/tabs/examples.md +1 -1
- package/docs/fundamentals/index.md +4 -4
- package/docs/fundamentals/node-tools/providence-analytics/LocalConfiguration.md +1 -1
- package/docs/fundamentals/node-tools/providence-analytics/QueryResult.md +1 -1
- package/docs/fundamentals/node-tools/providence-analytics/analyzer.md +1 -1
- package/docs/fundamentals/node-tools/providence-analytics/dashboard.md +1 -1
- package/docs/fundamentals/node-tools/providence-analytics/overview.md +3 -3
- 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/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 +1 -1
- package/docs/fundamentals/systems/localize/overview.md +4 -4
- package/docs/fundamentals/systems/overlays/configuration.md +2 -2
- package/docs/fundamentals/systems/overlays/overview.md +5 -10
- package/docs/fundamentals/systems/overlays/rationale.md +3 -6
- 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/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/exports/combobox-test-helpers.js +1 -0
- package/exports/combobox.js +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { getListboxMembers } from '@lion/ui/listbox-test-helpers.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {import('@lion/ui/combobox.js').LionCombobox} LionCombobox
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @param { LionCombobox } el
|
|
9
|
+
*/
|
|
10
|
+
export function getComboboxMembers(el) {
|
|
11
|
+
const obj = getListboxMembers(el);
|
|
12
|
+
return {
|
|
13
|
+
...obj,
|
|
14
|
+
...{
|
|
15
|
+
// @ts-ignore [allow-protected] in test
|
|
16
|
+
_invokerNode: el._invokerNode,
|
|
17
|
+
// @ts-ignore [allow-protected] in test
|
|
18
|
+
_overlayCtrl: el._overlayCtrl,
|
|
19
|
+
// @ts-ignore [allow-protected] in test
|
|
20
|
+
_comboboxNode: el._comboboxNode,
|
|
21
|
+
// @ts-ignore [allow-protected] in test
|
|
22
|
+
_inputNode: el._inputNode,
|
|
23
|
+
// @ts-ignore [allow-protected] in test
|
|
24
|
+
_listboxNode: el._listboxNode,
|
|
25
|
+
// @ts-ignore [allow-protected] in test
|
|
26
|
+
_selectionDisplayNode: el._selectionDisplayNode,
|
|
27
|
+
// @ts-ignore [allow-protected] in test
|
|
28
|
+
_activeDescendantOwnerNode: el._activeDescendantOwnerNode,
|
|
29
|
+
// @ts-ignore [allow-protected] in test
|
|
30
|
+
_ariaVersion: el._ariaVersion,
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @param {LionCombobox} el
|
|
37
|
+
* @param {string} value
|
|
38
|
+
*/
|
|
39
|
+
// TODO: add keys that actually make sense...
|
|
40
|
+
export function mimicUserTyping(el, value) {
|
|
41
|
+
const { _inputNode } = getComboboxMembers(el);
|
|
42
|
+
_inputNode.dispatchEvent(new Event('focusin', { bubbles: true }));
|
|
43
|
+
// eslint-disable-next-line no-param-reassign
|
|
44
|
+
_inputNode.value = value;
|
|
45
|
+
_inputNode.dispatchEvent(new Event('input', { bubbles: true, composed: true }));
|
|
46
|
+
_inputNode.dispatchEvent(new KeyboardEvent('keyup', { key: value }));
|
|
47
|
+
_inputNode.dispatchEvent(new KeyboardEvent('keydown', { key: value }));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @param {HTMLElement} el
|
|
52
|
+
* @param {string} key
|
|
53
|
+
*/
|
|
54
|
+
export function mimicKeyPress(el, key) {
|
|
55
|
+
el.dispatchEvent(new KeyboardEvent('keydown', { key }));
|
|
56
|
+
el.dispatchEvent(new KeyboardEvent('keyup', { key }));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* @param {LionCombobox} el
|
|
61
|
+
* @param {string[]} values
|
|
62
|
+
*/
|
|
63
|
+
export async function mimicUserTypingAdvanced(el, values) {
|
|
64
|
+
const { _inputNode } = getComboboxMembers(el);
|
|
65
|
+
_inputNode.dispatchEvent(new Event('focusin', { bubbles: true }));
|
|
66
|
+
|
|
67
|
+
for (const key of values) {
|
|
68
|
+
// eslint-disable-next-line no-await-in-loop, no-loop-func
|
|
69
|
+
await new Promise(resolve => {
|
|
70
|
+
const hasSelection = _inputNode.selectionStart !== _inputNode.selectionEnd;
|
|
71
|
+
|
|
72
|
+
if (key === 'Backspace') {
|
|
73
|
+
if (hasSelection) {
|
|
74
|
+
_inputNode.value =
|
|
75
|
+
_inputNode.value.slice(
|
|
76
|
+
0,
|
|
77
|
+
_inputNode.selectionStart ? _inputNode.selectionStart : undefined,
|
|
78
|
+
) +
|
|
79
|
+
_inputNode.value.slice(
|
|
80
|
+
_inputNode.selectionEnd ? _inputNode.selectionEnd : undefined,
|
|
81
|
+
_inputNode.value.length,
|
|
82
|
+
);
|
|
83
|
+
} else {
|
|
84
|
+
_inputNode.value = _inputNode.value.slice(0, -1);
|
|
85
|
+
}
|
|
86
|
+
} else if (hasSelection) {
|
|
87
|
+
_inputNode.value =
|
|
88
|
+
_inputNode.value.slice(
|
|
89
|
+
0,
|
|
90
|
+
_inputNode.selectionStart ? _inputNode.selectionStart : undefined,
|
|
91
|
+
) +
|
|
92
|
+
key +
|
|
93
|
+
_inputNode.value.slice(
|
|
94
|
+
_inputNode.selectionEnd ? _inputNode.selectionEnd : undefined,
|
|
95
|
+
_inputNode.value.length,
|
|
96
|
+
);
|
|
97
|
+
} else {
|
|
98
|
+
_inputNode.value += key;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
mimicKeyPress(_inputNode, key);
|
|
102
|
+
_inputNode.dispatchEvent(new Event('input', { bubbles: true, composed: true }));
|
|
103
|
+
|
|
104
|
+
el.updateComplete.then(() => {
|
|
105
|
+
// @ts-ignore
|
|
106
|
+
resolve();
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* @param {LionCombobox} el
|
|
114
|
+
*/
|
|
115
|
+
export function getFilteredOptionValues(el) {
|
|
116
|
+
const options = el.formElements;
|
|
117
|
+
/**
|
|
118
|
+
* @param {{ style: { display: string; }; }} option
|
|
119
|
+
*/
|
|
120
|
+
const filtered = options.filter(option => option.getAttribute('aria-hidden') !== 'true');
|
|
121
|
+
/**
|
|
122
|
+
* @param {{ value: any; }} option
|
|
123
|
+
*/
|
|
124
|
+
return filtered.map(option => option.value);
|
|
125
|
+
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { Constructor } from '@open-wc/dedupe-mixin';
|
|
2
2
|
import { LitElement } from 'lit';
|
|
3
|
-
import { FormControlHost } from '../FormControlMixinTypes.js';
|
|
4
3
|
import { FormControl } from '../form-group/FormGroupMixinTypes.js';
|
|
5
|
-
import {
|
|
4
|
+
import { FormControlHost } from '../FormControlMixinTypes.js';
|
|
6
5
|
import { InteractionStateHost } from '../InteractionStateMixinTypes.js';
|
|
6
|
+
import { FormRegistrarHost } from '../registration/FormRegistrarMixinTypes.js';
|
|
7
|
+
import { ChoiceInputHost } from './ChoiceInputMixinTypes.js';
|
|
7
8
|
|
|
8
9
|
export declare class ChoiceGroupHost {
|
|
9
10
|
multipleChoice: boolean;
|
|
@@ -26,7 +27,7 @@ export declare class ChoiceGroupHost {
|
|
|
26
27
|
protected _throwWhenInvalidChildModelValue(child: FormControlHost): void;
|
|
27
28
|
protected _isEmpty(): void;
|
|
28
29
|
protected _checkSingleChoiceElements(ev: Event): void;
|
|
29
|
-
protected _getCheckedElements():
|
|
30
|
+
protected _getCheckedElements(): ChoiceInputHost[];
|
|
30
31
|
protected _setCheckedElements(value: any, check: boolean): void;
|
|
31
32
|
protected _onBeforeRepropagateChildrenValues(ev: Event): void;
|
|
32
33
|
|
|
@@ -279,11 +279,19 @@ export class LionInputDatepicker extends ScopedElementsMixin(
|
|
|
279
279
|
aria-label="${this.msgLit('lion-input-datepicker:openDatepickerLabel')}"
|
|
280
280
|
title="${this.msgLit('lion-input-datepicker:openDatepickerLabel')}"
|
|
281
281
|
>
|
|
282
|
-
|
|
282
|
+
${this._invokerIconTemplate()}
|
|
283
283
|
</button>
|
|
284
284
|
`;
|
|
285
285
|
}
|
|
286
286
|
|
|
287
|
+
/**
|
|
288
|
+
* Subclassers can replace this with their custom extension invoker icon
|
|
289
|
+
*/
|
|
290
|
+
// eslint-disable-next-line class-methods-use-this
|
|
291
|
+
_invokerIconTemplate() {
|
|
292
|
+
return html`📅`;
|
|
293
|
+
}
|
|
294
|
+
|
|
287
295
|
_setupOverlayCtrl() {
|
|
288
296
|
super._setupOverlayCtrl();
|
|
289
297
|
|
|
@@ -635,6 +635,9 @@ const ListboxMixinImplementation = superclass =>
|
|
|
635
635
|
}
|
|
636
636
|
break;
|
|
637
637
|
case 'ArrowLeft':
|
|
638
|
+
if (this._listboxReceivesNoFocus) {
|
|
639
|
+
return;
|
|
640
|
+
}
|
|
638
641
|
ev.preventDefault();
|
|
639
642
|
if (this.orientation === 'horizontal') {
|
|
640
643
|
this.activeIndex = this._getPreviousEnabledOption(this.activeIndex);
|
|
@@ -647,6 +650,9 @@ const ListboxMixinImplementation = superclass =>
|
|
|
647
650
|
}
|
|
648
651
|
break;
|
|
649
652
|
case 'ArrowRight':
|
|
653
|
+
if (this._listboxReceivesNoFocus) {
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
650
656
|
ev.preventDefault();
|
|
651
657
|
if (this.orientation === 'horizontal') {
|
|
652
658
|
this.activeIndex = this._getNextEnabledOption(this.activeIndex);
|
|
@@ -393,7 +393,7 @@ export function runListboxMixinSuite(customConfig = {}) {
|
|
|
393
393
|
`);
|
|
394
394
|
await el.updateComplete;
|
|
395
395
|
await el.updateComplete; // need 2 awaits as overlay.show is an async function
|
|
396
|
-
|
|
396
|
+
// for more info about why we need the ignoreRules, see: https://lion-web.netlify.app/fundamentals/systems/overlays/rationale/#considerations
|
|
397
397
|
await expect(el).to.be.accessible({ ignoredRules: ['aria-allowed-role'] });
|
|
398
398
|
});
|
|
399
399
|
|
|
@@ -405,6 +405,7 @@ export function runListboxMixinSuite(customConfig = {}) {
|
|
|
405
405
|
<${optionTag} .choiceValue=${20}>Item 2</${optionTag}>
|
|
406
406
|
</${tag}>
|
|
407
407
|
`);
|
|
408
|
+
// for more info about why we need the ignoreRules, see: https://lion-web.netlify.app/fundamentals/systems/overlays/rationale/#considerations
|
|
408
409
|
await expect(el).to.be.accessible({ ignoredRules: ['aria-allowed-role'] });
|
|
409
410
|
});
|
|
410
411
|
|
|
@@ -861,6 +862,7 @@ export function runListboxMixinSuite(customConfig = {}) {
|
|
|
861
862
|
mimicKeyPress(_listboxNode, 'End');
|
|
862
863
|
expect(el.activeIndex).to.equal(3);
|
|
863
864
|
});
|
|
865
|
+
|
|
864
866
|
it('navigates through open lists with [ArrowDown] [ArrowUp] keys activates the option', async () => {
|
|
865
867
|
const el = /** @type {LionListbox} */ (
|
|
866
868
|
await fixture(html`
|
|
@@ -936,7 +938,7 @@ export function runListboxMixinSuite(customConfig = {}) {
|
|
|
936
938
|
it('uses [ArrowLeft] and [ArrowRight] keys when "horizontal"', async () => {
|
|
937
939
|
const el = /** @type {LionListbox} */ (
|
|
938
940
|
await fixture(html`
|
|
939
|
-
<${tag} opened name="foo" orientation="horizontal" autocomplete="none" show-all-on-empty>
|
|
941
|
+
<${tag} ._listboxReceivesNoFocus="${false}" opened name="foo" orientation="horizontal" autocomplete="none" show-all-on-empty>
|
|
940
942
|
<${optionTag} .choiceValue="${'Artichoke'}">Artichoke</${optionTag}>
|
|
941
943
|
<${optionTag} .choiceValue="${'Chard'}">Chard</${optionTag}>
|
|
942
944
|
</${tag}>
|
|
@@ -948,15 +950,12 @@ export function runListboxMixinSuite(customConfig = {}) {
|
|
|
948
950
|
|
|
949
951
|
// Normalize for suite tests
|
|
950
952
|
el.activeIndex = 0;
|
|
951
|
-
|
|
952
953
|
await el.updateComplete;
|
|
953
954
|
|
|
954
955
|
mimicKeyPress(_listboxNode, 'ArrowRight');
|
|
955
|
-
|
|
956
956
|
expect(el.activeIndex).to.equal(1);
|
|
957
957
|
|
|
958
958
|
mimicKeyPress(_listboxNode, 'ArrowLeft');
|
|
959
|
-
|
|
960
959
|
expect(el.activeIndex).to.equal(0);
|
|
961
960
|
|
|
962
961
|
// No response to vertical arrows...
|
|
@@ -965,7 +964,14 @@ export function runListboxMixinSuite(customConfig = {}) {
|
|
|
965
964
|
|
|
966
965
|
el.activeIndex = 1;
|
|
967
966
|
mimicKeyPress(_listboxNode, 'ArrowUp');
|
|
967
|
+
expect(el.activeIndex).to.equal(1);
|
|
968
968
|
|
|
969
|
+
// @ts-ignore allow protected member access in test
|
|
970
|
+
el._listboxReceivesNoFocus = true;
|
|
971
|
+
mimicKeyPress(_listboxNode, 'ArrowLeft');
|
|
972
|
+
expect(el.activeIndex).to.equal(1);
|
|
973
|
+
|
|
974
|
+
mimicKeyPress(_listboxNode, 'ArrowRight');
|
|
969
975
|
expect(el.activeIndex).to.equal(1);
|
|
970
976
|
});
|
|
971
977
|
|
|
@@ -1141,6 +1147,7 @@ export function runListboxMixinSuite(customConfig = {}) {
|
|
|
1141
1147
|
expect(el.checkedIndex).to.equal(0);
|
|
1142
1148
|
expectOnlyGivenOneOptionToBeChecked(options, 0);
|
|
1143
1149
|
});
|
|
1150
|
+
|
|
1144
1151
|
it('navigates through list with [ArrowLeft] [ArrowRight] keys when horizontal: activates and checks the option', async () => {
|
|
1145
1152
|
/**
|
|
1146
1153
|
* @param {LionOption[]} options
|
|
@@ -1157,7 +1164,7 @@ export function runListboxMixinSuite(customConfig = {}) {
|
|
|
1157
1164
|
}
|
|
1158
1165
|
const el = /** @type {LionListbox} */ (
|
|
1159
1166
|
await fixture(html`
|
|
1160
|
-
<${tag} opened selection-follows-focus orientation="horizontal" autocomplete="none" show-all-on-empty>
|
|
1167
|
+
<${tag} ._listboxReceivesNoFocus="${false}" opened selection-follows-focus orientation="horizontal" autocomplete="none" show-all-on-empty>
|
|
1161
1168
|
<${optionTag} .choiceValue=${10}>Item 1</${optionTag}>
|
|
1162
1169
|
<${optionTag} .choiceValue=${20}>Item 2</${optionTag}>
|
|
1163
1170
|
<${optionTag} .choiceValue=${30}>Item 3</${optionTag}>
|
|
@@ -1453,7 +1460,7 @@ export function runListboxMixinSuite(customConfig = {}) {
|
|
|
1453
1460
|
)}
|
|
1454
1461
|
</${tag}>
|
|
1455
1462
|
`);
|
|
1456
|
-
el.
|
|
1463
|
+
el.setCheckedIndex(0);
|
|
1457
1464
|
expect(el.modelValue).to.deep.equal({
|
|
1458
1465
|
type: 'mastercard',
|
|
1459
1466
|
label: 'Master Card',
|
|
@@ -1461,7 +1468,7 @@ export function runListboxMixinSuite(customConfig = {}) {
|
|
|
1461
1468
|
active: true,
|
|
1462
1469
|
});
|
|
1463
1470
|
|
|
1464
|
-
el.
|
|
1471
|
+
el.setCheckedIndex(1);
|
|
1465
1472
|
expect(el.modelValue).to.deep.equal({
|
|
1466
1473
|
type: 'visacard',
|
|
1467
1474
|
label: 'Visa Card',
|
|
@@ -124,6 +124,9 @@ export class OverlayController extends EventTarget {
|
|
|
124
124
|
/** @private */
|
|
125
125
|
this.__sharedConfig = config;
|
|
126
126
|
|
|
127
|
+
/** @private */
|
|
128
|
+
this.__activeElementRightBeforeHide = null;
|
|
129
|
+
|
|
127
130
|
/** @type {OverlayConfig} */
|
|
128
131
|
this.config = {};
|
|
129
132
|
|
|
@@ -570,12 +573,18 @@ export class OverlayController extends EventTarget {
|
|
|
570
573
|
// We use a dialog for its visual capabilities: it renders to the top layer.
|
|
571
574
|
// A11y will depend on the type of overlay and is arranged on contentNode level.
|
|
572
575
|
// Also see: https://www.scottohara.me/blog/2019/03/05/open-dialog.html
|
|
576
|
+
//
|
|
577
|
+
// The role="dialog" is set on the contentNode (or another role), so role="none"
|
|
578
|
+
// is valid here, although AXE complains about this setup.
|
|
579
|
+
// For now we need to add `ignoredRules: ['aria-allowed-role']` in your AXE tests.
|
|
580
|
+
// see: https://lion-web.netlify.app/fundamentals/systems/overlays/rationale/#considerations
|
|
573
581
|
wrappingDialogElement.setAttribute('role', 'none');
|
|
574
582
|
wrappingDialogElement.setAttribute('data-overlay-outer-wrapper', '');
|
|
575
583
|
// N.B. position: fixed is needed to escape out of 'overflow: hidden'
|
|
576
584
|
// We give a high z-index for non-modal dialogs, so that we at least win from all siblings of our
|
|
577
585
|
// parent stacking context
|
|
578
|
-
|
|
586
|
+
// padding reset so we don't get a weird dialog visual square showing up
|
|
587
|
+
wrappingDialogElement.style.cssText = `display:none; z-index: ${this.config.zIndex}; padding: 0;`;
|
|
579
588
|
this.__wrappingDialogNode = wrappingDialogElement;
|
|
580
589
|
|
|
581
590
|
/**
|
|
@@ -722,7 +731,7 @@ export class OverlayController extends EventTarget {
|
|
|
722
731
|
const event = new CustomEvent('before-show', { cancelable: true });
|
|
723
732
|
this.dispatchEvent(event);
|
|
724
733
|
if (!event.defaultPrevented) {
|
|
725
|
-
if (this.__wrappingDialogNode instanceof HTMLDialogElement) {
|
|
734
|
+
if ('HTMLDialogElement' in window && this.__wrappingDialogNode instanceof HTMLDialogElement) {
|
|
726
735
|
this.__wrappingDialogNode.open = true;
|
|
727
736
|
}
|
|
728
737
|
// @ts-ignore
|
|
@@ -827,6 +836,14 @@ export class OverlayController extends EventTarget {
|
|
|
827
836
|
this._hideResolve = resolve;
|
|
828
837
|
});
|
|
829
838
|
|
|
839
|
+
// save the current activeElement so we know if the user set focus to another element than the invoker of the dialog
|
|
840
|
+
// while the dialog was open.
|
|
841
|
+
// We need this in the _restoreFocus method to determine if we should focus this.elementToFocusAfterHide when the
|
|
842
|
+
// dialog is closed or keep focus on the element that the user deliberately gave focus
|
|
843
|
+
this.__activeElementRightBeforeHide = /** @type {ShadowRoot} */ (
|
|
844
|
+
this.contentNode.getRootNode()
|
|
845
|
+
).activeElement;
|
|
846
|
+
|
|
830
847
|
if (this.manager) {
|
|
831
848
|
this.manager.hide(this);
|
|
832
849
|
}
|
|
@@ -844,9 +861,10 @@ export class OverlayController extends EventTarget {
|
|
|
844
861
|
contentNode: this.contentNode,
|
|
845
862
|
});
|
|
846
863
|
|
|
847
|
-
if (this.__wrappingDialogNode instanceof HTMLDialogElement) {
|
|
864
|
+
if ('HTMLDialogElement' in window && this.__wrappingDialogNode instanceof HTMLDialogElement) {
|
|
848
865
|
this.__wrappingDialogNode.close();
|
|
849
866
|
}
|
|
867
|
+
|
|
850
868
|
// @ts-ignore
|
|
851
869
|
this.__wrappingDialogNode.style.display = 'none';
|
|
852
870
|
this._handleFeatures({ phase: 'hide' });
|
|
@@ -906,18 +924,20 @@ export class OverlayController extends EventTarget {
|
|
|
906
924
|
/** @protected */
|
|
907
925
|
_restoreFocus() {
|
|
908
926
|
// We only are allowed to move focus if we (still) 'own' the active element.
|
|
909
|
-
// Otherwise we assume the 'outside world' has purposefully taken over
|
|
910
|
-
const { activeElement } = /** @type {ShadowRoot} */ (this.contentNode.getRootNode());
|
|
927
|
+
// Otherwise, we assume the 'outside world' has purposefully taken over
|
|
911
928
|
const weStillOwnActiveElement =
|
|
912
|
-
|
|
929
|
+
this.__activeElementRightBeforeHide instanceof HTMLElement &&
|
|
930
|
+
this.contentNode.contains(this.__activeElementRightBeforeHide);
|
|
931
|
+
|
|
913
932
|
if (!weStillOwnActiveElement) {
|
|
914
933
|
return;
|
|
915
934
|
}
|
|
916
935
|
|
|
917
936
|
if (this.elementToFocusAfterHide) {
|
|
918
937
|
this.elementToFocusAfterHide.focus();
|
|
938
|
+
this.elementToFocusAfterHide.scrollIntoView({ block: 'center' });
|
|
919
939
|
} else {
|
|
920
|
-
|
|
940
|
+
/** @type {HTMLElement} */ (this.__activeElementRightBeforeHide).blur();
|
|
921
941
|
}
|
|
922
942
|
}
|
|
923
943
|
|
|
@@ -21,7 +21,7 @@ import { createShadowHost } from '../test-helpers/createShadowHost.js';
|
|
|
21
21
|
* @typedef {import('../types/OverlayConfig.js').ViewportPlacement} ViewportPlacement
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
-
const wrappingDialogNodeStyle = 'display: none; z-index: 9999;';
|
|
24
|
+
const wrappingDialogNodeStyle = 'display: none; z-index: 9999; padding: 0px;';
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* Make sure that all browsers serialize html in a similar way
|
|
@@ -46,6 +46,19 @@ function getProtectedMembers(overlayControllerEl) {
|
|
|
46
46
|
};
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
/**
|
|
50
|
+
* @param {HTMLElement} element
|
|
51
|
+
* */
|
|
52
|
+
const isInViewport = element => {
|
|
53
|
+
const rect = element.getBoundingClientRect();
|
|
54
|
+
return (
|
|
55
|
+
rect.top >= 0 &&
|
|
56
|
+
rect.left >= 0 &&
|
|
57
|
+
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
|
|
58
|
+
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
|
|
59
|
+
);
|
|
60
|
+
};
|
|
61
|
+
|
|
49
62
|
const withGlobalTestConfig = () =>
|
|
50
63
|
/** @type {OverlayConfig} */ ({
|
|
51
64
|
placementMode: 'global',
|
|
@@ -905,9 +918,10 @@ describe('OverlayController', () => {
|
|
|
905
918
|
|
|
906
919
|
await ctrl.hide();
|
|
907
920
|
expect(document.activeElement).to.equal(input);
|
|
921
|
+
expect(isInViewport(input)).to.be.true;
|
|
908
922
|
});
|
|
909
923
|
|
|
910
|
-
it('supports elementToFocusAfterHide option when shadowRoot involved
|
|
924
|
+
it('supports elementToFocusAfterHide option when shadowRoot involved', async () => {
|
|
911
925
|
const input = /** @type {HTMLElement} */ (await fixture('<input />'));
|
|
912
926
|
const contentNode = /** @type {HTMLElement} */ (
|
|
913
927
|
await fixture('<div><textarea></textarea></div>')
|
|
@@ -80,9 +80,6 @@ export class LionSwitch extends ScopedElementsMixin(ChoiceInputMixin(LionField))
|
|
|
80
80
|
|
|
81
81
|
connectedCallback() {
|
|
82
82
|
super.connectedCallback();
|
|
83
|
-
if (!this.role) {
|
|
84
|
-
this.role = 'switch';
|
|
85
|
-
}
|
|
86
83
|
this.addEventListener('checked-changed', this.__handleButtonSwitchCheckedChanged);
|
|
87
84
|
if (this._labelNode) {
|
|
88
85
|
this._labelNode.addEventListener('click', this._toggleChecked);
|
|
@@ -78,6 +78,7 @@ export class LionSwitchButton extends DisabledWithTabIndexMixin(LitElement) {
|
|
|
78
78
|
|
|
79
79
|
this.role = 'switch';
|
|
80
80
|
this.checked = false;
|
|
81
|
+
this.__initialized = false;
|
|
81
82
|
/** @protected */
|
|
82
83
|
this._toggleChecked = this._toggleChecked.bind(this);
|
|
83
84
|
/** @private */
|
|
@@ -158,8 +159,20 @@ export class LionSwitchButton extends DisabledWithTabIndexMixin(LitElement) {
|
|
|
158
159
|
*/
|
|
159
160
|
requestUpdate(name, oldValue, options) {
|
|
160
161
|
super.requestUpdate(name, oldValue, options);
|
|
161
|
-
if (
|
|
162
|
+
if (
|
|
163
|
+
this.__initialized &&
|
|
164
|
+
this.isConnected &&
|
|
165
|
+
name === 'checked' &&
|
|
166
|
+
this.checked !== oldValue &&
|
|
167
|
+
!this.disabled
|
|
168
|
+
) {
|
|
162
169
|
this.__checkedStateChange();
|
|
163
170
|
}
|
|
164
171
|
}
|
|
172
|
+
|
|
173
|
+
/** @param {import('lit').PropertyValues } changedProperties */
|
|
174
|
+
firstUpdated(changedProperties) {
|
|
175
|
+
super.firstUpdated(changedProperties);
|
|
176
|
+
this.__initialized = true;
|
|
177
|
+
}
|
|
165
178
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { expect, fixture as _fixture } from '@open-wc/testing';
|
|
1
|
+
import { expect, fixture as _fixture, fixtureSync, elementUpdated } from '@open-wc/testing';
|
|
2
2
|
import { html } from 'lit/static-html.js';
|
|
3
3
|
import sinon from 'sinon';
|
|
4
4
|
import '@lion/ui/define/lion-switch-button.js';
|
|
@@ -126,6 +126,20 @@ describe('lion-switch-button', () => {
|
|
|
126
126
|
expect(handlerSpy.called).to.be.false;
|
|
127
127
|
});
|
|
128
128
|
|
|
129
|
+
it('should not dispatch "checked-changed" event if not initialized on update', async () => {
|
|
130
|
+
const handlerSpy = sinon.spy();
|
|
131
|
+
const elSync = /** @type {LionSwitchButton} */ (
|
|
132
|
+
fixtureSync(html`<lion-switch-button @checked-changed="${handlerSpy}" .checked=${true} />`)
|
|
133
|
+
);
|
|
134
|
+
expect(elSync.__initialized).to.be.false;
|
|
135
|
+
await elementUpdated(elSync);
|
|
136
|
+
expect(elSync.__initialized).to.be.true;
|
|
137
|
+
expect(handlerSpy.called).to.be.false;
|
|
138
|
+
elSync.checked = !elSync.checked;
|
|
139
|
+
await elementUpdated(elSync);
|
|
140
|
+
expect(handlerSpy.called).to.be.true;
|
|
141
|
+
});
|
|
142
|
+
|
|
129
143
|
describe('a11y', () => {
|
|
130
144
|
it('should manage "aria-checked"', async () => {
|
|
131
145
|
expect(el.hasAttribute('aria-checked')).to.be.true;
|
|
@@ -10,7 +10,7 @@ import '@lion/ui/define/lion-switch.js';
|
|
|
10
10
|
/**
|
|
11
11
|
* @typedef {import('../src/LionSwitchButton.js').LionSwitchButton} LionSwitchButton
|
|
12
12
|
* @typedef {import('lit').TemplateResult} TemplateResult
|
|
13
|
-
* @typedef {import('
|
|
13
|
+
* @typedef {import('@lion/ui/types/form-core.js').FormControlHost} FormControlHost
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
const IsTrue = class extends Validator {
|
|
@@ -215,10 +215,25 @@ describe('lion-switch', () => {
|
|
|
215
215
|
expect(el.showsFeedbackFor).to.eql(['info']);
|
|
216
216
|
});
|
|
217
217
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
218
|
+
describe('Accessibility', () => {
|
|
219
|
+
it('passes axe a11y audit', async () => {
|
|
220
|
+
const el = await fixture(html`<lion-switch name="hi" label="My label"></lion-switch>`);
|
|
221
|
+
await expect(el).to.be.accessible();
|
|
222
|
+
|
|
223
|
+
el.checked = true;
|
|
224
|
+
await el.updateComplete;
|
|
225
|
+
await expect(el).to.be.accessible();
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it('passes axe a11y audit when disabled', async () => {
|
|
229
|
+
const el = await fixture(
|
|
230
|
+
html`<lion-switch name="hi" label="My label" disabled></lion-switch>`,
|
|
231
|
+
);
|
|
232
|
+
await expect(el).to.be.accessible();
|
|
233
|
+
|
|
234
|
+
el.checked = true;
|
|
235
|
+
await el.updateComplete;
|
|
236
|
+
await expect(el).to.be.accessible();
|
|
237
|
+
});
|
|
223
238
|
});
|
|
224
239
|
});
|
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
/* eslint-disable import/no-extraneous-dependencies */
|
|
2
|
+
import { MatchesOption } from '@lion/ui/combobox.js';
|
|
2
3
|
import {
|
|
3
4
|
DefaultSuccess,
|
|
5
|
+
EqualsLength,
|
|
4
6
|
IsDate,
|
|
5
7
|
IsDateDisabled,
|
|
8
|
+
IsEmail,
|
|
9
|
+
IsNumber,
|
|
6
10
|
MaxDate,
|
|
11
|
+
MaxLength,
|
|
12
|
+
MaxNumber,
|
|
7
13
|
MinDate,
|
|
14
|
+
MinLength,
|
|
8
15
|
MinMaxDate,
|
|
9
|
-
|
|
10
|
-
MaxNumber,
|
|
16
|
+
MinMaxLength,
|
|
11
17
|
MinMaxNumber,
|
|
12
18
|
MinNumber,
|
|
13
|
-
Required,
|
|
14
|
-
EqualsLength,
|
|
15
|
-
IsEmail,
|
|
16
|
-
MaxLength,
|
|
17
|
-
MinLength,
|
|
18
|
-
MinMaxLength,
|
|
19
19
|
Pattern,
|
|
20
|
+
Required,
|
|
20
21
|
} from '@lion/ui/form-core.js';
|
|
21
22
|
import { PhoneNumber } from '@lion/ui/input-tel.js';
|
|
22
23
|
|
|
@@ -162,6 +163,8 @@ export function loadDefaultFeedbackMessagesNoSideEffects({ localize }) {
|
|
|
162
163
|
MinMaxDate.getMessage = async data => getLocalizedMessage(data);
|
|
163
164
|
/** @param {FeedbackMessageData} data */
|
|
164
165
|
IsDateDisabled.getMessage = async data => getLocalizedMessage(data);
|
|
166
|
+
/** @param {FeedbackMessageData} data */
|
|
167
|
+
MatchesOption.getMessage = async data => getLocalizedMessage(data);
|
|
165
168
|
|
|
166
169
|
DefaultSuccess.getMessage = async data => {
|
|
167
170
|
await forMessagesToBeReady();
|
|
@@ -17,6 +17,8 @@ export default {
|
|
|
17
17
|
'Моля, въведете {fieldName} между {params.min, date, YYYYMMDD} и {params.max, date, YYYYMMDD}.',
|
|
18
18
|
IsDateDisabled: 'Тази дата не е на разположение, моля, изберете друга.',
|
|
19
19
|
IsEmail: 'Моля, въведете валиден {fieldName} с формат "name@example.com".',
|
|
20
|
+
MatchesOption:
|
|
21
|
+
'Не са открити съответстващи резултати. Моля, опитайте с друга ключова дума или категория.',
|
|
20
22
|
},
|
|
21
23
|
warning: {
|
|
22
24
|
Required: 'Моля, въведете също {fieldName}.',
|
|
@@ -35,6 +37,8 @@ export default {
|
|
|
35
37
|
'Моля, въведете {fieldName} между {params.min, date, YYYYMMDD} и {params.max, date, YYYYMMDD}.',
|
|
36
38
|
IsDateDisabled: 'Тази дата не е на разположение, моля, изберете друга.',
|
|
37
39
|
IsEmail: 'Моля, въведете валиден {fieldName} с формат "name@example.com".',
|
|
40
|
+
MatchesOption:
|
|
41
|
+
'Не са открити съответстващи резултати. Моля, опитайте с друга ключова дума или категория.',
|
|
38
42
|
},
|
|
39
43
|
success: {
|
|
40
44
|
DefaultOk: 'Добре',
|
|
@@ -17,6 +17,7 @@ export default {
|
|
|
17
17
|
'Zadejte {fieldName} od {params.min, date, YYYYMMDD} do {params.max, date, YYYYMMDD}.',
|
|
18
18
|
IsDateDisabled: 'Toto datum je nedostupné, vyberte jiné.',
|
|
19
19
|
IsEmail: 'Zadejte platný {fieldName} ve formátu "name@example.com".',
|
|
20
|
+
MatchesOption: 'Žádné odpovídající výsledky. Zkuste jiné klíčové slovo nebo kategorii.',
|
|
20
21
|
},
|
|
21
22
|
warning: {
|
|
22
23
|
Required: 'Zadejte rovněž {fieldName}.',
|
|
@@ -35,6 +36,7 @@ export default {
|
|
|
35
36
|
'Zadejte {fieldName} od {params.min, date, YYYYMMDD} do {params.max, date, YYYYMMDD}.',
|
|
36
37
|
IsDateDisabled: 'Toto datum je nedostupné, vyberte jiné.',
|
|
37
38
|
IsEmail: 'Zadejte platný {fieldName} ve formátu "name@example.com".',
|
|
39
|
+
MatchesOption: 'Žádné odpovídající výsledky. Zkuste jiné klíčové slovo nebo kategorii.',
|
|
38
40
|
},
|
|
39
41
|
success: {
|
|
40
42
|
DefaultOk: 'Dobře',
|
|
@@ -18,6 +18,8 @@ export default {
|
|
|
18
18
|
'Geben Sie für {fieldName} einen Wert zwischen {params.min, date, YYYYMMDD} und {params.max, date, YYYYMMDD} ein.',
|
|
19
19
|
IsDateDisabled: 'Dieses Datum ist nicht verfügbar, bitte wählen Sie ein anderes Datum.',
|
|
20
20
|
IsEmail: 'Geben Sie einen gültige {fieldName} im Format „name@example.com“ ein.',
|
|
21
|
+
MatchesOption:
|
|
22
|
+
'Keine übereinstimmenden Ergebnisse. Bitte versuchen Sie es mit einem anderen Schlüsselbegriff oder einer anderen Kategorie.',
|
|
21
23
|
},
|
|
22
24
|
warning: {
|
|
23
25
|
Required: '{fieldName} sollte ausgefüllt werden.',
|
|
@@ -37,6 +39,8 @@ export default {
|
|
|
37
39
|
'Geben Sie für {fieldName} einen Wert zwischen {params.min, date, YYYYMMDD} und {params.max, date, YYYYMMDD} ein.',
|
|
38
40
|
IsDateDisabled: 'Dieses Datum ist nicht verfügbar, bitte wählen Sie ein anderes Datum.',
|
|
39
41
|
IsEmail: 'Geben Sie einen gültige {fieldName} im Format „name@example.com“ ein.',
|
|
42
|
+
MatchesOption:
|
|
43
|
+
'Keine übereinstimmenden Ergebnisse. Bitte versuchen Sie es mit einem anderen Schlüsselbegriff oder einer anderen Kategorie.',
|
|
40
44
|
},
|
|
41
45
|
success: {
|
|
42
46
|
DefaultOk: 'OK',
|
|
@@ -18,6 +18,7 @@ export default {
|
|
|
18
18
|
'Please enter a {fieldName} between {params.min, date, YYYYMMDD} and {params.max, date, YYYYMMDD}.',
|
|
19
19
|
IsDateDisabled: 'This date is unavailable, please choose another one.',
|
|
20
20
|
IsEmail: 'Please enter a valid {fieldName} in the format "name@example.com".',
|
|
21
|
+
MatchesOption: 'No matching results. Please try a different keyword or category.',
|
|
21
22
|
},
|
|
22
23
|
warning: {
|
|
23
24
|
Required: 'Please enter a(n) {fieldName}.',
|
|
@@ -37,6 +38,7 @@ export default {
|
|
|
37
38
|
'Please enter a {fieldName} between {params.min, date, YYYYMMDD} and {params.max, date, YYYYMMDD}.',
|
|
38
39
|
IsDateDisabled: 'This date is unavailable, please choose another one.',
|
|
39
40
|
IsEmail: 'Please enter a valid {fieldName} in the format "name@example.com".',
|
|
41
|
+
MatchesOption: 'No matching results. Please try a different keyword or category.',
|
|
40
42
|
},
|
|
41
43
|
success: {
|
|
42
44
|
DefaultOk: 'Okay',
|
|
@@ -18,6 +18,8 @@ export default {
|
|
|
18
18
|
'Introduzca un/a {fieldName} entre {params.min, date, YYYYMMDD} y {params.max, date, YYYYMMDD}.',
|
|
19
19
|
IsDateDisabled: 'Esta fecha no está disponible. Elija otra.',
|
|
20
20
|
IsEmail: 'Introduzca un/a {fieldName} válido/a con el formato "nombre@ejemplo.com".',
|
|
21
|
+
MatchesOption:
|
|
22
|
+
'No hay resultados que coincidan. Pruebe con una palabra clave o categoría diferente.',
|
|
21
23
|
},
|
|
22
24
|
warning: {
|
|
23
25
|
Required: 'Introduzca también un/a {fieldName}.',
|
|
@@ -37,6 +39,8 @@ export default {
|
|
|
37
39
|
'Introduzca un/a {fieldName} entre {params.min, date, YYYYMMDD} y {params.max, date, YYYYMMDD}.',
|
|
38
40
|
IsDateDisabled: 'Esta fecha no está disponible. Elija otra.',
|
|
39
41
|
IsEmail: 'Introduzca un/a {fieldName} válido/a con el formato "nombre@ejemplo.com".',
|
|
42
|
+
MatchesOption:
|
|
43
|
+
'No hay resultados que coincidan. Pruebe con una palabra clave o categoría diferente.',
|
|
40
44
|
},
|
|
41
45
|
success: {
|
|
42
46
|
DefaultOk: 'Vale',
|