@lion/ui 0.6.0-beta.0 → 0.6.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 (166) hide show
  1. package/components/core/src/SlotMixin.js +107 -65
  2. package/components/core/test/SlotMixin.test.js +64 -1
  3. package/components/core/types/SlotMixinTypes.ts +8 -0
  4. package/components/form-core/src/choice-group/ChoiceGroupMixin.js +10 -1
  5. package/components/form-core/src/registration/FormRegisteringMixin.js +14 -0
  6. package/components/form-core/src/validate/ValidateMixin.js +10 -0
  7. package/components/form-core/src/validate/Validator.js +6 -3
  8. package/components/form-core/test-suites/FormRegistrationMixins.suite.js +64 -9
  9. package/components/form-core/types/FormControlMixinTypes.ts +2 -0
  10. package/components/form-core/types/registration/FormRegisteringMixinTypes.ts +9 -1
  11. package/components/form-core/types/validate/ValidateMixinTypes.ts +2 -0
  12. package/components/form-core/types/validate/validate.ts +2 -2
  13. package/components/input-file/src/LionInputFile.js +9 -2
  14. package/components/input-tel-dropdown/src/LionInputTelDropdown.js +12 -3
  15. package/components/input-tel-dropdown/test/LionInputTelDropdown.test.js +110 -2
  16. package/components/input-tel-dropdown/test-helpers/mimicUserChangingDropdown.js +22 -0
  17. package/components/input-tel-dropdown/test-suites/LionInputTelDropdown.suite.js +2 -39
  18. package/components/localize/src/LocalizeMixin.js +2 -2
  19. package/components/overlays/src/OverlayController.js +1 -1
  20. package/components/select/src/LionSelect.js +5 -0
  21. package/components/validate-messages/src/getLocalizedMessage.js +12 -1
  22. package/components/validate-messages/test/loadDefaultFeedbackMessagesNoSideEffects.test.js +105 -0
  23. package/components/validate-messages/translations/bg.js +4 -0
  24. package/components/validate-messages/translations/cs.js +4 -0
  25. package/components/validate-messages/translations/de.js +4 -0
  26. package/components/validate-messages/translations/en.js +5 -1
  27. package/components/validate-messages/translations/es.js +4 -0
  28. package/components/validate-messages/translations/fr.js +4 -0
  29. package/components/validate-messages/translations/hu.js +4 -0
  30. package/components/validate-messages/translations/it.js +4 -0
  31. package/components/validate-messages/translations/nl.js +4 -0
  32. package/components/validate-messages/translations/pl.js +4 -0
  33. package/components/validate-messages/translations/ro.js +4 -0
  34. package/components/validate-messages/translations/ru.js +4 -0
  35. package/components/validate-messages/translations/sk.js +4 -0
  36. package/components/validate-messages/translations/uk.js +4 -0
  37. package/components/validate-messages/translations/zh.js +4 -0
  38. package/custom-elements.json +5712 -1960
  39. package/dist-types/components/core/src/SlotMixin.d.ts +5 -1
  40. package/dist-types/components/core/src/SlotMixin.d.ts.map +1 -1
  41. package/dist-types/components/core/types/SlotMixinTypes.d.ts +8 -0
  42. package/dist-types/components/core/types/SlotMixinTypes.d.ts.map +1 -1
  43. package/dist-types/components/form-core/src/choice-group/ChoiceGroupMixin.d.ts +1 -0
  44. package/dist-types/components/form-core/src/choice-group/ChoiceGroupMixin.d.ts.map +1 -1
  45. package/dist-types/components/form-core/src/registration/FormRegisteringMixin.d.ts.map +1 -1
  46. package/dist-types/components/form-core/src/validate/ValidateMixin.d.ts +1 -0
  47. package/dist-types/components/form-core/src/validate/ValidateMixin.d.ts.map +1 -1
  48. package/dist-types/components/form-core/src/validate/Validator.d.ts +5 -2
  49. package/dist-types/components/form-core/src/validate/Validator.d.ts.map +1 -1
  50. package/dist-types/components/form-core/test-suites/FormRegistrationMixins.suite.d.ts.map +1 -1
  51. package/dist-types/components/form-core/types/FormControlMixinTypes.d.ts +1 -0
  52. package/dist-types/components/form-core/types/FormControlMixinTypes.d.ts.map +1 -1
  53. package/dist-types/components/form-core/types/registration/FormRegisteringMixinTypes.d.ts +9 -1
  54. package/dist-types/components/form-core/types/registration/FormRegisteringMixinTypes.d.ts.map +1 -1
  55. package/dist-types/components/form-core/types/validate/ValidateMixinTypes.d.ts +1 -0
  56. package/dist-types/components/form-core/types/validate/ValidateMixinTypes.d.ts.map +1 -1
  57. package/dist-types/components/form-core/types/validate/validate.d.ts +2 -2
  58. package/dist-types/components/input-file/src/LionInputFile.d.ts +1 -0
  59. package/dist-types/components/input-file/src/LionInputFile.d.ts.map +1 -1
  60. package/dist-types/components/input-tel-dropdown/src/LionInputTelDropdown.d.ts +1 -0
  61. package/dist-types/components/input-tel-dropdown/src/LionInputTelDropdown.d.ts.map +1 -1
  62. package/dist-types/components/input-tel-dropdown/test-helpers/mimicUserChangingDropdown.d.ts +12 -0
  63. package/dist-types/components/input-tel-dropdown/test-helpers/mimicUserChangingDropdown.d.ts.map +1 -0
  64. package/dist-types/components/input-tel-dropdown/test-suites/LionInputTelDropdown.suite.d.ts.map +1 -1
  65. package/dist-types/components/select/src/LionSelect.d.ts.map +1 -1
  66. package/dist-types/components/validate-messages/src/getLocalizedMessage.d.ts.map +1 -1
  67. package/dist-types/components/validate-messages/test/loadDefaultFeedbackMessagesNoSideEffects.test.d.ts +4 -0
  68. package/dist-types/components/validate-messages/test/loadDefaultFeedbackMessagesNoSideEffects.test.d.ts.map +1 -0
  69. package/dist-types/components/validate-messages/translations/bg-BG.d.ts +4 -0
  70. package/dist-types/components/validate-messages/translations/bg.d.ts +6 -0
  71. package/dist-types/components/validate-messages/translations/cs-CZ.d.ts +4 -0
  72. package/dist-types/components/validate-messages/translations/cs.d.ts +6 -0
  73. package/dist-types/components/validate-messages/translations/de-DE.d.ts +4 -0
  74. package/dist-types/components/validate-messages/translations/de.d.ts +6 -0
  75. package/dist-types/components/validate-messages/translations/en-AU.d.ts +4 -0
  76. package/dist-types/components/validate-messages/translations/en-GB.d.ts +4 -0
  77. package/dist-types/components/validate-messages/translations/en-PH.d.ts +4 -0
  78. package/dist-types/components/validate-messages/translations/en-US.d.ts +4 -0
  79. package/dist-types/components/validate-messages/translations/en.d.ts +6 -0
  80. package/dist-types/components/validate-messages/translations/es-ES.d.ts +4 -0
  81. package/dist-types/components/validate-messages/translations/es.d.ts +6 -0
  82. package/dist-types/components/validate-messages/translations/fr-BE.d.ts +4 -0
  83. package/dist-types/components/validate-messages/translations/fr-FR.d.ts +4 -0
  84. package/dist-types/components/validate-messages/translations/fr.d.ts +6 -0
  85. package/dist-types/components/validate-messages/translations/hu-HU.d.ts +4 -0
  86. package/dist-types/components/validate-messages/translations/hu.d.ts +6 -0
  87. package/dist-types/components/validate-messages/translations/it-IT.d.ts +4 -0
  88. package/dist-types/components/validate-messages/translations/it.d.ts +6 -0
  89. package/dist-types/components/validate-messages/translations/nl-BE.d.ts +4 -0
  90. package/dist-types/components/validate-messages/translations/nl-NL.d.ts +4 -0
  91. package/dist-types/components/validate-messages/translations/nl.d.ts +6 -0
  92. package/dist-types/components/validate-messages/translations/pl-PL.d.ts +4 -0
  93. package/dist-types/components/validate-messages/translations/pl.d.ts +6 -0
  94. package/dist-types/components/validate-messages/translations/ro-RO.d.ts +4 -0
  95. package/dist-types/components/validate-messages/translations/ro.d.ts +6 -0
  96. package/dist-types/components/validate-messages/translations/ru-RU.d.ts +4 -0
  97. package/dist-types/components/validate-messages/translations/ru.d.ts +6 -0
  98. package/dist-types/components/validate-messages/translations/sk-SK.d.ts +4 -0
  99. package/dist-types/components/validate-messages/translations/sk.d.ts +6 -0
  100. package/dist-types/components/validate-messages/translations/uk-UA.d.ts +4 -0
  101. package/dist-types/components/validate-messages/translations/uk.d.ts +6 -0
  102. package/dist-types/components/validate-messages/translations/zh.d.ts +6 -0
  103. package/dist-types/exports/input-tel-dropdown-test-helpers.d.ts +2 -0
  104. package/dist-types/exports/input-tel-dropdown-test-helpers.d.ts.map +1 -0
  105. package/dist-types/tsconfig.tsbuildinfo +1 -1
  106. package/docs/components/checkbox-group/overview.md +2 -2
  107. package/docs/components/collapsible/overview.md +1 -1
  108. package/docs/components/combobox/overview.md +1 -1
  109. package/docs/components/combobox/use-cases.md +1 -1
  110. package/docs/components/dialog/overview.md +1 -1
  111. package/docs/components/fieldset/overview.md +5 -5
  112. package/docs/components/form/overview.md +3 -3
  113. package/docs/components/icon/use-cases.md +1 -1
  114. package/docs/components/input/overview.md +1 -1
  115. package/docs/components/input-amount/overview.md +3 -3
  116. package/docs/components/input-date/overview.md +3 -3
  117. package/docs/components/input-datepicker/overview.md +5 -5
  118. package/docs/components/input-email/overview.md +2 -2
  119. package/docs/components/input-file/overview.md +1 -1
  120. package/docs/components/input-file/use-cases.md +8 -8
  121. package/docs/components/input-iban/overview.md +2 -2
  122. package/docs/components/input-range/overview.md +2 -2
  123. package/docs/components/input-stepper/overview.md +1 -1
  124. package/docs/components/input-tel/overview.md +1 -1
  125. package/docs/components/input-tel/use-cases.md +6 -6
  126. package/docs/components/input-tel-dropdown/overview.md +1 -1
  127. package/docs/components/listbox/use-cases.md +90 -95
  128. package/docs/components/radio-group/overview.md +3 -3
  129. package/docs/components/select/use-cases.md +34 -33
  130. package/docs/components/select-rich/use-cases.md +1 -1
  131. package/docs/components/tabs/examples.md +1 -1
  132. package/docs/fundamentals/index.md +4 -4
  133. package/docs/fundamentals/node-tools/providence-analytics/LocalConfiguration.md +1 -1
  134. package/docs/fundamentals/node-tools/providence-analytics/QueryResult.md +1 -1
  135. package/docs/fundamentals/node-tools/providence-analytics/analyzer.md +1 -1
  136. package/docs/fundamentals/node-tools/providence-analytics/dashboard.md +1 -1
  137. package/docs/fundamentals/node-tools/providence-analytics/overview.md +3 -3
  138. package/docs/fundamentals/node-tools/publish-docs/overview.md +3 -3
  139. package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +2 -2
  140. package/docs/fundamentals/rationales/accessibility.md +1 -1
  141. package/docs/fundamentals/systems/core/SlotMixin.md +1 -1
  142. package/docs/fundamentals/systems/core/overview.md +1 -1
  143. package/docs/fundamentals/systems/form/formatting-and-parsing.md +4 -4
  144. package/docs/fundamentals/systems/form/model-value.md +1 -1
  145. package/docs/fundamentals/systems/form/overview.md +28 -28
  146. package/docs/fundamentals/systems/form/styling.md +34 -39
  147. package/docs/fundamentals/systems/form/validate.md +7 -4
  148. package/docs/fundamentals/systems/localize/overview.md +4 -4
  149. package/docs/fundamentals/systems/overlays/configuration.md +2 -2
  150. package/docs/fundamentals/systems/overlays/overview.md +5 -5
  151. package/docs/fundamentals/systems/overlays/use-cases.md +2 -2
  152. package/docs/fundamentals/tools/ajax/overview.md +2 -1
  153. package/docs/fundamentals/tools/helpers/overview.md +1 -1
  154. package/docs/fundamentals/tools/singleton-manager/overview.md +4 -4
  155. package/docs/guides/how-to/create-a-custom-field.md +5 -5
  156. package/docs/guides/how-to/create-a-form.md +4 -4
  157. package/docs/guides/how-to/extend-a-native-input.md +2 -2
  158. package/docs/guides/index.md +8 -8
  159. package/docs/guides/principles/index.md +5 -5
  160. package/docs/guides/principles/styling.md +1 -1
  161. package/exports/input-tel-dropdown-test-helpers.js +1 -0
  162. package/input-tel-dropdown-test-helpers.js +1 -0
  163. package/package.json +1 -1
  164. package/components/validate-messages/test/loadDefaultFeedbackMessagesNoSideEffects.js +0 -51
  165. package/dist-types/components/validate-messages/test/loadDefaultFeedbackMessagesNoSideEffects.d.ts +0 -2
  166. package/dist-types/components/validate-messages/test/loadDefaultFeedbackMessagesNoSideEffects.d.ts.map +0 -1
@@ -180,6 +180,7 @@ export class LionInputTelDropdown extends LionInputTel {
180
180
 
181
181
  return {
182
182
  template: templates.dropdown(this._templateDataDropdown),
183
+ renderAsDirectHostChild: Boolean,
183
184
  };
184
185
  },
185
186
  };
@@ -324,7 +325,10 @@ export class LionInputTelDropdown extends LionInputTel {
324
325
  */
325
326
  _onDropdownValueChange(event) {
326
327
  const isInitializing = event.detail?.initialize || !this._phoneUtil;
327
- const dropdownValue = /** @type {RegionCode} */ (event.target.modelValue || event.target.value);
328
+ const dropdownElement = event.target;
329
+ const dropdownValue = /** @type {RegionCode} */ (
330
+ dropdownElement.modelValue || dropdownElement.value
331
+ );
328
332
 
329
333
  if (isInitializing || this.activeRegion === dropdownValue) {
330
334
  return;
@@ -355,8 +359,13 @@ export class LionInputTelDropdown extends LionInputTel {
355
359
  }
356
360
 
357
361
  // Put focus on text box
358
- const overlayController = event.target._overlayCtrl;
359
- if (overlayController?.isShown) {
362
+ //
363
+ // A LionSelectRich with interactionMode set on windows/linux
364
+ // will set each item on arrow key up/down to activeElement
365
+ // which causes the focus to jump every time to the inputNode
366
+ const overlayController = dropdownElement._overlayCtrl;
367
+ // @ts-ignore interactionMode only exists on LionSelectRich not on HTMLSelectElement
368
+ if (overlayController?.isShown && dropdownElement.interactionMode !== 'windows/linux') {
360
369
  setTimeout(() => {
361
370
  this._inputNode.focus();
362
371
  });
@@ -1,12 +1,12 @@
1
1
  import { runInputTelSuite } from '@lion/ui/input-tel-test-suites.js';
2
- import { html } from 'lit';
3
2
  import { repeat } from 'lit/directives/repeat.js';
4
3
  import { ref } from 'lit/directives/ref.js';
5
-
4
+ import { aTimeout, expect, fixture, html } from '@open-wc/testing';
6
5
  import { LionInputTelDropdown } from '@lion/ui/input-tel-dropdown.js';
7
6
  import { LionOption } from '@lion/ui/listbox.js';
8
7
  import { LionSelectRich } from '@lion/ui/select-rich.js';
9
8
  import { runInputTelDropdownSuite } from '@lion/ui/input-tel-dropdown-test-suites.js';
9
+ import { mimicUserChangingDropdown } from '@lion/ui/input-tel-dropdown-test-helpers.js';
10
10
  import { ScopedElementsMixin } from '../../core/src/ScopedElementsMixin.js';
11
11
 
12
12
  /**
@@ -62,4 +62,112 @@ describe('WithFormControlInputTelDropdown', () => {
62
62
  // @ts-expect-error
63
63
  // Runs it for LionSelectRich, which uses .modelValue/@model-value-changed instead of .value/@change
64
64
  runInputTelDropdownSuite({ klass: WithFormControlInputTelDropdown });
65
+
66
+ it('focuses the textbox right after selection if selected via opened dropdown if interaction-mode is mac', async () => {
67
+ class InputTelDropdownMac extends LionInputTelDropdown {
68
+ static templates = {
69
+ ...(super.templates || {}),
70
+ /**
71
+ * @param {TemplateDataForDropdownInputTel} templateDataForDropdown
72
+ */
73
+ dropdown: templateDataForDropdown => {
74
+ const { refs, data } = templateDataForDropdown;
75
+ // TODO: once spread directive available, use it per ref (like ref(refs?.dropdown?.ref))
76
+ return html`
77
+ <lion-select-rich
78
+ ${ref(refs?.dropdown?.ref)}
79
+ label="${refs?.dropdown?.labels?.country}"
80
+ label-sr-only
81
+ @model-value-changed="${refs?.dropdown?.listeners['model-value-changed']}"
82
+ style="${refs?.dropdown?.props?.style}"
83
+ interaction-mode="mac"
84
+ >
85
+ ${repeat(
86
+ data.regionMetaList,
87
+ regionMeta => regionMeta.regionCode,
88
+ regionMeta =>
89
+ html` <lion-option .choiceValue="${regionMeta.regionCode}"> </lion-option> `,
90
+ )}
91
+ </lion-select-rich>
92
+ `;
93
+ },
94
+ };
95
+ }
96
+ customElements.define('input-tel-dropdown-mac', InputTelDropdownMac);
97
+ const el = /** @type {LionInputTelDropdown} */ (
98
+ await fixture(
99
+ html`
100
+ <input-tel-dropdown-mac
101
+ .allowedRegions="${['NL', 'BE']}"
102
+ .modelValue="${'+31612345678'}"
103
+ ></input-tel-dropdown-mac>
104
+ `,
105
+ )
106
+ );
107
+ const dropdownElement = el.refs.dropdown.value;
108
+ // @ts-expect-error [allow-protected-in-tests]
109
+ if (dropdownElement?._overlayCtrl) {
110
+ // @ts-expect-error [allow-protected-in-tests]
111
+ dropdownElement._overlayCtrl.show();
112
+ mimicUserChangingDropdown(dropdownElement, 'BE');
113
+ await el.updateComplete;
114
+ await aTimeout(0);
115
+ // @ts-expect-error [allow-protected-in-tests]
116
+ expect(el._inputNode).to.equal(document.activeElement);
117
+ }
118
+ });
119
+
120
+ it('does not focus the textbox right after selection if selected via opened dropdown if interaction-mode is windows/linux', async () => {
121
+ class InputTelDropdownWindows extends LionInputTelDropdown {
122
+ static templates = {
123
+ ...(super.templates || {}),
124
+ /**
125
+ * @param {TemplateDataForDropdownInputTel} templateDataForDropdown
126
+ */
127
+ dropdown: templateDataForDropdown => {
128
+ const { refs, data } = templateDataForDropdown;
129
+ // TODO: once spread directive available, use it per ref (like ref(refs?.dropdown?.ref))
130
+ return html`
131
+ <lion-select-rich
132
+ ${ref(refs?.dropdown?.ref)}
133
+ label="${refs?.dropdown?.labels?.country}"
134
+ label-sr-only
135
+ @model-value-changed="${refs?.dropdown?.listeners['model-value-changed']}"
136
+ style="${refs?.dropdown?.props?.style}"
137
+ interaction-mode="windows/linux"
138
+ >
139
+ ${repeat(
140
+ data.regionMetaList,
141
+ regionMeta => regionMeta.regionCode,
142
+ regionMeta =>
143
+ html` <lion-option .choiceValue="${regionMeta.regionCode}"> </lion-option> `,
144
+ )}
145
+ </lion-select-rich>
146
+ `;
147
+ },
148
+ };
149
+ }
150
+ customElements.define('input-tel-dropdown-windows', InputTelDropdownWindows);
151
+ const el = /** @type {LionInputTelDropdown} */ (
152
+ await fixture(
153
+ html`
154
+ <input-tel-dropdown-windows
155
+ .allowedRegions="${['NL', 'BE']}"
156
+ .modelValue="${'+31612345678'}"
157
+ ></input-tel-dropdown-windows>
158
+ `,
159
+ )
160
+ );
161
+ const dropdownElement = el.refs.dropdown.value;
162
+ // @ts-expect-error [allow-protected-in-tests]
163
+ if (dropdownElement?._overlayCtrl) {
164
+ // @ts-expect-error [allow-protected-in-tests]
165
+ dropdownElement._overlayCtrl.show();
166
+ mimicUserChangingDropdown(dropdownElement, 'BE');
167
+ await el.updateComplete;
168
+ await aTimeout(0);
169
+ // @ts-expect-error [allow-protected-in-tests]
170
+ expect(el._inputNode).to.not.equal(document.activeElement);
171
+ }
172
+ });
65
173
  });
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @typedef {HTMLSelectElement|HTMLElement & {modelValue:string}} DropdownElement
3
+ */
4
+
5
+ /**
6
+ * @param {DropdownElement} dropdownEl
7
+ * @param {string} value
8
+ */
9
+ export function mimicUserChangingDropdown(dropdownEl, value) {
10
+ if ('modelValue' in dropdownEl) {
11
+ // eslint-disable-next-line no-param-reassign
12
+ dropdownEl.modelValue = value;
13
+ dropdownEl.dispatchEvent(
14
+ new CustomEvent('model-value-changed', { detail: { isTriggeredByUser: true } }),
15
+ );
16
+ } else {
17
+ // eslint-disable-next-line no-param-reassign
18
+ dropdownEl.value = value;
19
+ dropdownEl.dispatchEvent(new Event('change'));
20
+ dropdownEl.dispatchEvent(new Event('input'));
21
+ }
22
+ }
@@ -11,6 +11,7 @@ import {
11
11
  } from '@open-wc/testing';
12
12
  import sinon from 'sinon';
13
13
  import { LionInputTelDropdown } from '@lion/ui/input-tel-dropdown.js';
14
+ import { mimicUserChangingDropdown } from '@lion/ui/input-tel-dropdown-test-helpers.js';
14
15
 
15
16
  /**
16
17
  * @typedef {import('lit').TemplateResult} TemplateResult
@@ -36,24 +37,6 @@ function getDropdownValue(dropdownEl) {
36
37
  return dropdownEl.value;
37
38
  }
38
39
 
39
- /**
40
- * @param {DropdownElement} dropdownEl
41
- * @param {string} value
42
- */
43
- function mimicUserChangingDropdown(dropdownEl, value) {
44
- if ('modelValue' in dropdownEl) {
45
- // eslint-disable-next-line no-param-reassign
46
- dropdownEl.modelValue = value;
47
- dropdownEl.dispatchEvent(
48
- new CustomEvent('model-value-changed', { detail: { isTriggeredByUser: true } }),
49
- );
50
- } else {
51
- // eslint-disable-next-line no-param-reassign
52
- dropdownEl.value = value;
53
- dropdownEl.dispatchEvent(new Event('change'));
54
- }
55
- }
56
-
57
40
  /**
58
41
  * @param {{ klass:LionInputTelDropdown }} config
59
42
  */
@@ -232,7 +215,7 @@ export function runInputTelDropdownSuite({ klass } = { klass: LionInputTelDropdo
232
215
  it('renders to prefix slot in light dom', async () => {
233
216
  const el = await fixture(html` <${tag} .allowedRegions="${['DE']}"></${tag}> `);
234
217
  const prefixSlot = /** @type {HTMLElement} */ (
235
- /** @type {HTMLElement} */ (el.refs.dropdown.value).parentElement
218
+ /** @type {HTMLElement} */ (el.refs.dropdown.value)
236
219
  );
237
220
  expect(prefixSlot.getAttribute('slot')).to.equal('prefix');
238
221
  expect(prefixSlot.slot).to.equal('prefix');
@@ -335,26 +318,6 @@ export function runInputTelDropdownSuite({ klass } = { klass: LionInputTelDropdo
335
318
  expect(el.value).to.equal('+32');
336
319
  });
337
320
 
338
- it('focuses the textbox right after selection if selected via opened dropdown', async () => {
339
- const el = await fixture(
340
- html` <${tag} .allowedRegions="${[
341
- 'NL',
342
- 'BE',
343
- ]}" .modelValue="${'+31612345678'}"></${tag}> `,
344
- );
345
- const dropdownElement = el.refs.dropdown.value;
346
- // @ts-expect-error [allow-protected-in-tests]
347
- if (dropdownElement?._overlayCtrl) {
348
- // @ts-expect-error [allow-protected-in-tests]
349
- dropdownElement._overlayCtrl.show();
350
- mimicUserChangingDropdown(dropdownElement, 'BE');
351
- await el.updateComplete;
352
- await aTimeout(0);
353
- // @ts-expect-error [allow-protected-in-tests]
354
- expect(el._inputNode).to.equal(document.activeElement);
355
- }
356
- });
357
-
358
321
  it('keeps focus on dropdownElement after selection if selected via unopened dropdown', async () => {
359
322
  const el = await fixture(
360
323
  html` <${tag} .allowedRegions="${[
@@ -64,11 +64,11 @@ const LocalizeMixinImplementation = superclass =>
64
64
  * hook into LitElement to only render once all translations are loaded
65
65
  * @returns {Promise.<void>}
66
66
  */
67
- async performUpdate() {
67
+ async scheduleUpdate() {
68
68
  if (Object.getPrototypeOf(this).constructor.waitForLocalizeNamespaces) {
69
69
  await this.localizeNamespacesLoaded;
70
70
  }
71
- super.performUpdate();
71
+ super.scheduleUpdate();
72
72
  }
73
73
 
74
74
  connectedCallback() {
@@ -931,7 +931,7 @@ export class OverlayController extends EventTarget {
931
931
  return;
932
932
  }
933
933
 
934
- if (this.elementToFocusAfterHide) {
934
+ if (this.elementToFocusAfterHide instanceof HTMLElement) {
935
935
  this.elementToFocusAfterHide.focus();
936
936
  this.elementToFocusAfterHide.scrollIntoView({ block: 'nearest' });
937
937
  } else {
@@ -57,6 +57,11 @@ class LionFieldWithSelect extends LionField {
57
57
  * @customElement lion-select
58
58
  */
59
59
  export class LionSelect extends LionFieldWithSelect {
60
+ // eslint-disable-next-line class-methods-use-this
61
+ get operationMode() {
62
+ return 'select';
63
+ }
64
+
60
65
  connectedCallback() {
61
66
  super.connectedCallback();
62
67
  this._inputNode.addEventListener('change', this._proxyChangeEvent);
@@ -6,6 +6,11 @@
6
6
  /** @type {Promise<void | object>} */
7
7
  let pendingPromise;
8
8
 
9
+ /**
10
+ * @param {string} string
11
+ */
12
+ const capitalize = string => (string && string[0].toUpperCase() + string.slice(1)) || '';
13
+
9
14
  /**
10
15
  * @param {{localize: LocalizeManager}} opts
11
16
  */
@@ -105,7 +110,13 @@ export async function loadValidateNamespace({ localize }) {
105
110
  export const getLocalizedMessage = async ({ data, localize }) => {
106
111
  await loadValidateNamespace({ localize });
107
112
  if (data) {
108
- return localize.msg(`lion-validate:${data.type}.${data.name}`, data);
113
+ const operationMode =
114
+ data.formControl?.operationMode !== 'enter' && data.name === 'Required'
115
+ ? capitalize(data.formControl?.operationMode)
116
+ : undefined;
117
+ const validatorName = operationMode ? `_${data.name}${operationMode}` : data.name;
118
+
119
+ return localize.msg(`lion-validate:${data.type}.${validatorName}`, data);
109
120
  }
110
121
  return '';
111
122
  };
@@ -0,0 +1,105 @@
1
+ /* eslint-disable no-unused-vars, no-param-reassign */
2
+ import { expect } from '@open-wc/testing';
3
+ import { getLocalizeManager } from '@lion/ui/localize-no-side-effects.js';
4
+ import { MinDate, MinLength, Required } from '@lion/ui/form-core.js';
5
+ import { loadDefaultFeedbackMessagesNoSideEffects } from '@lion/ui/validate-messages-no-side-effects.js';
6
+
7
+ /**
8
+ * @typedef {import('../../form-core/src/validate/Validator.js').Validator} Validator
9
+ */
10
+
11
+ /**
12
+ * @param {Validator} validatorEl
13
+ */
14
+ function getProtectedMembers(validatorEl) {
15
+ // @ts-ignore protected members allowed in test
16
+ return {
17
+ // @ts-ignore
18
+ getMessage: (...args) => validatorEl._getMessage(...args),
19
+ };
20
+ }
21
+
22
+ /**
23
+ * @typedef {import('@lion/ui/types/form-core.js').FormControlHost} FormControlHost
24
+ * @typedef {ArrayConstructor | ObjectConstructor | NumberConstructor | BooleanConstructor | StringConstructor | DateConstructor | 'iban' | 'email'} modelValueType
25
+ */
26
+
27
+ describe('loadDefaultFeedbackMessagesNoSideEffects', () => {
28
+ const localizeManager = getLocalizeManager();
29
+
30
+ it('will set default feedback message for Required', async () => {
31
+ const el = new Required();
32
+ const { getMessage } = getProtectedMembers(el);
33
+ expect(await getMessage()).to.equals(
34
+ 'Please configure an error message for "Required" by overriding "static async getMessage()"',
35
+ );
36
+
37
+ loadDefaultFeedbackMessagesNoSideEffects({ localize: localizeManager });
38
+ expect(await getMessage({ fieldName: 'password' })).to.equal('Please enter a(n) password.');
39
+ });
40
+
41
+ it('passes data to the feedback message', async () => {
42
+ const el = new MinLength(10);
43
+ const { getMessage } = getProtectedMembers(el);
44
+
45
+ loadDefaultFeedbackMessagesNoSideEffects({ localize: localizeManager });
46
+ expect(await getMessage({ fieldName: 'password' })).to.equal(
47
+ 'Please enter a correct password (at least 10 characters).',
48
+ );
49
+
50
+ const el2 = new MinDate(new Date('2024-01-29'));
51
+ // @ts-ignore protected members allowed in test
52
+ expect(await el2._getMessage({ fieldName: 'date' })).to.equal(
53
+ 'Please enter a(n) date after or equal to 29/01/2024.',
54
+ );
55
+ });
56
+
57
+ it('will set select specific feedback message for Required when operationMode is set', async () => {
58
+ const el = new Required();
59
+ loadDefaultFeedbackMessagesNoSideEffects({ localize: localizeManager });
60
+ const { getMessage } = getProtectedMembers(el);
61
+ const formControl = { operationMode: 'select' };
62
+ expect(await getMessage({ fieldName: 'password', formControl })).to.equal(
63
+ 'Please select a(n) password.',
64
+ );
65
+ });
66
+
67
+ it('will set upload specific feedback message for Required when operationMode is set', async () => {
68
+ const el = new Required();
69
+ const { getMessage } = getProtectedMembers(el);
70
+
71
+ loadDefaultFeedbackMessagesNoSideEffects({ localize: localizeManager });
72
+ const formControl = { operationMode: 'upload' };
73
+ expect(await getMessage({ fieldName: 'password', formControl })).to.equal(
74
+ 'Please upload a(n) password.',
75
+ );
76
+ });
77
+
78
+ it('will set ignore the operationMode for any other validator then Required, e.g. MinLength', async () => {
79
+ const el = new MinLength(10);
80
+ const { getMessage } = getProtectedMembers(el);
81
+
82
+ loadDefaultFeedbackMessagesNoSideEffects({ localize: localizeManager });
83
+ const formControl = { operationMode: 'select' };
84
+ expect(await getMessage({ fieldName: 'password', formControl })).to.equal(
85
+ 'Please enter a correct password (at least 10 characters).',
86
+ );
87
+ });
88
+
89
+ it('will await loading of translations when switching locale', async () => {
90
+ const el = new Required();
91
+ const { getMessage } = getProtectedMembers(el);
92
+ loadDefaultFeedbackMessagesNoSideEffects({ localize: localizeManager });
93
+ expect(await getMessage({ fieldName: 'password' })).to.equal('Please enter a(n) password.');
94
+ expect(await getMessage({ fieldName: 'user name' })).to.equal('Please enter a(n) user name.');
95
+
96
+ localizeManager.locale = 'de-DE';
97
+ await localizeManager.loadingComplete;
98
+ expect(await getMessage({ fieldName: 'Password' })).to.equal(
99
+ 'Password muss ausgefüllt werden.',
100
+ );
101
+ expect(await getMessage({ fieldName: 'Benutzername' })).to.equal(
102
+ 'Benutzername muss ausgefüllt werden.',
103
+ );
104
+ });
105
+ });
@@ -1,6 +1,8 @@
1
1
  export default {
2
2
  error: {
3
3
  Required: 'Моля, въведете също {fieldName}.',
4
+ _RequiredUpload: 'Моля, качете {fieldName}.',
5
+ _RequiredSelect: 'Wählen Sie auch einen Wert für {fieldName} aus.',
4
6
  EqualsLength: 'Моля, въведете правилно {fieldName} от точно {params} знака.',
5
7
  MinLength: 'Моля, въведете правилен {fieldName} (поне {params}).',
6
8
  MaxLength: 'Моля, въведете правилен {fieldName} (до {params} знака).',
@@ -22,6 +24,8 @@ export default {
22
24
  },
23
25
  warning: {
24
26
  Required: 'Моля, въведете също {fieldName}.',
27
+ _RequiredUpload: 'Моля, качете {fieldName}.',
28
+ _RequiredSelect: 'Wählen Sie auch einen Wert für {fieldName} aus.',
25
29
  EqualsLength: 'Моля, въведете правилно {fieldName} от точно {params} знака.',
26
30
  MinLength: 'Моля, въведете правилен {fieldName} (поне {params}).',
27
31
  MaxLength: 'Моля, въведете правилен {fieldName} (до {params} знака).',
@@ -1,6 +1,8 @@
1
1
  export default {
2
2
  error: {
3
3
  Required: 'Zadejte rovněž {fieldName}.',
4
+ _RequiredUpload: 'Nahrajte {fieldname}.',
5
+ _RequiredSelect: 'Vyberte rovněž {fieldname}.',
4
6
  EqualsLength: 'Zadejte správné {fieldName}, přesně {params} znaků.',
5
7
  MinLength: 'Zadejte správné {fieldName} (alespoň {params}).',
6
8
  MaxLength: 'Zadejte správné {fieldName} (až {params} znaků).',
@@ -21,6 +23,8 @@ export default {
21
23
  },
22
24
  warning: {
23
25
  Required: 'Zadejte rovněž {fieldName}.',
26
+ _RequiredUpload: 'Nahrajte {fieldname}.',
27
+ _RequiredSelect: 'Vyberte rovněž {fieldname}.',
24
28
  EqualsLength: 'Zadejte správné {fieldName}, přesně {params} znaků.',
25
29
  MinLength: 'Zadejte správné {fieldName} (alespoň {params}).',
26
30
  MaxLength: 'Zadejte správné {fieldName} (až {params} znaků).',
@@ -1,6 +1,8 @@
1
1
  export default {
2
2
  error: {
3
3
  Required: '{fieldName} muss ausgefüllt werden.',
4
+ _RequiredUpload: 'Bitte laden Sie ein/e/n {fieldName} hoch.',
5
+ _RequiredSelect: 'Wählen Sie auch einen Wert für {fieldName} aus.',
4
6
  EqualsLength: 'Geben Sie einen korrekten Wert für {fieldName} mit exakt {params} Zeichen ein.',
5
7
  MinLength: 'Du musst mindestens {params} Zeichen eingeben.',
6
8
  MaxLength: 'Du kannst maximal {params} Zeichen eingeben.',
@@ -23,6 +25,8 @@ export default {
23
25
  },
24
26
  warning: {
25
27
  Required: '{fieldName} sollte ausgefüllt werden.',
28
+ _RequiredUpload: 'Bitte laden Sie ein/e/n {fieldName} hoch.',
29
+ _RequiredSelect: 'Wählen Sie auch einen Wert für {fieldName} aus.',
26
30
  EqualsLength: 'Geben Sie einen korrekten Wert für {fieldName} mit exakt {params} Zeichen ein.',
27
31
  MinLength: 'Du solltest mindestens {params} Zeichen eingeben.',
28
32
  MaxLength: 'Du kannst maximal {params} Zeichen eingeben.',
@@ -1,6 +1,8 @@
1
1
  export default {
2
2
  error: {
3
3
  Required: 'Please enter a(n) {fieldName}.',
4
+ _RequiredUpload: 'Please upload a(n) {fieldName}.',
5
+ _RequiredSelect: 'Please select a(n) {fieldName}.',
4
6
  EqualsLength: 'Please enter a correct {fieldName} of exactly {params} characters.',
5
7
  MinLength: 'Please enter a correct {fieldName} (at least {params} characters).',
6
8
  MaxLength: 'Please enter a correct {fieldName} (up to {params} characters).',
@@ -22,8 +24,10 @@ export default {
22
24
  },
23
25
  warning: {
24
26
  Required: 'Please enter a(n) {fieldName}.',
27
+ _RequiredUpload: 'Please upload a(n) {fieldName}.',
28
+ _RequiredSelect: 'Please select a(n) {fieldName}.',
25
29
  EqualsLength: 'Please enter a correct {fieldName} of exactly {params} characters.',
26
- MinLength: 'Please enter a correct {fieldName} (at least {params}).',
30
+ MinLength: 'Please enter a correct {fieldName} (at least {params} characters).',
27
31
  MaxLength: 'Please enter a correct {fieldName} (up to {params} characters).',
28
32
  MinMaxLength:
29
33
  'Please enter a correct {fieldName} (between {params.min} and {params.max} characters).',
@@ -1,6 +1,8 @@
1
1
  export default {
2
2
  error: {
3
3
  Required: 'Introduzca también un/a {fieldName}.',
4
+ _RequiredUpload: 'Cargue un {fieldName}.',
5
+ _RequiredSelect: 'Seleccione también un/a {fieldname}.',
4
6
  EqualsLength: 'Introduzca un/a {fieldName} correcto/a de exactamente {params} caracteres.',
5
7
  MinLength: 'Introduzca un/a {fieldName} correcto/a (de al menos {params} caracteres).',
6
8
  MaxLength: 'Introduzca un/a {fieldName} correcto/a (hasta {params} caracteres).',
@@ -23,6 +25,8 @@ export default {
23
25
  },
24
26
  warning: {
25
27
  Required: 'Introduzca también un/a {fieldName}.',
28
+ _RequiredUpload: 'Cargue un {fieldName}.',
29
+ _RequiredSelect: 'Seleccione también un/a {fieldname}.',
26
30
  EqualsLength: 'Introduzca un/a {fieldName} correcto/a de exactamente {params} caracteres.',
27
31
  MinLength: 'Introduzca un/a {fieldName} correcto/a (de al menos {params} caracteres).',
28
32
  MaxLength: 'Introduzca un/a {fieldName} correcto/a (hasta {params} caracteres).',
@@ -1,6 +1,8 @@
1
1
  export default {
2
2
  error: {
3
3
  Required: 'Veuillez également indiquer un(e) {fieldName}.',
4
+ _RequiredUpload: 'Veuillez télécharger un(e) {fieldName}.',
5
+ _RequiredSelect: 'Veuillez également sélectionner un(e) {fieldName}.',
4
6
  EqualsLength:
5
7
  'Veuillez saisir un(e) {fieldName} correct(e) comptant précisément {params} caractères.',
6
8
  MinLength: 'Veuillez indiquer un(e) {fieldName} correct(e) (au moins {params}).',
@@ -24,6 +26,8 @@ export default {
24
26
  },
25
27
  warning: {
26
28
  Required: 'Veuillez également indiquer un(e) {fieldName}.',
29
+ _RequiredUpload: 'Veuillez télécharger un(e) {fieldName}.',
30
+ _RequiredSelect: 'Veuillez également sélectionner un(e) {fieldName}.',
27
31
  EqualsLength:
28
32
  'Veuillez saisir un(e) {fieldName} correct(e) comptant précisément {params} caractères.',
29
33
  MinLength: 'Veuillez indiquer un(e) {fieldName} correct(e) (au moins {params}).',
@@ -1,6 +1,8 @@
1
1
  export default {
2
2
  error: {
3
3
  Required: 'Továbbá adjon meg egy {fieldName} értéket.',
4
+ _RequiredUpload: 'Töltsön fel egy {fieldName} elemet.',
5
+ _RequiredSelect: 'Továbbá válasszon ki egy {fieldname} értéket.',
4
6
  EqualsLength: 'Adjon meg egy helyes {fieldName} értéket (pontosan {params} karakter).',
5
7
  MinLength: 'Adjon meg egy helyes {fieldName} értéket (legalább {params}).',
6
8
  MaxLength: 'Adjon meg egy helyes {fieldName} értéket (legfeljebb {params} karakter).',
@@ -23,6 +25,8 @@ export default {
23
25
  },
24
26
  warning: {
25
27
  Required: 'Továbbá adjon meg egy {fieldName} értéket.',
28
+ _RequiredUpload: 'Töltsön fel egy {fieldName} elemet.',
29
+ _RequiredSelect: 'Továbbá válasszon ki egy {fieldname} értéket.',
26
30
  EqualsLength: 'Adjon meg egy helyes {fieldName} értéket (pontosan {params} karakter).',
27
31
  MinLength: 'Adjon meg egy helyes {fieldName} értéket (legalább {params}).',
28
32
  MaxLength: 'Adjon meg egy helyes {fieldName} értéket (legfeljebb {params} karakter).',
@@ -1,6 +1,8 @@
1
1
  export default {
2
2
  error: {
3
3
  Required: 'Inserire anche un(a) {fieldName}.',
4
+ _RequiredUpload: 'Caricare un {fieldName}.',
5
+ _RequiredSelect: 'Selezionare anche un(a) {fieldname}.',
4
6
  EqualsLength: 'Inserire un(a) {fieldName} corretto(a) di esattamente {params} caratteri.',
5
7
  MinLength: 'Inserire un(a) {fieldName} corretto(a) (almeno {params}).',
6
8
  MaxLength: 'Inserire un(a) {fieldName} corretto(a) (fino a {params} caratteri).',
@@ -23,6 +25,8 @@ export default {
23
25
  },
24
26
  warning: {
25
27
  Required: 'Inserire anche un(a) {fieldName}.',
28
+ _RequiredUpload: 'Caricare un {fieldName}.',
29
+ _RequiredSelect: 'Selezionare anche un(a) {fieldname}.',
26
30
  EqualsLength: 'Inserire un(a) {fieldName} corretto(a) di esattamente {params} caratteri.',
27
31
  MinLength: 'Inserire un(a) {fieldName} corretto(a) (almeno {params}).',
28
32
  MaxLength: 'Inserire un(a) {fieldName} corretto(a) (fino a {params} caratteri).',
@@ -1,6 +1,8 @@
1
1
  export default {
2
2
  error: {
3
3
  Required: 'Vul een {fieldName} in.',
4
+ _RequiredUpload: 'Upload een {fieldName}.',
5
+ _RequiredSelect: 'Selecteer een {fieldname}.',
4
6
  EqualsLength: 'Vul een {fieldName} in gelijk aan {params} karakters.',
5
7
  MinLength: 'Vul een {fieldName} in van minimaal {params} karakters.',
6
8
  MaxLength: 'Vul een {fieldName} in van maximaal {params} karakters.',
@@ -22,6 +24,8 @@ export default {
22
24
  },
23
25
  warning: {
24
26
  Required: 'Vul een {fieldName} in.',
27
+ _RequiredUpload: 'Upload een {fieldName}.',
28
+ _RequiredSelect: 'Selecteer een {fieldname}.',
25
29
  EqualsLength: 'Vul een {fieldName} in gelijk aan {params} karakters.',
26
30
  MinLength: 'Vul een {fieldName} in van minimaal {params} karakters.',
27
31
  MaxLength: 'Vul een {fieldName} in van maximaal {params} karakters.',
@@ -1,6 +1,8 @@
1
1
  export default {
2
2
  error: {
3
3
  Required: 'Proszę również podać wartość {fieldName}.',
4
+ _RequiredUpload: 'Prześlij plik {fieldName}.',
5
+ _RequiredSelect: 'Wprowadź prawidłową wartość w polu {fieldname}.',
4
6
  EqualsLength: 'Wprowadź prawidłową wartość w polu {fieldName} (maks. liczba znaków: {params}).',
5
7
  MinLength: 'Proszę podać prawidłową wartość {fieldName} (co najmniej {params} znaków).',
6
8
  MaxLength: 'Proszę podać prawidłową wartość {fieldName} (maks. {params} znaków).',
@@ -22,6 +24,8 @@ export default {
22
24
  },
23
25
  warning: {
24
26
  Required: 'Proszę również podać wartość {fieldName}.',
27
+ _RequiredUpload: 'Prześlij plik {fieldName}.',
28
+ _RequiredSelect: 'Wprowadź prawidłową wartość w polu {fieldname}.',
25
29
  EqualsLength: 'Wprowadź prawidłową wartość w polu {fieldName} (maks. liczba znaków: {params}).',
26
30
  MinLength: 'Proszę podać prawidłową wartość {fieldName} (co najmniej {params} znaków).',
27
31
  MaxLength: 'Proszę podać prawidłową wartość {fieldName} (maks. {params} znaków).',
@@ -1,6 +1,8 @@
1
1
  export default {
2
2
  error: {
3
3
  Required: 'Introduceți un/o {fieldName}.',
4
+ _RequiredUpload: 'Încărcaţi un {fieldName}.',
5
+ _RequiredSelect: 'Selectați un/o {fieldName}.',
4
6
  EqualsLength: 'Introduceți un/o {fieldName} corect(ă) de exact {params} (de) caractere.',
5
7
  MinLength: 'Introduceți un/o {fieldName} corect(ă) (cel puțin {params}).',
6
8
  MaxLength: 'Introduceți un/o {fieldName} corect(ă) (până la {params} (de) caractere).',
@@ -23,6 +25,8 @@ export default {
23
25
  },
24
26
  warning: {
25
27
  Required: 'Introduceți un/o {fieldName}.',
28
+ _RequiredUpload: 'Încărcaţi un {fieldName}.',
29
+ _RequiredSelect: 'Selectați un/o {fieldName}.',
26
30
  EqualsLength: 'Introduceți un/o {fieldName} corect(ă) de exact {params} (de) caractere.',
27
31
  MinLength: 'Introduceți un/o {fieldName} corect(ă) (cel puțin {params}).',
28
32
  MaxLength: 'Introduceți un/o {fieldName} corect(ă) (până la {params} (de) caractere).',
@@ -1,6 +1,8 @@
1
1
  export default {
2
2
  error: {
3
3
  Required: 'Введите значение поля {fieldName}.',
4
+ _RequiredUpload: 'Загрузите {fieldName}.',
5
+ _RequiredSelect: 'Также выберите значение поля {fieldname}.',
4
6
  EqualsLength: 'Введите корректное значение поля {fieldName} — ровно {params} симв.',
5
7
  MinLength: 'Введите корректное значение поля {fieldName} (не менее {params}).',
6
8
  MaxLength: 'Введите корректное значение поля {fieldName} (до {params} симв.).',
@@ -23,6 +25,8 @@ export default {
23
25
  },
24
26
  warning: {
25
27
  Required: 'Введите значение поля {fieldName}.',
28
+ _RequiredUpload: 'Загрузите {fieldName}.',
29
+ _RequiredSelect: 'Также выберите значение поля {fieldname}.',
26
30
  EqualsLength: 'Введите корректное значение поля {fieldName} — ровно {paramsn} симв.',
27
31
  MinLength: 'Введите корректное значение поля {fieldName} (не менее {params}).',
28
32
  MaxLength: 'Введите корректное значение поля {fieldName} (до {params} симв.).',