@lion/ui 0.4.1 → 0.5.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.
Files changed (158) hide show
  1. package/components/calendar/src/LionCalendar.js +5 -3
  2. package/components/calendar/test-helpers/DayObject.js +2 -2
  3. package/components/combobox/src/LionCombobox.js +82 -29
  4. package/components/combobox/test/lion-combobox-integrations.test.js +5 -0
  5. package/components/combobox/test/lion-combobox.test.js +318 -23
  6. package/components/combobox/test-helpers/combobox-helpers.js +19 -22
  7. package/components/drawer/src/LionDrawer.js +1 -0
  8. package/components/form-core/src/FocusMixin.js +2 -0
  9. package/components/form-core/src/FormControlMixin.js +1 -1
  10. package/components/form-core/src/choice-group/ChoiceGroupMixin.js +1 -0
  11. package/components/form-core/src/choice-group/CustomChoiceGroupMixin.js +173 -0
  12. package/components/form-core/src/utils/getAriaElementsInRightDomOrder.js +7 -14
  13. package/components/form-core/src/validate/validators/Required.js +2 -2
  14. package/components/form-core/test/choice-group/CustomChoiceGroupMixin.integrations.test.js +55 -0
  15. package/components/form-core/test/choice-group/CustomChoiceGroupMixin.test.js +16 -0
  16. package/components/form-core/test/utils/getAriaElementsInRightDomOrder.test.js +0 -25
  17. package/components/form-core/test/validate/StringValidators.test.js +1 -1
  18. package/components/form-core/test-helpers/ExampleValidators.js +1 -3
  19. package/components/form-core/test-suites/FormRegistrationMixins.suite.js +2 -0
  20. package/components/form-core/test-suites/NativeTextFieldMixin.suite.js +4 -4
  21. package/components/form-core/test-suites/ValidateMixin.suite.js +27 -0
  22. package/components/form-core/test-suites/ValidateMixinFeedbackPart.suite.js +11 -2
  23. package/components/form-core/test-suites/choice-group/ChoiceGroupMixin.suite.js +1 -0
  24. package/components/form-core/test-suites/choice-group/CustomChoiceGroupMixin.suite.js +265 -0
  25. package/components/form-core/types/choice-group/ChoiceGroupMixinTypes.ts +1 -1
  26. package/components/form-core/types/choice-group/CustomChoiceGroupMixinTypes.ts +30 -0
  27. package/components/form-core/types/choice-group/index.ts +1 -0
  28. package/components/helpers/src/SbActionLogger.js +1 -0
  29. package/components/icon/src/LionIcon.js +1 -9
  30. package/components/icon/test/lion-icon.test.js +2 -0
  31. package/components/input-amount/src/LionInputAmount.js +5 -2
  32. package/components/input-amount/test/lion-input-amount.test.js +21 -0
  33. package/components/input-range/test/lion-input-range.test.js +12 -6
  34. package/components/listbox/src/LionOptions.js +5 -5
  35. package/components/listbox/src/ListboxMixin.js +1 -16
  36. package/components/listbox/test/lion-options.test.js +1 -1
  37. package/components/listbox/test-suites/ListboxMixin.suite.js +1 -1
  38. package/components/localize/src/date/getMonthNames.js +3 -0
  39. package/components/localize/src/date/utils/forceDotsForNlnl.js +11 -0
  40. package/components/localize/src/number/utils/normalize-format-number-to-parts/forceAddGroupSeparators.js +3 -1
  41. package/components/localize/src/number/utils/normalize-format-number-to-parts/forceSymbols.js +2 -0
  42. package/components/localize/src/number/utils/normalize-format-number-to-parts/normalizeIntl.js +1 -0
  43. package/components/localize/test/date/getMonthNames.test.js +1 -0
  44. package/components/localize/test-helpers/fake-imports.js +1 -0
  45. package/components/overlays/src/utils/adopt-styles.js +1 -1
  46. package/components/radio-group/src/LionRadioGroup.js +1 -1
  47. package/components/radio-group/test/lion-radio-group.test.js +29 -0
  48. package/components/select/test/lion-select.test.js +1 -1
  49. package/components/switch/src/LionSwitchButton.js +1 -5
  50. package/components/tabs/src/LionTabs.js +7 -7
  51. package/components/textarea/src/LionTextarea.js +1 -1
  52. package/custom-elements.json +103314 -61972
  53. package/dist-types/components/calendar/src/LionCalendar.d.ts.map +1 -1
  54. package/dist-types/components/combobox/src/LionCombobox.d.ts +13 -8
  55. package/dist-types/components/combobox/src/LionCombobox.d.ts.map +1 -1
  56. package/dist-types/components/combobox/test-helpers/combobox-helpers.d.ts.map +1 -1
  57. package/dist-types/components/drawer/src/LionDrawer.d.ts.map +1 -1
  58. package/dist-types/components/form-core/src/FocusMixin.d.ts.map +1 -1
  59. package/dist-types/components/form-core/src/choice-group/ChoiceGroupMixin.d.ts.map +1 -1
  60. package/dist-types/components/form-core/src/choice-group/CustomChoiceGroupMixin.d.ts +4 -0
  61. package/dist-types/components/form-core/src/choice-group/CustomChoiceGroupMixin.d.ts.map +1 -0
  62. package/dist-types/components/form-core/src/utils/getAriaElementsInRightDomOrder.d.ts +5 -5
  63. package/dist-types/components/form-core/src/utils/getAriaElementsInRightDomOrder.d.ts.map +1 -1
  64. package/dist-types/components/form-core/test/choice-group/CustomChoiceGroupMixin.integrations.test.d.ts +2 -0
  65. package/dist-types/components/form-core/test/choice-group/CustomChoiceGroupMixin.integrations.test.d.ts.map +1 -0
  66. package/dist-types/components/form-core/test/choice-group/CustomChoiceGroupMixin.test.d.ts +6 -0
  67. package/dist-types/components/form-core/test/choice-group/CustomChoiceGroupMixin.test.d.ts.map +1 -0
  68. package/dist-types/components/form-core/test-helpers/ExampleValidators.d.ts +0 -1
  69. package/dist-types/components/form-core/test-helpers/ExampleValidators.d.ts.map +1 -1
  70. package/dist-types/components/form-core/test-suites/FormRegistrationMixins.suite.d.ts.map +1 -1
  71. package/dist-types/components/form-core/test-suites/ValidateMixin.suite.d.ts.map +1 -1
  72. package/dist-types/components/form-core/test-suites/ValidateMixinFeedbackPart.suite.d.ts.map +1 -1
  73. package/dist-types/components/form-core/test-suites/choice-group/ChoiceGroupMixin.suite.d.ts.map +1 -1
  74. package/dist-types/components/form-core/test-suites/choice-group/CustomChoiceGroupMixin.suite.d.ts +14 -0
  75. package/dist-types/components/form-core/test-suites/choice-group/CustomChoiceGroupMixin.suite.d.ts.map +1 -0
  76. package/dist-types/components/form-core/types/choice-group/ChoiceGroupMixinTypes.d.ts +1 -1
  77. package/dist-types/components/form-core/types/choice-group/ChoiceGroupMixinTypes.d.ts.map +1 -1
  78. package/dist-types/components/form-core/types/choice-group/CustomChoiceGroupMixinTypes.d.ts +18 -0
  79. package/dist-types/components/form-core/types/choice-group/CustomChoiceGroupMixinTypes.d.ts.map +1 -0
  80. package/dist-types/components/form-core/types/choice-group/index.d.ts +1 -0
  81. package/dist-types/components/form-core/types/choice-group/index.d.ts.map +1 -1
  82. package/dist-types/components/helpers/src/SbActionLogger.d.ts.map +1 -1
  83. package/dist-types/components/icon/src/LionIcon.d.ts +0 -9
  84. package/dist-types/components/icon/src/LionIcon.d.ts.map +1 -1
  85. package/dist-types/components/input-amount/src/LionInputAmount.d.ts +2 -2
  86. package/dist-types/components/input-amount/src/LionInputAmount.d.ts.map +1 -1
  87. package/dist-types/components/listbox/src/LionOptions.d.ts +0 -5
  88. package/dist-types/components/listbox/src/LionOptions.d.ts.map +1 -1
  89. package/dist-types/components/listbox/src/ListboxMixin.d.ts.map +1 -1
  90. package/dist-types/components/localize/src/date/getMonthNames.d.ts.map +1 -1
  91. package/dist-types/components/localize/src/date/utils/forceDotsForNlnl.d.ts +5 -0
  92. package/dist-types/components/localize/src/date/utils/forceDotsForNlnl.d.ts.map +1 -0
  93. package/dist-types/components/localize/src/number/utils/normalize-format-number-to-parts/forceAddGroupSeparators.d.ts.map +1 -1
  94. package/dist-types/components/localize/src/number/utils/normalize-format-number-to-parts/forceSymbols.d.ts.map +1 -1
  95. package/dist-types/components/localize/src/number/utils/normalize-format-number-to-parts/normalizeIntl.d.ts.map +1 -1
  96. package/dist-types/components/localize/test-helpers/fake-imports.d.ts.map +1 -1
  97. package/dist-types/components/switch/src/LionSwitchButton.d.ts +0 -5
  98. package/dist-types/components/switch/src/LionSwitchButton.d.ts.map +1 -1
  99. package/dist-types/components/tabs/src/LionTabs.d.ts.map +1 -1
  100. package/dist-types/exports/types/form-core.d.ts +1 -1
  101. package/dist-types/exports/types/form-core.d.ts.map +1 -1
  102. package/dist-types/tsconfig.tsbuildinfo +1 -1
  103. package/docs/components/checkbox-group/overview.md +2 -2
  104. package/docs/components/collapsible/assets/CustomCollapsible.js +4 -0
  105. package/docs/components/collapsible/overview.md +1 -1
  106. package/docs/components/combobox/overview.md +1 -1
  107. package/docs/components/combobox/src/demo-selection-display.js +8 -35
  108. package/docs/components/combobox/use-cases.md +24 -1
  109. package/docs/components/dialog/overview.md +1 -1
  110. package/docs/components/fieldset/overview.md +5 -5
  111. package/docs/components/form/overview.md +3 -3
  112. package/docs/components/icon/use-cases.md +1 -1
  113. package/docs/components/input/overview.md +1 -1
  114. package/docs/components/input-amount/overview.md +3 -3
  115. package/docs/components/input-date/overview.md +3 -3
  116. package/docs/components/input-datepicker/overview.md +5 -5
  117. package/docs/components/input-email/overview.md +2 -2
  118. package/docs/components/input-file/overview.md +1 -1
  119. package/docs/components/input-iban/overview.md +2 -2
  120. package/docs/components/input-range/overview.md +2 -2
  121. package/docs/components/input-stepper/overview.md +1 -1
  122. package/docs/components/input-tel/overview.md +1 -1
  123. package/docs/components/input-tel/use-cases.md +6 -6
  124. package/docs/components/input-tel-dropdown/overview.md +1 -1
  125. package/docs/components/radio-group/overview.md +3 -3
  126. package/docs/components/select-rich/use-cases.md +1 -1
  127. package/docs/components/steps/overview.md +2 -4
  128. package/docs/components/tabs/examples.md +1 -1
  129. package/docs/fundamentals/index.md +4 -4
  130. package/docs/fundamentals/node-tools/providence-analytics/LocalConfiguration.md +1 -1
  131. package/docs/fundamentals/node-tools/providence-analytics/QueryResult.md +1 -1
  132. package/docs/fundamentals/node-tools/providence-analytics/analyzer.md +1 -1
  133. package/docs/fundamentals/node-tools/providence-analytics/dashboard.md +1 -1
  134. package/docs/fundamentals/node-tools/providence-analytics/overview.md +3 -3
  135. package/docs/fundamentals/node-tools/publish-docs/overview.md +3 -3
  136. package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +2 -2
  137. package/docs/fundamentals/rationales/accessibility.md +3 -3
  138. package/docs/fundamentals/systems/core/SlotMixin.md +1 -1
  139. package/docs/fundamentals/systems/core/overview.md +1 -1
  140. package/docs/fundamentals/systems/form/formatting-and-parsing.md +4 -4
  141. package/docs/fundamentals/systems/form/model-value.md +1 -1
  142. package/docs/fundamentals/systems/form/overview.md +28 -28
  143. package/docs/fundamentals/systems/form/validate.md +18 -2
  144. package/docs/fundamentals/systems/localize/overview.md +4 -4
  145. package/docs/fundamentals/systems/overlays/configuration.md +3 -2
  146. package/docs/fundamentals/systems/overlays/overview.md +5 -5
  147. package/docs/fundamentals/systems/overlays/use-cases.md +2 -2
  148. package/docs/fundamentals/tools/helpers/overview.md +1 -1
  149. package/docs/fundamentals/tools/singleton-manager/example-complex/overlayCompatibility.js +1 -2
  150. package/docs/fundamentals/tools/singleton-manager/overview.md +4 -4
  151. package/docs/guides/how-to/create-a-custom-field.md +5 -5
  152. package/docs/guides/how-to/create-a-form.md +4 -4
  153. package/docs/guides/how-to/extend-a-native-input.md +2 -2
  154. package/docs/guides/index.md +8 -8
  155. package/docs/guides/principles/index.md +5 -5
  156. package/docs/guides/principles/styling.md +1 -1
  157. package/exports/types/form-core.ts +5 -1
  158. package/package.json +1 -1
@@ -0,0 +1,265 @@
1
+ import '@lion/ui/define/lion-fieldset.js';
2
+ import '@lion/ui/define/lion-checkbox-group.js';
3
+ import '@lion/ui/define/lion-checkbox.js';
4
+ import { expect, fixture, fixtureSync, html, unsafeStatic } from '@open-wc/testing';
5
+
6
+ /**
7
+ *
8
+ * @typedef {import('../../test/choice-group/CustomChoiceGroupMixin.test.js').CustomChoiceGroup} CustomChoiceGroup
9
+ */
10
+
11
+ /**
12
+ * @param {{ parentTagString?:string, childTagString?: string, choiceType?: string}} config
13
+ */
14
+ export function runCustomChoiceGroupMixinSuite({
15
+ parentTagString,
16
+ childTagString,
17
+ choiceType,
18
+ } = {}) {
19
+ const cfg = {
20
+ parentTagString: parentTagString || 'custom-choice-input-group',
21
+ childTagString: childTagString || 'custom-choice-input',
22
+ choiceType: choiceType || 'single',
23
+ };
24
+
25
+ const parentTag = unsafeStatic(cfg.parentTagString);
26
+ const childTag = unsafeStatic(cfg.childTagString);
27
+
28
+ describe(`CustomChoiceGroupMixin: ${cfg.parentTagString}`, () => {
29
+ if (cfg.choiceType === 'single') {
30
+ it('has a single modelValue representing a custom value', async () => {
31
+ const el = /** @type {CustomChoiceGroup} */ (
32
+ await fixture(html`
33
+ <${parentTag} allow-custom-choice name="gender[]">
34
+ <${childTag} .choiceValue=${'male'}></${childTag}>
35
+ <${childTag} checked .choiceValue=${'female'}></${childTag}>
36
+ </${parentTag}>
37
+ `)
38
+ );
39
+
40
+ await el.registrationComplete;
41
+
42
+ expect(el.modelValue).to.equal('female');
43
+ el.modelValue = 'male';
44
+ expect(el.modelValue).to.equal('male');
45
+
46
+ el.modelValue = 'other';
47
+ expect(el.modelValue).to.equal('other');
48
+
49
+ expect(el.formElements[0].checked).to.be.false;
50
+ expect(el.formElements[1].checked).to.be.false;
51
+ });
52
+
53
+ it('has a single formattedValue representing a custom value', async () => {
54
+ const el = /** @type {CustomChoiceGroup} */ (
55
+ await fixture(html`
56
+ <${parentTag} allow-custom-choice name="gender">
57
+ <${childTag} .choiceValue=${'male'}></${childTag}>
58
+ <${childTag} .choiceValue=${'female'} checked></${childTag}>
59
+ </${parentTag}>
60
+ `)
61
+ );
62
+
63
+ el.modelValue = 'other';
64
+ expect(el.formattedValue).to.equal('other');
65
+ });
66
+ }
67
+
68
+ it('can set initial custom modelValue on creation', async () => {
69
+ const el = /** @type {CustomChoiceGroup} */ (
70
+ await fixture(html`
71
+ <${parentTag} allow-custom-choice name="gender[]" .modelValue=${'other'}>
72
+ <${childTag} .choiceValue=${'male'}></${childTag}>
73
+ <${childTag} .choiceValue=${'female'}></${childTag}>
74
+ </${parentTag}>
75
+ `)
76
+ );
77
+
78
+ if (cfg.choiceType === 'single') {
79
+ expect(el.modelValue).to.equal('other');
80
+ } else {
81
+ expect(el.modelValue).to.deep.equal(['other']);
82
+ }
83
+ expect(el.formElements[0].checked).to.be.false;
84
+ expect(el.formElements[1].checked).to.be.false;
85
+ });
86
+
87
+ it('can set initial custom serializedValue on creation', async () => {
88
+ const el = /** @type {CustomChoiceGroup} */ (
89
+ await fixture(html`
90
+ <${parentTag} allow-custom-choice name="gender[]" .serializedValue=${'other'}>
91
+ <${childTag} .choiceValue=${'male'}></${childTag}>
92
+ <${childTag} .choiceValue=${'female'}></${childTag}>
93
+ </${parentTag}>
94
+ `)
95
+ );
96
+
97
+ if (cfg.choiceType === 'single') {
98
+ expect(el.serializedValue).to.equal('other');
99
+ } else {
100
+ expect(el.serializedValue).to.deep.equal(['other']);
101
+ }
102
+ expect(el.formElements[0].checked).to.be.false;
103
+ expect(el.formElements[1].checked).to.be.false;
104
+ });
105
+
106
+ it('can set initial custom formattedValue on creation', async () => {
107
+ const el = /** @type {CustomChoiceGroup} */ (
108
+ await fixture(html`
109
+ <${parentTag} allow-custom-choice name="gender[]" .formattedValue=${'other'}>
110
+ <${childTag} .choiceValue=${'male'}></${childTag}>
111
+ <${childTag} .choiceValue=${'female'}></${childTag}>
112
+ </${parentTag}>
113
+ `)
114
+ );
115
+
116
+ if (cfg.choiceType === 'single') {
117
+ expect(el.formattedValue).to.equal('other');
118
+ } else {
119
+ expect(el.formattedValue).to.deep.equal(['other']);
120
+ }
121
+ expect(el.formElements[0].checked).to.be.false;
122
+ expect(el.formElements[1].checked).to.be.false;
123
+ });
124
+
125
+ it('correctly handles custom modelValue being set before registrationComplete', async () => {
126
+ const el = /** @type {CustomChoiceGroup} */ (
127
+ fixtureSync(html`
128
+ <${parentTag} allow-custom-choice name="gender[]" .modelValue=${null}>
129
+ <${childTag} .choiceValue=${'male'}></${childTag}>
130
+ <${childTag} .choiceValue=${'female'}></${childTag}>
131
+ </${parentTag}>
132
+ `)
133
+ );
134
+
135
+ if (cfg.choiceType === 'single') {
136
+ el.modelValue = 'other';
137
+ await el.registrationComplete;
138
+ expect(el.modelValue).to.equal('other');
139
+ } else {
140
+ el.modelValue = ['other'];
141
+ await el.registrationComplete;
142
+ expect(el.modelValue).to.deep.equal(['other']);
143
+ }
144
+ });
145
+
146
+ it('correctly handles custom serializedValue being set before registrationComplete', async () => {
147
+ const el = /** @type {CustomChoiceGroup} */ (
148
+ fixtureSync(html`
149
+ <${parentTag} allow-custom-choice name="gender[]" .serializedValue=${null}>
150
+ <${childTag} .choiceValue=${'male'}></${childTag}>
151
+ <${childTag} .choiceValue=${'female'}></${childTag}>
152
+ </${parentTag}>
153
+ `)
154
+ );
155
+
156
+ if (cfg.choiceType === 'single') {
157
+ // @ts-expect-error
158
+ el.serializedValue = 'other';
159
+ await el.registrationComplete;
160
+ expect(el.serializedValue).to.equal('other');
161
+ } else {
162
+ // @ts-expect-error
163
+ el.serializedValue = ['other'];
164
+ await el.registrationComplete;
165
+ expect(el.serializedValue).to.deep.equal(['other']);
166
+ }
167
+ });
168
+
169
+ it('can be cleared, even when a custom value is selected', async () => {
170
+ const el = /** @type {CustomChoiceGroup} */ (
171
+ await fixture(html`
172
+ <${parentTag} allow-custom-choice name="gender[]">
173
+ <${childTag} .choiceValue=${'male'}></${childTag}>
174
+ <${childTag} .choiceValue=${'female'}></${childTag}>
175
+ </${parentTag}>
176
+ `)
177
+ );
178
+ if (cfg.choiceType === 'single') {
179
+ el.modelValue = 'other';
180
+ } else {
181
+ el.modelValue = ['other'];
182
+ }
183
+
184
+ el.clear();
185
+
186
+ if (cfg.choiceType === 'single') {
187
+ expect(el.serializedValue).to.deep.equal('');
188
+ } else {
189
+ expect(el.serializedValue).to.deep.equal([]);
190
+ }
191
+ });
192
+
193
+ describe('multipleChoice', () => {
194
+ it('has a single modelValue representing all currently checked values, including custom values', async () => {
195
+ const el = /** @type {CustomChoiceGroup} */ (
196
+ await fixture(html`
197
+ <${parentTag} allow-custom-choice multiple-choice name="gender[]">
198
+ <${childTag} .choiceValue=${'male'}></${childTag}>
199
+ <${childTag} .choiceValue=${'female'} checked></${childTag}>
200
+ </${parentTag}>
201
+ `)
202
+ );
203
+
204
+ expect(el.modelValue).to.eql(['female']);
205
+
206
+ el.modelValue = ['female', 'male'];
207
+ expect(el.modelValue).to.eql(['male', 'female']);
208
+
209
+ el.modelValue = ['female', 'male', 'other'];
210
+ expect(el.modelValue).to.eql(['male', 'female', 'other']);
211
+ });
212
+
213
+ it('has a single serializedValue representing all currently checked values, including custom values', async () => {
214
+ const el = /** @type {CustomChoiceGroup} */ (
215
+ await fixture(html`
216
+ <${parentTag} allow-custom-choice multiple-choice name="gender[]">
217
+ <${childTag} .choiceValue=${'male'}></${childTag}>
218
+ <${childTag} .choiceValue=${'female'} checked></${childTag}>
219
+ </${parentTag}>
220
+ `)
221
+ );
222
+
223
+ expect(el.serializedValue).to.eql(['female']);
224
+
225
+ el.modelValue = ['female', 'male', 'other'];
226
+ expect(el.serializedValue).to.eql(['male', 'female', 'other']);
227
+ });
228
+
229
+ it('has a single formattedValue representing all currently checked values', async () => {
230
+ const el = /** @type {CustomChoiceGroup} */ (
231
+ await fixture(html`
232
+ <${parentTag} allow-custom-choice multiple-choice name="gender[]">
233
+ <${childTag} .choiceValue=${'male'}></${childTag}>
234
+ <${childTag} .choiceValue=${'female'} checked></${childTag}>
235
+ </${parentTag}>
236
+ `)
237
+ );
238
+
239
+ expect(el.formattedValue).to.eql(['female']);
240
+
241
+ el.modelValue = ['female', 'male', 'other'];
242
+ expect(el.formattedValue).to.eql(['male', 'female', 'other']);
243
+ });
244
+
245
+ it('unchecks non-matching checkboxes when setting the modelValue', async () => {
246
+ const el = /** @type {CustomChoiceGroup} */ (
247
+ await fixture(html`
248
+ <${parentTag} allow-custom-choice multiple-choice name="gender[]">
249
+ <${childTag} .choiceValue=${'male'} checked></${childTag}>
250
+ <${childTag} .choiceValue=${'female'} checked></${childTag}>
251
+ </${parentTag}>
252
+ `)
253
+ );
254
+
255
+ expect(el.modelValue).to.eql(['male', 'female']);
256
+ expect(el.formElements[0].checked).to.be.true;
257
+ expect(el.formElements[1].checked).to.be.true;
258
+
259
+ el.modelValue = ['other'];
260
+ expect(el.formElements[0].checked).to.be.false;
261
+ expect(el.formElements[1].checked).to.be.false;
262
+ });
263
+ });
264
+ });
265
+ }
@@ -25,7 +25,7 @@ export declare class ChoiceGroupHost {
25
25
  filterFn?: (el: FormControl, property?: string) => boolean,
26
26
  ): void;
27
27
  protected _throwWhenInvalidChildModelValue(child: FormControlHost): void;
28
- protected _isEmpty(): void;
28
+ protected _isEmpty(): boolean;
29
29
  protected _checkSingleChoiceElements(ev: Event): void;
30
30
  protected _getCheckedElements(): ChoiceInputHost[];
31
31
  protected _setCheckedElements(value: any, check: boolean): void;
@@ -0,0 +1,30 @@
1
+ import { Constructor } from '@open-wc/dedupe-mixin';
2
+ import { LitElement } from 'lit';
3
+
4
+ import { ChoiceGroupHost } from './ChoiceGroupMixinTypes.js';
5
+
6
+ export declare class CustomChoiceGroupHost {
7
+ allowCustomChoice: boolean;
8
+ get modelValue(): any;
9
+ set modelValue(value: any);
10
+ get serializedValue(): string;
11
+ set serializedValue(value: string);
12
+ get formattedValue(): string;
13
+ set formattedValue(value: string);
14
+
15
+ clear(): void;
16
+ parser(value: string | string[]): string | string[];
17
+
18
+ protected _isEmpty(): boolean;
19
+ }
20
+
21
+ export declare function CustomChoiceGroupImplementation<T extends Constructor<LitElement>>(
22
+ superclass: T,
23
+ ): T &
24
+ Constructor<CustomChoiceGroupHost> &
25
+ Pick<typeof CustomChoiceGroupHost, keyof typeof CustomChoiceGroupHost> &
26
+ Constructor<ChoiceGroupHost> &
27
+ Pick<typeof ChoiceGroupHost, keyof typeof ChoiceGroupHost> &
28
+ Pick<typeof LitElement, keyof typeof LitElement>;
29
+
30
+ export type CustomChoiceGroupMixin = typeof CustomChoiceGroupImplementation;
@@ -1,2 +1,3 @@
1
1
  export * from './ChoiceInputMixinTypes.js';
2
2
  export * from './ChoiceGroupMixinTypes.js';
3
+ export * from './CustomChoiceGroupMixinTypes.js';
@@ -5,6 +5,7 @@ import { css, html, LitElement, render } from 'lit';
5
5
  export class SbActionLogger extends LitElement {
6
6
  static get properties() {
7
7
  return {
8
+ // eslint-disable-next-line lit/no-native-attributes
8
9
  title: { type: String, reflect: true },
9
10
  simple: { type: Boolean, reflect: true },
10
11
  __logCounter: { type: Number },
@@ -57,14 +57,6 @@ export class LionIcon extends LitElement {
57
57
  type: String,
58
58
  attribute: 'icon-id',
59
59
  },
60
- /**
61
- * @private
62
- */
63
- role: {
64
- type: String,
65
- attribute: 'role',
66
- reflect: true,
67
- },
68
60
  };
69
61
  }
70
62
 
@@ -101,7 +93,6 @@ export class LionIcon extends LitElement {
101
93
 
102
94
  constructor() {
103
95
  super();
104
- this.role = 'img';
105
96
  this.ariaLabel = '';
106
97
  this.iconId = '';
107
98
  /**
@@ -131,6 +122,7 @@ export class LionIcon extends LitElement {
131
122
  // ensures that aria-hidden is set if there is no aria-label attribute
132
123
  this._onLabelChanged();
133
124
  super.connectedCallback();
125
+ this.setAttribute('role', 'img');
134
126
  }
135
127
 
136
128
  /**
@@ -185,10 +185,12 @@ describe('lion-icon', () => {
185
185
  try {
186
186
  icons.addIconResolver(
187
187
  'foo',
188
+ // eslint-disable-next-line no-promise-executor-return
188
189
  () => new Promise(resolve => setTimeout(() => resolve(heartSvg), 10)),
189
190
  );
190
191
  icons.addIconResolver(
191
192
  'bar',
193
+ // eslint-disable-next-line no-promise-executor-return
192
194
  () => new Promise(resolve => setTimeout(() => resolve(hammerSvg), 4)),
193
195
  );
194
196
  const el = await fixture(html`<lion-icon icon-id="foo:lorem:ipsum"></lion-icon>`);
@@ -159,6 +159,9 @@ export class LionInputAmount extends LocalizeMixin(LionInput) {
159
159
  if (currency) {
160
160
  if (!this.__currencyDisplayNodeIsConnected) {
161
161
  this.appendChild(this.__currencyDisplayNode);
162
+ this.addToAriaLabelledBy(this.__currencyDisplayNode, {
163
+ idPrefix: this._currencyDisplayNodeSlot,
164
+ });
162
165
  this.__currencyDisplayNodeIsConnected = true;
163
166
  }
164
167
  this.__currencyDisplayNode.textContent = this.__currencyLabel;
@@ -182,11 +185,11 @@ export class LionInputAmount extends LocalizeMixin(LionInput) {
182
185
  }
183
186
 
184
187
  /**
185
- * @returns the current currency display node
188
+ * @returns {HTMLElement | undefined} the current currency display node
186
189
  * @private
187
190
  */
188
191
  get __currencyDisplayNode() {
189
- const node = Array.from(this.children).find(
192
+ const node = /** @type {HTMLElement[]} */ (Array.from(this.children)).find(
190
193
  child => child.slot === this._currencyDisplayNodeSlot,
191
194
  );
192
195
  if (node) {
@@ -308,6 +308,27 @@ describe('<lion-input-amount>', () => {
308
308
  expect(_inputNode.getAttribute('aria-labelledby')).to.contain(label?.id);
309
309
  });
310
310
 
311
+ it('adds currency id to aria-labelledby of input when currency switches from undefined', async () => {
312
+ const el = /** @type {LionInputAmount} */ (
313
+ await fixture(`<lion-input-amount></lion-input-amount>`)
314
+ );
315
+
316
+ el.currency = 'EUR';
317
+
318
+ let resolved = await el.updateComplete;
319
+ while (!resolved) {
320
+ resolved = await el.updateComplete;
321
+ }
322
+
323
+ const label = /** @type {HTMLElement[]} */ (Array.from(el.children)).find(
324
+ child => child.slot === 'after',
325
+ );
326
+ const { _inputNode } = getInputMembers(/** @type {* & LionInput} */ (el));
327
+
328
+ expect(label?.id).not.equal('');
329
+ expect(_inputNode.getAttribute('aria-labelledby')).to.contain(label?.id);
330
+ });
331
+
311
332
  it('adds an aria-label to currency slot', async () => {
312
333
  const el = /** @type {LionInputAmount} */ (
313
334
  await fixture(`<lion-input-amount currency="EUR"></lion-input-amount>`)
@@ -19,10 +19,14 @@ describe('<lion-input-range>', () => {
19
19
  <lion-input-range .modelValue=${75} unit="${`%`}"></lion-input-range>
20
20
  `);
21
21
  expect(
22
- /** @type {HTMLElement} */ (el.shadowRoot?.querySelector('.input-range__value')).innerText,
22
+ /** @type {HTMLElement} */ (
23
+ /** @type {ShadowRoot} */ (el.shadowRoot).querySelector('.input-range__value')
24
+ ).innerText,
23
25
  ).to.equal('75');
24
26
  expect(
25
- /** @type {HTMLElement} */ (el.shadowRoot?.querySelector('.input-range__unit')).innerText,
27
+ /** @type {HTMLElement} */ (
28
+ /** @type {ShadowRoot} */ (el.shadowRoot).querySelector('.input-range__unit')
29
+ ).innerText,
26
30
  ).to.equal('%');
27
31
  });
28
32
 
@@ -30,12 +34,14 @@ describe('<lion-input-range>', () => {
30
34
  const el = await fixture(`<lion-input-range min="100" max="200"></lion-input-range>`);
31
35
  expect(el.shadowRoot?.querySelectorAll('.input-range__limits span').length).to.equal(2);
32
36
  expect(
33
- /** @type {HTMLElement} */ (el.shadowRoot?.querySelectorAll('.input-range__limits span')[0])
34
- .innerText,
37
+ /** @type {HTMLElement} */ (
38
+ /** @type {ShadowRoot} */ (el.shadowRoot).querySelectorAll('.input-range__limits span')[0]
39
+ ).innerText,
35
40
  ).to.equal(el.min.toString());
36
41
  expect(
37
- /** @type {HTMLElement} */ (el.shadowRoot?.querySelectorAll('.input-range__limits span')[1])
38
- .innerText,
42
+ /** @type {HTMLElement} */ (
43
+ /** @type {ShadowRoot} */ (el.shadowRoot).querySelectorAll('.input-range__limits span')[1]
44
+ ).innerText,
39
45
  ).to.equal(el.max.toString());
40
46
  });
41
47
 
@@ -7,10 +7,6 @@ import { FormRegistrarPortalMixin } from '@lion/ui/form-core.js';
7
7
  export class LionOptions extends FormRegistrarPortalMixin(LitElement) {
8
8
  static get properties() {
9
9
  return {
10
- role: {
11
- type: String,
12
- reflect: true,
13
- },
14
10
  tabIndex: {
15
11
  type: Number,
16
12
  reflect: true,
@@ -21,10 +17,14 @@ export class LionOptions extends FormRegistrarPortalMixin(LitElement) {
21
17
 
22
18
  constructor() {
23
19
  super();
24
- this.role = 'listbox';
25
20
  this.tabIndex = 0;
26
21
  }
27
22
 
23
+ connectedCallback() {
24
+ super.connectedCallback();
25
+ this.setAttribute('role', 'listbox');
26
+ }
27
+
28
28
  createRenderRoot() {
29
29
  return this;
30
30
  }
@@ -196,22 +196,6 @@ const ListboxMixinImplementation = superclass =>
196
196
  return this._listboxNode;
197
197
  }
198
198
 
199
- /**
200
- * @override ChoiceGroupMixin
201
- */
202
- get serializedValue() {
203
- return this.modelValue;
204
- }
205
-
206
- // Duplicating from FormGroupMixin, because you cannot independently inherit/override getter + setter.
207
- // If you override one, gotta override the other, they go in pairs.
208
- /**
209
- * @override ChoiceGroupMixin
210
- */
211
- set serializedValue(value) {
212
- super.serializedValue = value;
213
- }
214
-
215
199
  get activeIndex() {
216
200
  return this.formElements.findIndex(el => el.active === true);
217
201
  }
@@ -473,6 +457,7 @@ const ListboxMixinImplementation = superclass =>
473
457
  }
474
458
 
475
459
  clear() {
460
+ super.clear();
476
461
  this.setCheckedIndex(-1);
477
462
  this.resetInteractionState();
478
463
  }
@@ -12,6 +12,6 @@ describe('lion-options', () => {
12
12
  <lion-options .registrationTarget=${registrationTargetEl}></lion-options>
13
13
  `)
14
14
  );
15
- expect(el.role).to.equal('listbox');
15
+ expect(el.getAttribute('role')).to.equal('listbox');
16
16
  });
17
17
  });
@@ -163,7 +163,7 @@ export function runListboxMixinSuite(customConfig = {}) {
163
163
  });
164
164
 
165
165
  it('requests update for modelValue when checkedIndex changes', async () => {
166
- const el = await fixture(html`
166
+ const el = /** @type {LionListbox} */ await fixture(html`
167
167
  <${tag} name="gender" .modelValue=${'other'}>
168
168
  <${optionTag} .choiceValue=${'male'}></${optionTag}>
169
169
  <${optionTag} .choiceValue=${'female'}></${optionTag}>
@@ -1,5 +1,6 @@
1
1
  import { normalizeIntlDate } from './utils/normalizeIntlDate.js';
2
2
  import { forceShortMonthNamesForEnGb } from './utils/forceShortMonthNamesForEnGb.js';
3
+ import { forceDotsForNlnl } from './utils/forceDotsForNlnl.js';
3
4
 
4
5
  /** @type {Object.<string, Object.<string,string[]>>} */
5
6
  const monthsLocaleCache = {};
@@ -29,6 +30,8 @@ export function getMonthNames({ locale = 'en-GB', style = 'long' } = {}) {
29
30
  }
30
31
  if (locale === 'en-GB' && style === 'short') {
31
32
  months = forceShortMonthNamesForEnGb(months);
33
+ } else if (locale === 'nl-NL' && style === 'short') {
34
+ months = forceDotsForNlnl(months);
32
35
  }
33
36
  monthsLocaleCache[locale] = monthsLocaleCache[locale] || {};
34
37
  monthsLocaleCache[locale][style] = months;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @param {string[]} months
3
+ */
4
+ export function forceDotsForNlnl(months) {
5
+ return months.map(m => {
6
+ if (m !== 'mei' && !m.endsWith('.')) {
7
+ return `${m}.`;
8
+ }
9
+ return m;
10
+ });
11
+ }
@@ -13,7 +13,7 @@ export function forceAddGroupSeparators(formattedParts, groupSeparator) {
13
13
  let integerPart;
14
14
 
15
15
  for (let i = 0; i < formattedParts.length; i += 1) {
16
- if (formattedParts[i].type === 'integer') {
16
+ if (formattedParts[i].type === 'integer' && formattedParts[i].value.length > 3) {
17
17
  firstPart = formattedParts.splice(0, i);
18
18
  integerPart = formattedParts.splice(0, 1);
19
19
  }
@@ -66,6 +66,8 @@ export function forceAddGroupSeparators(formattedParts, groupSeparator) {
66
66
  if (firstPart) {
67
67
  concatArray = firstPart.concat(numberArray, formattedParts);
68
68
  }
69
+ } else {
70
+ return formattedParts;
69
71
  }
70
72
  return concatArray;
71
73
  }
@@ -17,6 +17,7 @@ const CURRENCY_CODE_SYMBOL_MAP = {
17
17
  * @param {string[]} currencyScope
18
18
  * @returns {FormatNumberPart[]}
19
19
  */
20
+ // eslint-disable-next-line default-param-last
20
21
  export function forceSymbols(formattedParts, { currency, currencyDisplay } = {}, currencyScope) {
21
22
  const result = formattedParts;
22
23
  if (
@@ -44,6 +45,7 @@ export function forceSymbols(formattedParts, { currency, currencyDisplay } = {},
44
45
  */
45
46
  export function forceFRBESymbols(
46
47
  formattedParts,
48
+ // eslint-disable-next-line default-param-last
47
49
  { currency, currencyDisplay } = {},
48
50
  currencyScope,
49
51
  ) {
@@ -17,6 +17,7 @@ import { forceFRBESymbols, forceSymbols } from './forceSymbols.js';
17
17
  * @param {string} _locale
18
18
  * @returns {FormatNumberPart[]}
19
19
  */
20
+ // eslint-disable-next-line default-param-last
20
21
  export function normalizeIntl(formattedParts, options = {}, _locale) {
21
22
  let normalize = forceNormalSpaces(formattedParts);
22
23
  // Dutch and Belgian currency must be moved to end of number
@@ -25,6 +25,7 @@ describe('getMonthNames', () => {
25
25
  // expect(getMonthNames({ locale: 'en-GB', style: 'short' })).to.deep.equal(
26
26
  // s`Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec`,
27
27
  // );
28
+ // Chromium default is leading
28
29
  expect(getMonthNames({ locale: 'nl-NL', style: 'short' })).to.deep.equal(
29
30
  s`jan. feb. mrt. apr. mei jun. jul. aug. sep. okt. nov. dec.`,
30
31
  );
@@ -56,5 +56,6 @@ export async function fakeImport(path, ms = 0) {
56
56
  setTimeout(() => resolveOrReject(result, resolve, reject), ms);
57
57
  });
58
58
  }
59
+ // eslint-disable-next-line no-promise-executor-return
59
60
  return new Promise((resolve, reject) => resolveOrReject(result, resolve, reject));
60
61
  }
@@ -119,7 +119,7 @@ export function adoptStyle(renderRoot, style, { teardown = false } = {}) {
119
119
  if (!teardown) {
120
120
  // @ts-ignore
121
121
  // eslint-disable-next-line no-param-reassign
122
- renderRoot.adoptedStyleSheets.push(sheet);
122
+ renderRoot.adoptedStyleSheets = [...renderRoot.adoptedStyleSheets, sheet];
123
123
  } else if (renderRoot.adoptedStyleSheets.includes(sheet)) {
124
124
  renderRoot.adoptedStyleSheets.splice(renderRoot.adoptedStyleSheets.indexOf(sheet), 1);
125
125
  }
@@ -23,7 +23,7 @@ export class LionRadioGroup extends ChoiceGroupMixin(FormGroupMixin(LitElement))
23
23
  child.reset();
24
24
  // If the value was initially checked save this
25
25
  if (child.checked) {
26
- initValue = child.value;
26
+ initValue = child.choiceValue;
27
27
  }
28
28
  }
29
29
  });