@lion/ui 0.4.2 → 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 (151) hide show
  1. package/components/calendar/src/LionCalendar.js +1 -1
  2. package/components/calendar/test-helpers/DayObject.js +2 -2
  3. package/components/combobox/src/LionCombobox.js +79 -28
  4. package/components/combobox/test/lion-combobox-integrations.test.js +5 -0
  5. package/components/combobox/test/lion-combobox.test.js +290 -23
  6. package/components/combobox/test-helpers/combobox-helpers.js +5 -2
  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-range/test/lion-input-range.test.js +12 -6
  32. package/components/listbox/src/LionOptions.js +5 -5
  33. package/components/listbox/src/ListboxMixin.js +1 -16
  34. package/components/listbox/test/lion-options.test.js +1 -1
  35. package/components/listbox/test-suites/ListboxMixin.suite.js +1 -1
  36. package/components/localize/src/date/getMonthNames.js +3 -0
  37. package/components/localize/src/date/utils/forceDotsForNlnl.js +11 -0
  38. package/components/localize/src/number/utils/normalize-format-number-to-parts/forceAddGroupSeparators.js +3 -1
  39. package/components/localize/src/number/utils/normalize-format-number-to-parts/forceSymbols.js +2 -0
  40. package/components/localize/src/number/utils/normalize-format-number-to-parts/normalizeIntl.js +1 -0
  41. package/components/localize/test/date/getMonthNames.test.js +1 -0
  42. package/components/localize/test-helpers/fake-imports.js +1 -0
  43. package/components/radio-group/src/LionRadioGroup.js +1 -1
  44. package/components/radio-group/test/lion-radio-group.test.js +29 -0
  45. package/components/select/test/lion-select.test.js +1 -1
  46. package/components/switch/src/LionSwitchButton.js +1 -5
  47. package/components/tabs/src/LionTabs.js +7 -7
  48. package/components/textarea/src/LionTextarea.js +1 -1
  49. package/custom-elements.json +102923 -61581
  50. package/dist-types/components/combobox/src/LionCombobox.d.ts +13 -8
  51. package/dist-types/components/combobox/src/LionCombobox.d.ts.map +1 -1
  52. package/dist-types/components/combobox/test-helpers/combobox-helpers.d.ts.map +1 -1
  53. package/dist-types/components/drawer/src/LionDrawer.d.ts.map +1 -1
  54. package/dist-types/components/form-core/src/FocusMixin.d.ts.map +1 -1
  55. package/dist-types/components/form-core/src/choice-group/ChoiceGroupMixin.d.ts.map +1 -1
  56. package/dist-types/components/form-core/src/choice-group/CustomChoiceGroupMixin.d.ts +4 -0
  57. package/dist-types/components/form-core/src/choice-group/CustomChoiceGroupMixin.d.ts.map +1 -0
  58. package/dist-types/components/form-core/src/utils/getAriaElementsInRightDomOrder.d.ts +5 -5
  59. package/dist-types/components/form-core/src/utils/getAriaElementsInRightDomOrder.d.ts.map +1 -1
  60. package/dist-types/components/form-core/test/choice-group/CustomChoiceGroupMixin.integrations.test.d.ts +2 -0
  61. package/dist-types/components/form-core/test/choice-group/CustomChoiceGroupMixin.integrations.test.d.ts.map +1 -0
  62. package/dist-types/components/form-core/test/choice-group/CustomChoiceGroupMixin.test.d.ts +6 -0
  63. package/dist-types/components/form-core/test/choice-group/CustomChoiceGroupMixin.test.d.ts.map +1 -0
  64. package/dist-types/components/form-core/test-helpers/ExampleValidators.d.ts +0 -1
  65. package/dist-types/components/form-core/test-helpers/ExampleValidators.d.ts.map +1 -1
  66. package/dist-types/components/form-core/test-suites/FormRegistrationMixins.suite.d.ts.map +1 -1
  67. package/dist-types/components/form-core/test-suites/ValidateMixin.suite.d.ts.map +1 -1
  68. package/dist-types/components/form-core/test-suites/ValidateMixinFeedbackPart.suite.d.ts.map +1 -1
  69. package/dist-types/components/form-core/test-suites/choice-group/ChoiceGroupMixin.suite.d.ts.map +1 -1
  70. package/dist-types/components/form-core/test-suites/choice-group/CustomChoiceGroupMixin.suite.d.ts +14 -0
  71. package/dist-types/components/form-core/test-suites/choice-group/CustomChoiceGroupMixin.suite.d.ts.map +1 -0
  72. package/dist-types/components/form-core/types/choice-group/ChoiceGroupMixinTypes.d.ts +1 -1
  73. package/dist-types/components/form-core/types/choice-group/ChoiceGroupMixinTypes.d.ts.map +1 -1
  74. package/dist-types/components/form-core/types/choice-group/CustomChoiceGroupMixinTypes.d.ts +18 -0
  75. package/dist-types/components/form-core/types/choice-group/CustomChoiceGroupMixinTypes.d.ts.map +1 -0
  76. package/dist-types/components/form-core/types/choice-group/index.d.ts +1 -0
  77. package/dist-types/components/form-core/types/choice-group/index.d.ts.map +1 -1
  78. package/dist-types/components/helpers/src/SbActionLogger.d.ts.map +1 -1
  79. package/dist-types/components/icon/src/LionIcon.d.ts +0 -9
  80. package/dist-types/components/icon/src/LionIcon.d.ts.map +1 -1
  81. package/dist-types/components/listbox/src/LionOptions.d.ts +0 -5
  82. package/dist-types/components/listbox/src/LionOptions.d.ts.map +1 -1
  83. package/dist-types/components/listbox/src/ListboxMixin.d.ts.map +1 -1
  84. package/dist-types/components/localize/src/date/getMonthNames.d.ts.map +1 -1
  85. package/dist-types/components/localize/src/date/utils/forceDotsForNlnl.d.ts +5 -0
  86. package/dist-types/components/localize/src/date/utils/forceDotsForNlnl.d.ts.map +1 -0
  87. package/dist-types/components/localize/src/number/utils/normalize-format-number-to-parts/forceAddGroupSeparators.d.ts.map +1 -1
  88. package/dist-types/components/localize/src/number/utils/normalize-format-number-to-parts/forceSymbols.d.ts.map +1 -1
  89. package/dist-types/components/localize/src/number/utils/normalize-format-number-to-parts/normalizeIntl.d.ts.map +1 -1
  90. package/dist-types/components/localize/test-helpers/fake-imports.d.ts.map +1 -1
  91. package/dist-types/components/switch/src/LionSwitchButton.d.ts +0 -5
  92. package/dist-types/components/switch/src/LionSwitchButton.d.ts.map +1 -1
  93. package/dist-types/components/tabs/src/LionTabs.d.ts.map +1 -1
  94. package/dist-types/exports/types/form-core.d.ts +1 -1
  95. package/dist-types/exports/types/form-core.d.ts.map +1 -1
  96. package/dist-types/tsconfig.tsbuildinfo +1 -1
  97. package/docs/components/checkbox-group/overview.md +2 -2
  98. package/docs/components/collapsible/assets/CustomCollapsible.js +4 -0
  99. package/docs/components/collapsible/overview.md +1 -1
  100. package/docs/components/combobox/overview.md +1 -1
  101. package/docs/components/combobox/src/demo-selection-display.js +8 -35
  102. package/docs/components/combobox/use-cases.md +24 -1
  103. package/docs/components/dialog/overview.md +1 -1
  104. package/docs/components/fieldset/overview.md +5 -5
  105. package/docs/components/form/overview.md +3 -3
  106. package/docs/components/icon/use-cases.md +1 -1
  107. package/docs/components/input/overview.md +1 -1
  108. package/docs/components/input-amount/overview.md +3 -3
  109. package/docs/components/input-date/overview.md +3 -3
  110. package/docs/components/input-datepicker/overview.md +5 -5
  111. package/docs/components/input-email/overview.md +2 -2
  112. package/docs/components/input-file/overview.md +1 -1
  113. package/docs/components/input-iban/overview.md +2 -2
  114. package/docs/components/input-range/overview.md +2 -2
  115. package/docs/components/input-stepper/overview.md +1 -1
  116. package/docs/components/input-tel/overview.md +1 -1
  117. package/docs/components/input-tel/use-cases.md +6 -6
  118. package/docs/components/input-tel-dropdown/overview.md +1 -1
  119. package/docs/components/radio-group/overview.md +3 -3
  120. package/docs/components/select-rich/use-cases.md +1 -1
  121. package/docs/components/tabs/examples.md +1 -1
  122. package/docs/fundamentals/index.md +4 -4
  123. package/docs/fundamentals/node-tools/providence-analytics/LocalConfiguration.md +1 -1
  124. package/docs/fundamentals/node-tools/providence-analytics/QueryResult.md +1 -1
  125. package/docs/fundamentals/node-tools/providence-analytics/analyzer.md +1 -1
  126. package/docs/fundamentals/node-tools/providence-analytics/dashboard.md +1 -1
  127. package/docs/fundamentals/node-tools/providence-analytics/overview.md +3 -3
  128. package/docs/fundamentals/node-tools/publish-docs/overview.md +3 -3
  129. package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +2 -2
  130. package/docs/fundamentals/rationales/accessibility.md +3 -3
  131. package/docs/fundamentals/systems/core/SlotMixin.md +1 -1
  132. package/docs/fundamentals/systems/core/overview.md +1 -1
  133. package/docs/fundamentals/systems/form/formatting-and-parsing.md +4 -4
  134. package/docs/fundamentals/systems/form/model-value.md +1 -1
  135. package/docs/fundamentals/systems/form/overview.md +28 -28
  136. package/docs/fundamentals/systems/form/validate.md +18 -2
  137. package/docs/fundamentals/systems/localize/overview.md +4 -4
  138. package/docs/fundamentals/systems/overlays/configuration.md +3 -2
  139. package/docs/fundamentals/systems/overlays/overview.md +5 -5
  140. package/docs/fundamentals/systems/overlays/use-cases.md +2 -2
  141. package/docs/fundamentals/tools/helpers/overview.md +1 -1
  142. package/docs/fundamentals/tools/singleton-manager/example-complex/overlayCompatibility.js +1 -2
  143. package/docs/fundamentals/tools/singleton-manager/overview.md +4 -4
  144. package/docs/guides/how-to/create-a-custom-field.md +5 -5
  145. package/docs/guides/how-to/create-a-form.md +4 -4
  146. package/docs/guides/how-to/extend-a-native-input.md +2 -2
  147. package/docs/guides/index.md +8 -8
  148. package/docs/guides/principles/index.md +5 -5
  149. package/docs/guides/principles/styling.md +1 -1
  150. package/exports/types/form-core.ts +5 -1
  151. package/package.json +1 -1
@@ -0,0 +1,173 @@
1
+ import { dedupeMixin } from '@open-wc/dedupe-mixin';
2
+ import { ChoiceGroupMixin } from './ChoiceGroupMixin.js';
3
+
4
+ /**
5
+ * @typedef {import('../../types/choice-group/CustomChoiceGroupMixinTypes.js').CustomChoiceGroupMixin} CustomChoiceGroupMixin
6
+ * @typedef {import('../../types/choice-group/CustomChoiceGroupMixinTypes.js').CustomChoiceGroupHost} CustomChoiceGroupHost
7
+ */
8
+
9
+ /**
10
+ * @param {any|any[]} value
11
+ * @returns {any[]}
12
+ */
13
+ function ensureArray(value) {
14
+ return Array.isArray(value) ? value : [value];
15
+ }
16
+
17
+ /**
18
+ * Extends the ChoiceGroupMixin to add optional support for custom user choices without altering the initial choice list.
19
+ *
20
+ * @type {CustomChoiceGroupMixin}
21
+ * @param {import('@open-wc/dedupe-mixin').Constructor<import('lit').LitElement>} superclass
22
+ */
23
+ const CustomChoiceGroupMixinImplementation = superclass =>
24
+ // @ts-ignore https://github.com/microsoft/TypeScript/issues/36821#issuecomment-588375051
25
+ class CustomChoiceGroupMixin extends ChoiceGroupMixin(superclass) {
26
+ static get properties() {
27
+ return {
28
+ allowCustomChoice: {
29
+ type: Boolean,
30
+ attribute: 'allow-custom-choice',
31
+ },
32
+ modelValue: { type: Object },
33
+ };
34
+ }
35
+
36
+ // @ts-ignore
37
+ get modelValue() {
38
+ return this.__getChoicesFrom(super.modelValue);
39
+ }
40
+
41
+ set modelValue(value) {
42
+ super.modelValue = value;
43
+
44
+ if (value === null || value === undefined || value === '') {
45
+ // @ts-ignore
46
+ this._customChoices = new Set();
47
+ } else if (this.allowCustomChoice) {
48
+ const old = this.modelValue;
49
+ // @ts-ignore
50
+ this._customChoices = new Set(ensureArray(value));
51
+ this.requestUpdate('modelValue', old);
52
+ }
53
+ }
54
+
55
+ // @ts-ignore
56
+ get formattedValue() {
57
+ return this.__getChoicesFrom(super.formattedValue);
58
+ }
59
+
60
+ set formattedValue(value) {
61
+ super.formattedValue = value;
62
+
63
+ if (value === null || value === undefined) {
64
+ this._customChoices = new Set();
65
+ } else if (this.allowCustomChoice) {
66
+ const old = this.modelValue;
67
+ // Convert formattedValue to modelValue to store as custom choices, or fall back to the input value
68
+ this._customChoices = new Set(
69
+ ensureArray(value).map(
70
+ val => this.formElements.find(el => el.formattedValue === val)?.modelValue || val,
71
+ ),
72
+ );
73
+ this.requestUpdate('modelValue', old);
74
+ }
75
+ }
76
+
77
+ // @ts-ignore
78
+ get serializedValue() {
79
+ return this.__getChoicesFrom(super.serializedValue);
80
+ }
81
+
82
+ set serializedValue(value) {
83
+ super.serializedValue = value;
84
+
85
+ if (value === null || value === undefined) {
86
+ this._customChoices = new Set();
87
+ } else if (this.allowCustomChoice) {
88
+ const old = this.modelValue;
89
+ // Convert serializedValue to modelValue to store as custom choices, or fall back to the input value
90
+ this._customChoices = new Set(
91
+ ensureArray(value).map(
92
+ val => this.formElements.find(el => el.serializedValue === val)?.modelValue || val,
93
+ ),
94
+ );
95
+ this.requestUpdate('modelValue', old);
96
+ }
97
+ }
98
+
99
+ /**
100
+ * Custom elements are all missing elements that have no corresponding element, independent if enabled or not.
101
+ */
102
+ // @ts-ignore
103
+ get customChoices() {
104
+ if (!this.allowCustomChoice) {
105
+ return [];
106
+ }
107
+
108
+ const elems = this._getCheckedElements();
109
+
110
+ return Array.from(this._customChoices).filter(
111
+ choice => !elems.some(elem => elem.choiceValue === choice),
112
+ );
113
+ }
114
+
115
+ constructor() {
116
+ super();
117
+
118
+ this.allowCustomChoice = false;
119
+
120
+ /**
121
+ * @type {Set<unknown>}
122
+ * @protected
123
+ */
124
+ this._customChoices = new Set();
125
+ }
126
+
127
+ /**
128
+ * @private
129
+ */
130
+ // @ts-ignore
131
+ __getChoicesFrom(input) {
132
+ const values = input;
133
+ if (!this.allowCustomChoice) {
134
+ return values;
135
+ }
136
+
137
+ if (this.multipleChoice) {
138
+ return [...ensureArray(values), ...this.customChoices];
139
+ }
140
+
141
+ if (values === '') {
142
+ return this._customChoices.values().next().value || '';
143
+ }
144
+
145
+ return values;
146
+ }
147
+
148
+ /**
149
+ * @protected
150
+ */
151
+ _isEmpty() {
152
+ return super._isEmpty() && this._customChoices.size === 0;
153
+ }
154
+
155
+ clear() {
156
+ this._customChoices = new Set();
157
+ super.clear();
158
+ }
159
+
160
+ /**
161
+ * @param {string|string[]} value
162
+ * @returns {*}
163
+ */
164
+ parser(value) {
165
+ if (this.allowCustomChoice && Array.isArray(value)) {
166
+ return value.filter(v => v.trim() !== '');
167
+ }
168
+
169
+ return value;
170
+ }
171
+ };
172
+
173
+ export const CustomChoiceGroupMixin = dedupeMixin(CustomChoiceGroupMixinImplementation);
@@ -1,6 +1,4 @@
1
1
  /* eslint-disable no-bitwise */
2
- import { browserDetection } from '@lion/ui/core.js';
3
-
4
2
  const moveDownConditions = [
5
3
  Node.DOCUMENT_POSITION_PRECEDING,
6
4
  Node.DOCUMENT_POSITION_CONTAINS,
@@ -8,30 +6,25 @@ const moveDownConditions = [
8
6
  ];
9
7
 
10
8
  /**
11
- * @desc Let the order of adding ids to aria element by DOM order, so that the screen reader
9
+ * Let the order of adding ids to aria element by DOM order, so that the screen reader
12
10
  * respects visual order when reading:
13
11
  * https://developers.google.com/web/fundamentals/accessibility/focus/dom-order-matters
14
- * @param {HTMLElement[]} descriptionElements - holds references to description or label elements whose
12
+ * @param {Element[]} descriptionElements - holds references to description or label elements whose
15
13
  * id should be returned
16
14
  * @param {Object} opts
17
15
  * @param {boolean} [opts.reverse]
18
- * @returns {HTMLElement[]} sorted set of elements based on dom order
16
+ * @returns {Element[]} sorted set of elements based on dom order
19
17
  */
20
18
  export function getAriaElementsInRightDomOrder(descriptionElements, { reverse } = {}) {
21
19
  /**
22
- * @param {HTMLElement} a
23
- * @param {HTMLElement} b
24
- * @return {-1|1}
20
+ * @param {Node} a
21
+ * @param {Node} b
22
+ * @returns {-1|1}
25
23
  */
26
24
  const putPrecedingSiblingsAndLocalParentsFirst = (a, b) => {
27
25
  // https://developer.mozilla.org/en-US/docs/Web/API/Node/compareDocumentPosition
28
26
  const pos = a.compareDocumentPosition(b);
29
-
30
- // Unfortunately, for IE, we have to switch the order (?)
31
- if (moveDownConditions.includes(pos)) {
32
- return browserDetection.isIE11 ? -1 : 1;
33
- }
34
- return browserDetection.isIE11 ? 1 : -1;
27
+ return moveDownConditions.includes(pos) ? 1 : -1;
35
28
  };
36
29
 
37
30
  const descriptionEls = descriptionElements.filter(el => el); // filter out null references
@@ -45,7 +45,7 @@ export class Required extends Validator {
45
45
  /**
46
46
  * @param {FormControlHost & HTMLElement} formControl
47
47
  */
48
- // @ts-ignore [allow-protected] we are allowed to know FormControl protcected props in form-core
48
+ // @ts-ignore [allow-protected] we are allowed to know FormControl protected props in form-core
49
49
  // eslint-disable-next-line class-methods-use-this
50
50
  onFormControlConnect({ _inputNode: inputNode }) {
51
51
  if (inputNode) {
@@ -61,7 +61,7 @@ export class Required extends Validator {
61
61
  /**
62
62
  * @param {FormControlHost & HTMLElement} formControl
63
63
  */
64
- // @ts-ignore [allow-protected] we are allowed to know FormControl protcected props in form-core
64
+ // @ts-ignore [allow-protected] we are allowed to know FormControl protected props in form-core
65
65
  // eslint-disable-next-line class-methods-use-this
66
66
  onFormControlDisconnect({ _inputNode: inputNode }) {
67
67
  if (inputNode) {
@@ -0,0 +1,55 @@
1
+ import { runChoiceGroupMixinSuite } from '@lion/ui/form-core-test-suites.js';
2
+ import { LitElement } from 'lit';
3
+ import '@lion/ui/define/lion-fieldset.js';
4
+ import '@lion/ui/define/lion-checkbox-group.js';
5
+ import '@lion/ui/define/lion-checkbox.js';
6
+ import { FormGroupMixin, ChoiceInputMixin } from '@lion/ui/form-core.js';
7
+ import { LionInput } from '@lion/ui/input.js';
8
+ import { CustomChoiceGroupMixin } from '../../src/choice-group/CustomChoiceGroupMixin.js';
9
+
10
+ class CustomChoiceGroup extends CustomChoiceGroupMixin(FormGroupMixin(LitElement)) {}
11
+ customElements.define('custom-choice-input-group', CustomChoiceGroup);
12
+
13
+ class ChoiceInput extends ChoiceInputMixin(LionInput) {}
14
+ customElements.define('custom-choice-input', ChoiceInput);
15
+
16
+ class CustomChoiceGroupAllowCustom extends CustomChoiceGroupMixin(FormGroupMixin(LitElement)) {
17
+ constructor() {
18
+ super();
19
+ this.allowCustomChoice = true;
20
+ }
21
+ }
22
+ customElements.define('allow-custom-choice-input-group', CustomChoiceGroupAllowCustom);
23
+
24
+ class MultipleCustomChoiceGroup extends CustomChoiceGroupMixin(FormGroupMixin(LitElement)) {
25
+ constructor() {
26
+ super();
27
+ this.multipleChoice = true;
28
+ }
29
+ }
30
+ customElements.define('multiple-custom-choice-input-group', MultipleCustomChoiceGroup);
31
+
32
+ class MultipleCustomChoiceGroupAllowCustom extends CustomChoiceGroupMixin(
33
+ FormGroupMixin(LitElement),
34
+ ) {
35
+ constructor() {
36
+ super();
37
+ this.multipleChoice = true;
38
+ this.allowCustomChoice = true;
39
+ }
40
+ }
41
+ customElements.define(
42
+ 'multiple-allow-custom-choice-input-group',
43
+ MultipleCustomChoiceGroupAllowCustom,
44
+ );
45
+
46
+ runChoiceGroupMixinSuite({ parentTagString: 'custom-choice-input-group' });
47
+ runChoiceGroupMixinSuite({
48
+ parentTagString: 'multiple-custom-choice-input-group',
49
+ choiceType: 'multiple',
50
+ });
51
+ runChoiceGroupMixinSuite({ parentTagString: 'allow-custom-choice-input-group' });
52
+ runChoiceGroupMixinSuite({
53
+ parentTagString: 'multiple-allow-custom-choice-input-group',
54
+ choiceType: 'multiple',
55
+ });
@@ -0,0 +1,16 @@
1
+ import { ChoiceInputMixin, FormGroupMixin } from '@lion/ui/form-core.js';
2
+ import { LionInput } from '@lion/ui/input.js';
3
+ import { LitElement } from 'lit';
4
+ import '@lion/ui/define/lion-fieldset.js';
5
+ import '@lion/ui/define/lion-checkbox-group.js';
6
+ import '@lion/ui/define/lion-checkbox.js';
7
+ import { CustomChoiceGroupMixin } from '../../src/choice-group/CustomChoiceGroupMixin.js';
8
+ import { runCustomChoiceGroupMixinSuite } from '../../test-suites/choice-group/CustomChoiceGroupMixin.suite.js';
9
+
10
+ export class CustomChoiceGroup extends CustomChoiceGroupMixin(FormGroupMixin(LitElement)) {}
11
+ customElements.define('custom-choice-input-group', CustomChoiceGroup);
12
+
13
+ class ChoiceInput extends ChoiceInputMixin(LionInput) {}
14
+ customElements.define('custom-choice-input', ChoiceInput);
15
+
16
+ runCustomChoiceGroupMixinSuite();
@@ -1,7 +1,5 @@
1
1
  import { expect, fixture } from '@open-wc/testing';
2
2
  import { html } from 'lit/static-html.js';
3
- import sinon from 'sinon';
4
- import { browserDetection } from '@lion/ui/core.js';
5
3
  import { getAriaElementsInRightDomOrder } from '../../src/utils/getAriaElementsInRightDomOrder.js';
6
4
 
7
5
  describe('getAriaElementsInRightDomOrder', () => {
@@ -47,27 +45,4 @@ describe('getAriaElementsInRightDomOrder', () => {
47
45
  const result = getAriaElementsInRightDomOrder(unorderedNodes, { reverse: true });
48
46
  expect(result).to.eql([c, bChild, b, a]);
49
47
  });
50
-
51
- it('orders in reverse for IE11', async () => {
52
- const browserDetectionStub = sinon.stub(browserDetection, 'isIE11').value(true);
53
- const el = await fixture(html`
54
- <div>
55
- <div id="a"></div>
56
- <div></div>
57
- <div id="b">
58
- <div></div>
59
- <div id="b-child"></div>
60
- </div>
61
- <div></div>
62
- <div id="c"></div>
63
- <div></div>
64
- </div>
65
- `);
66
- // eslint-disable-next-line no-unused-vars
67
- const [a, _1, b, _2, bChild, _3, c, _4] = Array.from(el.querySelectorAll('div'));
68
- const unorderedNodes = [bChild, c, a, b];
69
- const result = getAriaElementsInRightDomOrder(unorderedNodes);
70
- expect(result).to.eql([c, bChild, b, a]);
71
- browserDetectionStub.restore();
72
- });
73
48
  });
@@ -124,7 +124,7 @@ describe('String Validation', () => {
124
124
  isEnabled = validator.execute('#LionRests');
125
125
  expect(isEnabled).to.be.true;
126
126
 
127
- validator = new Pattern(new RegExp('#LionRocks'));
127
+ validator = new Pattern(/#LionRocks/);
128
128
  isEnabled = validator.execute('Some string #LionRocks');
129
129
  expect(isEnabled).to.be.false;
130
130
 
@@ -2,9 +2,7 @@
2
2
  import { Validator } from '@lion/ui/form-core.js';
3
3
 
4
4
  export class AlwaysInvalid extends Validator {
5
- static get validatorName() {
6
- return 'AlwaysInvalid';
7
- }
5
+ static validatorName = 'AlwaysInvalid';
8
6
 
9
7
  execute() {
10
8
  const showMessage = true;
@@ -165,6 +165,7 @@ export const runRegistrationSuite = customConfig => {
165
165
  it('works for components that have a delayed render', async () => {
166
166
  class PerformUpdate extends FormRegistrarMixin(LitElement) {
167
167
  async performUpdate() {
168
+ // eslint-disable-next-line no-promise-executor-return
168
169
  await new Promise(resolve => setTimeout(() => resolve(undefined), 10));
169
170
  await super.performUpdate();
170
171
  }
@@ -359,6 +360,7 @@ export const runRegistrationSuite = customConfig => {
359
360
  const delayedPortalString = defineCE(
360
361
  class extends FormRegistrarPortalMixin(LitElement) {
361
362
  async performUpdate() {
363
+ // eslint-disable-next-line no-promise-executor-return
362
364
  await new Promise(resolve => setTimeout(() => resolve(undefined), 10));
363
365
  await super.performUpdate();
364
366
  }
@@ -5,9 +5,9 @@ import { sendKeys } from '@web/test-runner-commands';
5
5
  import { spy } from 'sinon';
6
6
  import { NativeTextFieldMixin } from '@lion/ui/form-core.js';
7
7
 
8
- const isFirefox = (() => {
8
+ const isSafari = (() => {
9
9
  const ua = navigator.userAgent.toLowerCase();
10
- return ua.indexOf('firefox') !== -1 && ua.indexOf('safari') === -1 && ua.indexOf('chrome') === -1;
10
+ return ua.indexOf('safari') !== -1 && ua.indexOf('chrome') === -1;
11
11
  })();
12
12
 
13
13
  /**
@@ -54,8 +54,8 @@ export function runNativeTextFieldMixinSuite(customConfig) {
54
54
  });
55
55
 
56
56
  it('move focus to a next focusable element after writing some text', async () => {
57
- if (isFirefox) {
58
- // TODO: This test is broken on Firefox, to be fixed later
57
+ if (isSafari) {
58
+ // TODO: This test is broken on Safari, to be fixed later
59
59
  return;
60
60
  }
61
61
  const el = /** @type {NativeTextFieldClass} */ (await fixture(html`<${tag}></${tag}>`));
@@ -9,6 +9,7 @@ import {
9
9
  } from '@lion/ui/form-core-test-helpers.js';
10
10
  import sinon from 'sinon';
11
11
  import {
12
+ EqualsLength,
12
13
  MaxLength,
13
14
  MinLength,
14
15
  Required,
@@ -779,6 +780,32 @@ export function runValidateMixinSuite(customConfig) {
779
780
  });
780
781
  });
781
782
 
783
+ describe('getMessages with custom HTML', () => {
784
+ it('will render HTML for lion-validation-feedback', async () => {
785
+ const messageHtmlId = 'test123';
786
+ const messageHtml = `<div id="test123">test</div>`;
787
+ const el = /** @type {ValidateElement} */ (
788
+ await fixture(html`
789
+ <${tag}
790
+ .validators="${[
791
+ new EqualsLength(4, { getMessage: () => html`<div id="test123">test</div>` }),
792
+ ]}" })]}"
793
+ .modelValue="${'123'}"
794
+ label="Custom message for validator instance"
795
+ ></${tag}>
796
+ `)
797
+ );
798
+ expect(el.validationStates.error.EqualsLength).to.be.true;
799
+ expect(el.hasFeedbackFor).to.deep.equal(['error']);
800
+ const { _feedbackNode } = getFormControlMembers(el);
801
+ await el.updateComplete;
802
+ await el.updateComplete;
803
+ const messageHtmlNode = _feedbackNode.shadowRoot?.querySelector(`#${messageHtmlId}`);
804
+ expect(messageHtmlNode?.outerHTML).to.equal(messageHtml);
805
+ expect(messageHtmlNode?.tagName).to.equal('DIV');
806
+ });
807
+ });
808
+
782
809
  describe('Required Validator integration', () => {
783
810
  it('will result in erroneous state when form control is empty', async () => {
784
811
  const el = /** @type {ValidateElement} */ (
@@ -517,7 +517,11 @@ export function runValidateMixinFeedbackPart() {
517
517
  .submitted=${true}
518
518
  .validators=${[constructorValidator]}
519
519
  .modelValue=${'cat'}
520
- .fieldName=${new Promise(resolve => resolve('myField'))}
520
+ .fieldName=${new Promise(
521
+ (
522
+ resolve, // eslint-disable-next-line no-promise-executor-return
523
+ ) => resolve('myField'),
524
+ )}
521
525
  >${lightDom}</${tag}>
522
526
  `)
523
527
  );
@@ -537,6 +541,7 @@ export function runValidateMixinFeedbackPart() {
537
541
 
538
542
  it('".getMessage()" gets .fieldName defined on Validator config', async () => {
539
543
  const constructorValidator = new MinLength(4, {
544
+ // eslint-disable-next-line no-promise-executor-return
540
545
  fieldName: new Promise(resolve => resolve('myFieldViaCfg')),
541
546
  });
542
547
  const ctorValidator = /** @type {typeof MinLength} */ (constructorValidator.constructor);
@@ -548,7 +553,11 @@ export function runValidateMixinFeedbackPart() {
548
553
  .submitted=${true}
549
554
  .validators=${[constructorValidator]}
550
555
  .modelValue=${'cat'}
551
- .fieldName=${new Promise(resolve => resolve('myField'))}
556
+ .fieldName=${new Promise(
557
+ (
558
+ resolve, // eslint-disable-next-line no-promise-executor-return
559
+ ) => resolve('myField'),
560
+ )}
552
561
  >${lightDom}</${tag}>
553
562
  `)
554
563
  );
@@ -55,6 +55,7 @@ export function runChoiceGroupMixinSuite({ parentTagString, childTagString, choi
55
55
  </${parentTag}>
56
56
  `)
57
57
  );
58
+
58
59
  expect(el.modelValue).to.equal('female');
59
60
  el.formElements[0].checked = true;
60
61
  expect(el.modelValue).to.equal('male');