@lion/ui 0.13.0 → 0.13.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 (160) hide show
  1. package/components/accordion/src/LionAccordion.js +3 -2
  2. package/components/button/src/LionButton.js +6 -10
  3. package/components/button/src/LionButtonReset.js +2 -0
  4. package/components/button/src/LionButtonSubmit.js +2 -0
  5. package/components/button/test-suites/LionButton.suite.js +0 -14
  6. package/components/checkbox-group/src/LionCheckbox.js +3 -0
  7. package/components/checkbox-group/src/LionCheckboxGroup.js +2 -0
  8. package/components/checkbox-group/src/LionCheckboxIndeterminate.js +3 -0
  9. package/components/collapsible/src/LionCollapsible.js +4 -1
  10. package/components/combobox/src/LionCombobox.js +5 -0
  11. package/components/dialog/src/LionDialog.js +3 -0
  12. package/components/drawer/src/LionDrawer.js +9 -0
  13. package/components/fieldset/src/LionFieldset.js +1 -1
  14. package/components/form/src/LionForm.js +0 -1
  15. package/components/form-core/src/FormControlMixin.js +10 -0
  16. package/components/form-core/src/FormatMixin.js +1 -1
  17. package/components/form-core/src/validate/LionValidationFeedback.js +8 -10
  18. package/components/form-core/src/validate/ValidateMixin.js +23 -3
  19. package/components/form-core/test/validate/lion-validation-feedback.test.js +0 -22
  20. package/components/form-core/test-suites/ValidateMixinFeedbackPart.suite.js +119 -0
  21. package/components/form-core/types/validate/validate.ts +1 -0
  22. package/components/icon/src/LionIcon.js +2 -0
  23. package/components/input-file/src/LionInputFile.js +9 -0
  24. package/components/input-tel/src/LionInputTel.js +3 -0
  25. package/components/input-tel-dropdown/src/LionInputTelDropdown.js +2 -0
  26. package/components/listbox/src/LionListbox.js +2 -0
  27. package/components/overlays/src/OverlayMixin.js +4 -0
  28. package/components/progress-indicator/src/LionProgressIndicator.js +4 -0
  29. package/components/radio-group/src/LionRadioGroup.js +3 -1
  30. package/components/select/src/LionSelect.js +4 -0
  31. package/components/select-rich/src/LionSelectInvoker.js +2 -0
  32. package/components/select-rich/src/LionSelectRich.js +2 -0
  33. package/components/steps/src/LionStep.js +0 -1
  34. package/components/steps/src/LionSteps.js +0 -1
  35. package/components/switch/src/LionSwitch.js +3 -0
  36. package/components/switch/src/LionSwitchButton.js +5 -0
  37. package/components/tabs/src/LionTabs.js +8 -0
  38. package/custom-elements.json +127 -79
  39. package/dist-types/components/accordion/src/LionAccordion.d.ts +3 -2
  40. package/dist-types/components/accordion/src/LionAccordion.d.ts.map +1 -1
  41. package/dist-types/components/button/src/LionButton.d.ts +2 -1
  42. package/dist-types/components/button/src/LionButton.d.ts.map +1 -1
  43. package/dist-types/components/button/src/LionButtonReset.d.ts +2 -0
  44. package/dist-types/components/button/src/LionButtonReset.d.ts.map +1 -1
  45. package/dist-types/components/button/src/LionButtonSubmit.d.ts +2 -0
  46. package/dist-types/components/button/src/LionButtonSubmit.d.ts.map +1 -1
  47. package/dist-types/components/button/test-suites/LionButton.suite.d.ts.map +1 -1
  48. package/dist-types/components/checkbox-group/src/LionCheckbox.d.ts +3 -0
  49. package/dist-types/components/checkbox-group/src/LionCheckbox.d.ts.map +1 -1
  50. package/dist-types/components/checkbox-group/src/LionCheckboxGroup.d.ts +2 -0
  51. package/dist-types/components/checkbox-group/src/LionCheckboxGroup.d.ts.map +1 -1
  52. package/dist-types/components/checkbox-group/src/LionCheckboxIndeterminate.d.ts +3 -0
  53. package/dist-types/components/checkbox-group/src/LionCheckboxIndeterminate.d.ts.map +1 -1
  54. package/dist-types/components/collapsible/src/LionCollapsible.d.ts +3 -1
  55. package/dist-types/components/collapsible/src/LionCollapsible.d.ts.map +1 -1
  56. package/dist-types/components/combobox/src/LionCombobox.d.ts +5 -0
  57. package/dist-types/components/combobox/src/LionCombobox.d.ts.map +1 -1
  58. package/dist-types/components/dialog/src/LionDialog.d.ts +3 -0
  59. package/dist-types/components/dialog/src/LionDialog.d.ts.map +1 -1
  60. package/dist-types/components/drawer/src/LionDrawer.d.ts +9 -0
  61. package/dist-types/components/drawer/src/LionDrawer.d.ts.map +1 -1
  62. package/dist-types/components/fieldset/src/LionFieldset.d.ts +1 -1
  63. package/dist-types/components/form/src/LionForm.d.ts.map +1 -1
  64. package/dist-types/components/form-core/src/FormControlMixin.d.ts.map +1 -1
  65. package/dist-types/components/form-core/src/validate/LionValidationFeedback.d.ts +4 -3
  66. package/dist-types/components/form-core/src/validate/LionValidationFeedback.d.ts.map +1 -1
  67. package/dist-types/components/form-core/src/validate/ValidateMixin.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/types/validate/validate.d.ts +1 -0
  70. package/dist-types/components/form-core/types/validate/validate.d.ts.map +1 -1
  71. package/dist-types/components/icon/src/LionIcon.d.ts +2 -0
  72. package/dist-types/components/icon/src/LionIcon.d.ts.map +1 -1
  73. package/dist-types/components/input-file/src/LionInputFile.d.ts +9 -0
  74. package/dist-types/components/input-file/src/LionInputFile.d.ts.map +1 -1
  75. package/dist-types/components/input-tel/src/LionInputTel.d.ts +3 -0
  76. package/dist-types/components/input-tel/src/LionInputTel.d.ts.map +1 -1
  77. package/dist-types/components/input-tel-dropdown/src/LionInputTelDropdown.d.ts +2 -0
  78. package/dist-types/components/input-tel-dropdown/src/LionInputTelDropdown.d.ts.map +1 -1
  79. package/dist-types/components/listbox/src/LionListbox.d.ts +2 -0
  80. package/dist-types/components/listbox/src/LionListbox.d.ts.map +1 -1
  81. package/dist-types/components/overlays/src/OverlayMixin.d.ts +4 -0
  82. package/dist-types/components/overlays/src/OverlayMixin.d.ts.map +1 -1
  83. package/dist-types/components/progress-indicator/src/LionProgressIndicator.d.ts +3 -0
  84. package/dist-types/components/progress-indicator/src/LionProgressIndicator.d.ts.map +1 -1
  85. package/dist-types/components/radio-group/src/LionRadioGroup.d.ts +3 -1
  86. package/dist-types/components/radio-group/src/LionRadioGroup.d.ts.map +1 -1
  87. package/dist-types/components/select/src/LionSelect.d.ts +3 -0
  88. package/dist-types/components/select/src/LionSelect.d.ts.map +1 -1
  89. package/dist-types/components/select-rich/src/LionSelectInvoker.d.ts +2 -0
  90. package/dist-types/components/select-rich/src/LionSelectInvoker.d.ts.map +1 -1
  91. package/dist-types/components/select-rich/src/LionSelectRich.d.ts +3 -1
  92. package/dist-types/components/select-rich/src/LionSelectRich.d.ts.map +1 -1
  93. package/dist-types/components/steps/src/LionStep.d.ts +0 -1
  94. package/dist-types/components/steps/src/LionStep.d.ts.map +1 -1
  95. package/dist-types/components/steps/src/LionSteps.d.ts +0 -1
  96. package/dist-types/components/steps/src/LionSteps.d.ts.map +1 -1
  97. package/dist-types/components/switch/src/LionSwitch.d.ts +3 -0
  98. package/dist-types/components/switch/src/LionSwitch.d.ts.map +1 -1
  99. package/dist-types/components/switch/src/LionSwitchButton.d.ts +5 -0
  100. package/dist-types/components/switch/src/LionSwitchButton.d.ts.map +1 -1
  101. package/dist-types/components/tabs/src/LionTabs.d.ts +8 -0
  102. package/dist-types/components/tabs/src/LionTabs.d.ts.map +1 -1
  103. package/dist-types/tsconfig.tsbuildinfo +1 -1
  104. package/docs/components/accordion/api-table.md +8 -0
  105. package/docs/components/button/api-table.md +0 -3
  106. package/docs/components/checkbox-group/overview.md +2 -2
  107. package/docs/components/collapsible/api-table.md +7 -0
  108. package/docs/components/collapsible/overview.md +1 -1
  109. package/docs/components/combobox/api-table.md +7 -0
  110. package/docs/components/combobox/overview.md +1 -1
  111. package/docs/components/combobox/use-cases.md +1 -1
  112. package/docs/components/dialog/overview.md +1 -1
  113. package/docs/components/drawer/api-table.md +8 -0
  114. package/docs/components/fieldset/overview.md +5 -5
  115. package/docs/components/form/overview.md +3 -3
  116. package/docs/components/form/use-cases.md +2 -2
  117. package/docs/components/icon/use-cases.md +1 -1
  118. package/docs/components/input/overview.md +1 -1
  119. package/docs/components/input-amount/overview.md +3 -3
  120. package/docs/components/input-date/overview.md +3 -3
  121. package/docs/components/input-datepicker/overview.md +5 -5
  122. package/docs/components/input-email/overview.md +2 -2
  123. package/docs/components/input-file/api-table.md +7 -0
  124. package/docs/components/input-file/overview.md +1 -1
  125. package/docs/components/input-iban/overview.md +2 -2
  126. package/docs/components/input-range/overview.md +2 -2
  127. package/docs/components/input-stepper/overview.md +1 -1
  128. package/docs/components/input-tel/overview.md +1 -1
  129. package/docs/components/input-tel/use-cases.md +6 -6
  130. package/docs/components/input-tel-dropdown/overview.md +1 -1
  131. package/docs/components/listbox/use-cases.md +1 -1
  132. package/docs/components/radio-group/overview.md +3 -3
  133. package/docs/components/select/use-cases.md +1 -1
  134. package/docs/components/select-rich/api-table.md +0 -1
  135. package/docs/components/select-rich/use-cases.md +1 -1
  136. package/docs/components/tabs/api-table.md +7 -0
  137. package/docs/components/tabs/examples.md +1 -1
  138. package/docs/fundamentals/index.md +4 -4
  139. package/docs/fundamentals/node-tools/publish-docs/overview.md +3 -3
  140. package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +2 -2
  141. package/docs/fundamentals/rationales/accessibility.md +1 -1
  142. package/docs/fundamentals/systems/core/SlotMixin.md +1 -1
  143. package/docs/fundamentals/systems/core/overview.md +1 -1
  144. package/docs/fundamentals/systems/form/formatting-and-parsing.md +4 -4
  145. package/docs/fundamentals/systems/form/model-value.md +1 -1
  146. package/docs/fundamentals/systems/form/overview.md +28 -28
  147. package/docs/fundamentals/systems/form/validate.md +19 -3
  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/helpers/overview.md +1 -1
  153. package/docs/fundamentals/tools/singleton-manager/overview.md +4 -4
  154. package/docs/guides/how-to/create-a-custom-field.md +5 -5
  155. package/docs/guides/how-to/create-a-form.md +4 -4
  156. package/docs/guides/how-to/extend-a-native-input.md +2 -2
  157. package/docs/guides/index.md +8 -8
  158. package/docs/guides/principles/index.md +5 -5
  159. package/docs/guides/principles/styling.md +1 -1
  160. package/package.json +1 -1
@@ -14,10 +14,11 @@ import { uuid } from '@lion/ui/core.js';
14
14
  */
15
15
 
16
16
  /**
17
- * # <lion-accordion> webcomponent
17
+ * @slot invoker - The invoker element for the accordion
18
+ * @slot content - The content element for the accordion
19
+ * @slot _accordion - The slot for the accordion, used to rearrange invokers and content
18
20
  *
19
21
  * @customElement lion-accordion
20
- * @extends LitElement
21
22
  */
22
23
  export class LionAccordion extends LitElement {
23
24
  static get properties() {
@@ -1,9 +1,11 @@
1
1
  import { html, LitElement, css } from 'lit';
2
- import { browserDetection, DisabledWithTabIndexMixin, uuid } from '@lion/ui/core.js';
2
+ import { DisabledWithTabIndexMixin } from '@lion/ui/core.js';
3
3
 
4
4
  const isKeyboardClickEvent = (/** @type {KeyboardEvent} */ e) => e.key === ' ' || e.key === 'Enter';
5
5
  const isSpaceKeyboardClickEvent = (/** @type {KeyboardEvent} */ e) => e.key === ' ';
6
6
 
7
+ // TODO: simplify html structure, as we got rid of the wrapper element for IE11
8
+
7
9
  /**
8
10
  * @typedef {import('lit').TemplateResult} TemplateResult
9
11
  */
@@ -25,6 +27,8 @@ const isSpaceKeyboardClickEvent = (/** @type {KeyboardEvent} */ e) => e.key ===
25
27
  * `<form>` support is needed:
26
28
  * - When type="reset|submit" should be supported, use LionButtonReset.
27
29
  * - When implicit form submission should be supported on top, use LionButtonSubmit.
30
+ *
31
+ * @customElement lion-button
28
32
  */
29
33
  export class LionButton extends DisabledWithTabIndexMixin(LitElement) {
30
34
  static get properties() {
@@ -35,7 +39,7 @@ export class LionButton extends DisabledWithTabIndexMixin(LitElement) {
35
39
  }
36
40
 
37
41
  render() {
38
- return html` <div class="button-content" id="${this._buttonId}"><slot></slot></div> `;
42
+ return html` <div class="button-content"><slot></slot></div> `;
39
43
  }
40
44
 
41
45
  static get styles() {
@@ -124,14 +128,6 @@ export class LionButton extends DisabledWithTabIndexMixin(LitElement) {
124
128
  this.type = 'button';
125
129
  this.active = false;
126
130
 
127
- this._buttonId = uuid('button');
128
- if (browserDetection.isIE11) {
129
- this.updateComplete.then(() => {
130
- if (!this.hasAttribute('aria-labelledby')) {
131
- this.setAttribute('aria-labelledby', this._buttonId);
132
- }
133
- });
134
- }
135
131
  this.__setupEvents();
136
132
  }
137
133
 
@@ -17,6 +17,8 @@ import { LionButton } from './LionButton.js';
17
17
  * implicit form submission logic), but LionButtonReset is an easier to grasp name for
18
18
  * Application Developers: for reset buttons, always use LionButtonReset, for submit
19
19
  * buttons always use LionButtonSubmit.
20
+ *
21
+ * @customElement lion-button-reset
20
22
  */
21
23
  export class LionButtonReset extends LionButton {
22
24
  constructor() {
@@ -39,6 +39,8 @@ function createImplicitSubmitHelperButton() {
39
39
  * - the Application Developer should be able to switch types between 'submit'|'reset'|'button'
40
40
  * (this is similar to how native HTMLButtonElement works)
41
41
  * - a submit button with native form support is needed
42
+ *
43
+ * @customElement lion-button-submit
42
44
  */
43
45
  export class LionButtonSubmit extends LionButtonReset {
44
46
  /**
@@ -203,20 +203,6 @@ export function LionButtonSuite({ klass = LionButton } = {}) {
203
203
  expect(el.getAttribute('tabindex')).to.equal('5');
204
204
  });
205
205
 
206
- it('has an aria-labelledby and wrapper element in IE11', async () => {
207
- const browserDetectionStub = sinon.stub(browserDetection, 'isIE11').value(true);
208
- const el = /** @type {LionButton} */ (
209
- await fixture(html`<${tagButton}>foo</${tagButton}>`)
210
- );
211
- expect(el.hasAttribute('aria-labelledby')).to.be.true;
212
- const wrapperId = el.getAttribute('aria-labelledby');
213
- expect(/** @type {ShadowRoot} */ (el.shadowRoot).querySelector(`#${wrapperId}`)).to.exist;
214
- expect(
215
- /** @type {ShadowRoot} */ (el.shadowRoot).querySelector(`#${wrapperId}`),
216
- ).dom.to.equal(`<div class="button-content" id="${wrapperId}"><slot></slot></div>`);
217
- browserDetectionStub.restore();
218
- });
219
-
220
206
  it('does not override aria-labelledby when provided by user', async () => {
221
207
  const browserDetectionStub = sinon.stub(browserDetection, 'isIE11').value(true);
222
208
  const el = /** @type {LionButton} */ (
@@ -1,6 +1,9 @@
1
1
  import { LionInput } from '@lion/ui/input.js';
2
2
  import { ChoiceInputMixin } from '@lion/ui/form-core.js';
3
3
 
4
+ /**
5
+ * @customElement lion-checkbox
6
+ */
4
7
  export class LionCheckbox extends ChoiceInputMixin(LionInput) {
5
8
  connectedCallback() {
6
9
  super.connectedCallback();
@@ -3,6 +3,8 @@ import { ChoiceGroupMixin, FormGroupMixin } from '@lion/ui/form-core.js';
3
3
 
4
4
  /**
5
5
  * A wrapper around multiple checkboxes
6
+ *
7
+ * @customElement lion-checkbox-group
6
8
  */
7
9
  export class LionCheckboxGroup extends ChoiceGroupMixin(FormGroupMixin(LitElement)) {
8
10
  constructor() {
@@ -5,6 +5,9 @@ import { LionCheckbox } from './LionCheckbox.js';
5
5
  * @typedef {import('./LionCheckboxGroup.js').LionCheckboxGroup} LionCheckboxGroup
6
6
  */
7
7
 
8
+ /**
9
+ * @customElement lion-checkbox-indeterminate
10
+ */
8
11
  export class LionCheckboxIndeterminate extends LionCheckbox {
9
12
  static get styles() {
10
13
  return [
@@ -1,10 +1,13 @@
1
1
  import { LitElement, html, css } from 'lit';
2
2
  import { uuid } from '@lion/ui/core.js';
3
+
3
4
  /**
4
5
  * `LionCollapsible` is a class for custom collapsible element (`<lion-collapsible>` web component).
5
6
  *
7
+ * @slot invoker - The invoker element for the collapsible
8
+ * @slot content - The content element for the collapsible
9
+ *
6
10
  * @customElement lion-collapsible
7
- * @extends LitElement
8
11
  */
9
12
  export class LionCollapsible extends LitElement {
10
13
  static get styles() {
@@ -28,6 +28,11 @@ const matchA11ySpanReverseFns = new WeakMap();
28
28
  /**
29
29
  * LionCombobox: implements the wai-aria combobox design pattern and integrates it as a Lion
30
30
  * FormControl
31
+ *
32
+ * @slot listbox - The listbox element for the combobox, e.g. <lion-options>
33
+ * @slot selection-display - The selection display element for the combobox, e.g. <lion-selection-display>
34
+ *
35
+ * @customElement lion-combobox
31
36
  */
32
37
  export class LionCombobox extends LocalizeMixin(OverlayMixin(CustomChoiceGroupMixin(LionListbox))) {
33
38
  /** @type {any} */
@@ -1,6 +1,9 @@
1
1
  import { html, LitElement } from 'lit';
2
2
  import { OverlayMixin, withModalDialogConfig } from '@lion/ui/overlays.js';
3
3
 
4
+ /**
5
+ * @customElement lion-dialog
6
+ */
4
7
  export class LionDialog extends OverlayMixin(LitElement) {
5
8
  /** @type {any} */
6
9
  static get properties() {
@@ -7,6 +7,15 @@ const EVENT = {
7
7
  TRANSITION_START: 'transitionstart',
8
8
  };
9
9
 
10
+ /**
11
+ * LionDrawer: extension of lion-collapsible with drawer specific styles and animations
12
+ *
13
+ * @slot invoker - The invoker element for the drawer
14
+ * @slot content - The content element for the drawer
15
+ * @slot headline - The headline element for the drawer
16
+ *
17
+ * @customElement lion-drawer
18
+ */
10
19
  export class LionDrawer extends LionCollapsible {
11
20
  static get properties() {
12
21
  return {
@@ -2,7 +2,7 @@ import { LitElement } from 'lit';
2
2
  import { FormGroupMixin } from '@lion/ui/form-core.js';
3
3
 
4
4
  /**
5
- * @desc LionFieldset is basically a 'sub form' and can have its own nested sub forms.
5
+ * LionFieldset is basically a 'sub form' and can have its own nested sub forms.
6
6
  * It mimics the native <fieldset> element in this sense, but has all the functionality of
7
7
  * a FormControl (advanced styling, validation, interaction states etc.) Also see
8
8
  * FormGroupMixin it depends on.
@@ -15,7 +15,6 @@ const throwFormNodeError = () => {
15
15
  *
16
16
  * @customElement lion-form
17
17
  */
18
- // eslint-disable-next-line no-unused-vars
19
18
  export class LionForm extends LionFieldset {
20
19
  constructor() {
21
20
  super();
@@ -24,6 +24,16 @@ import { FormRegisteringMixin } from './registration/FormRegisteringMixin.js';
24
24
  * This Mixin is a shared fundament for all form components, it's applied on:
25
25
  * - LionField (which is extended to LionInput, LionTextarea, LionSelect etc. etc.)
26
26
  * - LionFieldset (which is extended to LionRadioGroup, LionCheckboxGroup, LionForm)
27
+ *
28
+ * @slot label - The label for the form control
29
+ * @slot help-text - The help text for the form control
30
+ * @slot input - The input element for the form control, e.g. <input>, <textarea>, <select>
31
+ * @slot feedback - The validation feedback for the form control
32
+ * @slot prefix - The prefix for the form control, e.g. currency symbol
33
+ * @slot suffix - The suffix for the form control, e.g. currency symbol
34
+ * @slot before - The before element for the form control, e.g. a label
35
+ * @slot after - The after element for the form control, e.g. a label
36
+ *
27
37
  * @param {import('@open-wc/dedupe-mixin').Constructor<import('lit').LitElement>} superclass
28
38
  * @type {FormControlMixin}
29
39
  */
@@ -25,7 +25,7 @@ import { Unparseable } from './validate/Unparseable.js';
25
25
  // formattedValue condition needs to be evaluated right before syncing back to the view
26
26
 
27
27
  /**
28
- * @desc Designed to be applied on top of a LionField.
28
+ * Designed to be applied on top of a LionField.
29
29
  * To understand all concepts within the Mixin, please consult the flow diagram in the
30
30
  * documentation.
31
31
  *
@@ -48,6 +48,14 @@ export class LionValidationFeedback extends LocalizeMixin(LitElement) {
48
48
  ];
49
49
  }
50
50
 
51
+ constructor() {
52
+ super();
53
+ /**
54
+ * @type {FeedbackMessage[] | undefined}
55
+ */
56
+ this.feedbackData = undefined;
57
+ }
58
+
51
59
  /**
52
60
  * @overridable
53
61
  * @param {Object} opts
@@ -69,16 +77,6 @@ export class LionValidationFeedback extends LocalizeMixin(LitElement) {
69
77
  if (this.feedbackData && this.feedbackData[0]) {
70
78
  this.setAttribute('type', this.feedbackData[0].type);
71
79
  this.currentType = this.feedbackData[0].type;
72
- window.clearTimeout(this.removeMessage);
73
- // TODO: this logic should be in ValidateMixin, so that [show-feedback-for] is in sync,
74
- // plus duration should be configurable
75
- if (this.currentType === 'success') {
76
- this.removeMessage = window.setTimeout(() => {
77
- this.removeAttribute('type');
78
- /** @type {FeedbackMessage[]} */
79
- this.feedbackData = [];
80
- }, 3000);
81
- }
82
80
  } else if (this.currentType !== 'success') {
83
81
  this.removeAttribute('type');
84
82
  }
@@ -590,7 +590,7 @@ export const ValidateMixinImplementation = superclass =>
590
590
  return [];
591
591
  }
592
592
 
593
- // If empty, do not show the ResulValidation message (e.g. Correct!)
593
+ // If empty, do not show the ResultValidation message (e.g. Correct!)
594
594
  if (this._isEmpty(this.modelValue)) {
595
595
  this.__prevShownValidationResult = [];
596
596
  return [];
@@ -619,7 +619,7 @@ export const ValidateMixinImplementation = superclass =>
619
619
  * - on sync validation
620
620
  * - on async validation (can depend on server response)
621
621
  *
622
- * This method inishes a pass by adding the properties to the instance:
622
+ * This method finishes a pass by adding the properties to the instance:
623
623
  * - validationStates
624
624
  * - hasFeedbackFor
625
625
  *
@@ -763,6 +763,7 @@ export const ValidateMixinImplementation = superclass =>
763
763
  * @property {string} type will be 'error' for messages from default Validators. Could be
764
764
  * 'warning', 'info' etc. for Validators with custom types. Needed as a directive for
765
765
  * feedbackNode how to render a message of a certain type
766
+ * @property {number} visibilityDuration duration in ms for how long the message should be shown
766
767
  * @property {Validator} [validator] when the message is directly coupled to a Validator
767
768
  * (in most cases), this property is filled. When a message is not coupled to a Validator
768
769
  * (in case of success feedback which is based on a diff or current and previous validation
@@ -788,7 +789,12 @@ export const ValidateMixinImplementation = superclass =>
788
789
  fieldName,
789
790
  outcome,
790
791
  });
791
- return { message, type: validator.type, validator };
792
+ return {
793
+ message,
794
+ type: validator.type,
795
+ validator,
796
+ visibilityDuration: validator.config?.visibilityDuration || 3000,
797
+ };
792
798
  }),
793
799
  );
794
800
  }
@@ -809,6 +815,8 @@ export const ValidateMixinImplementation = superclass =>
809
815
  * @protected
810
816
  */
811
817
  _updateFeedbackComponent() {
818
+ window.clearTimeout(this.removeMessage);
819
+
812
820
  const { _feedbackNode } = this;
813
821
  if (!_feedbackNode) {
814
822
  return;
@@ -840,6 +848,18 @@ export const ValidateMixinImplementation = superclass =>
840
848
 
841
849
  const messageMap = await this.__getFeedbackMessages(this.__prioritizedResult);
842
850
  _feedbackNode.feedbackData = messageMap || [];
851
+
852
+ if (
853
+ messageMap?.[0] &&
854
+ messageMap[0].type === 'success' &&
855
+ messageMap[0].visibilityDuration !== Infinity
856
+ ) {
857
+ this.removeMessage = window.setTimeout(() => {
858
+ _feedbackNode.removeAttribute('type');
859
+ /** @type {FeedbackMessage[]} */
860
+ _feedbackNode.feedbackData = [];
861
+ }, messageMap[0].visibilityDuration);
862
+ }
843
863
  });
844
864
  } else {
845
865
  this.__feedbackQueue.add(async () => {
@@ -33,28 +33,6 @@ describe('lion-validation-feedback', () => {
33
33
  expect(el.getAttribute('type')).to.equal('warning');
34
34
  });
35
35
 
36
- it('success message clears after 3s', async () => {
37
- const el = /** @type {LionValidationFeedback} */ (
38
- await fixture(html`<lion-validation-feedback></lion-validation-feedback>`)
39
- );
40
-
41
- const clock = sinon.useFakeTimers();
42
-
43
- el.feedbackData = [{ message: 'hello', type: 'success', validator: new AlwaysValid() }];
44
- await el.updateComplete;
45
- expect(el.getAttribute('type')).to.equal('success');
46
-
47
- clock.tick(2900);
48
-
49
- expect(el.getAttribute('type')).to.equal('success');
50
-
51
- clock.tick(200);
52
-
53
- expect(el).to.not.have.attribute('type');
54
-
55
- clock.restore();
56
- });
57
-
58
36
  it('does not clear error messages', async () => {
59
37
  const el = /** @type {LionValidationFeedback} */ (
60
38
  await fixture(html`<lion-validation-feedback></lion-validation-feedback>`)
@@ -349,6 +349,125 @@ export function runValidateMixinFeedbackPart() {
349
349
  expect(_feedbackNode.feedbackData?.[0].message).to.equal('Nachricht für MinLength');
350
350
  });
351
351
 
352
+ it('shows success message and clears after 3s', async () => {
353
+ class ValidateElementCustomTypes extends ValidateMixin(LitElement) {
354
+ static get validationTypes() {
355
+ return ['error', 'success'];
356
+ }
357
+ }
358
+ const clock = sinon.useFakeTimers();
359
+ const elTagString = defineCE(ValidateElementCustomTypes);
360
+ const elTag = unsafeStatic(elTagString);
361
+ const el = /** @type {ValidateElementCustomTypes} */ (
362
+ await fixture(html`
363
+ <${elTag}
364
+ .submitted=${true}
365
+ .validators=${[
366
+ new MinLength(3),
367
+ new DefaultSuccess(null, { getMessage: () => 'This is a success message' }),
368
+ ]}
369
+ >${lightDom}</${elTag}>
370
+ `)
371
+ );
372
+ const { _feedbackNode } = getFormControlMembers(el);
373
+
374
+ el.modelValue = 'a';
375
+ await el.updateComplete;
376
+ await el.feedbackComplete;
377
+ expect(_feedbackNode.feedbackData?.[0].message).to.equal('Message for MinLength');
378
+
379
+ el.modelValue = 'abcd';
380
+ await el.updateComplete;
381
+ await el.feedbackComplete;
382
+ expect(_feedbackNode.feedbackData?.[0].message).to.equal('This is a success message');
383
+ clock.tick(2900);
384
+ expect(_feedbackNode.feedbackData?.[0].message).to.equal('This is a success message');
385
+ clock.tick(200);
386
+ expect(_feedbackNode.feedbackData).to.be.empty;
387
+ });
388
+
389
+ it('shows success message and clears after configured time', async () => {
390
+ class ValidateElementCustomTypes extends ValidateMixin(LitElement) {
391
+ static get validationTypes() {
392
+ return ['error', 'success'];
393
+ }
394
+ }
395
+ const clock = sinon.useFakeTimers();
396
+ const elTagString = defineCE(ValidateElementCustomTypes);
397
+ const elTag = unsafeStatic(elTagString);
398
+ const el = /** @type {ValidateElementCustomTypes} */ (
399
+ await fixture(html`
400
+ <${elTag}
401
+ .submitted=${true}
402
+ .validators=${[
403
+ new MinLength(3),
404
+ new DefaultSuccess(null, {
405
+ getMessage: () => 'This is a success message',
406
+ visibilityDuration: 6000,
407
+ }),
408
+ ]}
409
+ >${lightDom}</${elTag}>
410
+ `)
411
+ );
412
+ const { _feedbackNode } = getFormControlMembers(el);
413
+
414
+ el.modelValue = 'a';
415
+ await el.updateComplete;
416
+ await el.feedbackComplete;
417
+ expect(_feedbackNode.feedbackData?.[0].message).to.equal('Message for MinLength');
418
+
419
+ el.modelValue = 'abcd';
420
+ await el.updateComplete;
421
+ await el.feedbackComplete;
422
+ expect(_feedbackNode.feedbackData?.[0].message).to.equal('This is a success message');
423
+ clock.tick(5900);
424
+ expect(_feedbackNode.feedbackData?.[0].message).to.equal('This is a success message');
425
+ clock.tick(200);
426
+ expect(_feedbackNode.feedbackData).to.be.empty;
427
+ });
428
+
429
+ it('shows success message and stays persistent', async () => {
430
+ class ValidateElementCustomTypes extends ValidateMixin(LitElement) {
431
+ static get validationTypes() {
432
+ return ['error', 'success'];
433
+ }
434
+ }
435
+ const clock = sinon.useFakeTimers();
436
+ const elTagString = defineCE(ValidateElementCustomTypes);
437
+ const elTag = unsafeStatic(elTagString);
438
+ const el = /** @type {ValidateElementCustomTypes} */ (
439
+ await fixture(html`
440
+ <${elTag}
441
+ .submitted=${true}
442
+ .validators=${[
443
+ new MinLength(3),
444
+ new DefaultSuccess(null, {
445
+ getMessage: () => 'This is a success message',
446
+ visibilityDuration: Infinity,
447
+ }),
448
+ ]}
449
+ >${lightDom}</${elTag}>
450
+ `)
451
+ );
452
+ const { _feedbackNode } = getFormControlMembers(el);
453
+
454
+ el.modelValue = 'a';
455
+ await el.updateComplete;
456
+ await el.feedbackComplete;
457
+ expect(_feedbackNode.feedbackData?.[0].message).to.equal('Message for MinLength');
458
+
459
+ el.modelValue = 'abcd';
460
+ await el.updateComplete;
461
+ await el.feedbackComplete;
462
+ expect(_feedbackNode.feedbackData?.[0].message).to.equal('This is a success message');
463
+ clock.tick(2900);
464
+ expect(_feedbackNode.feedbackData?.[0].message).to.equal('This is a success message');
465
+ clock.tick(200);
466
+ expect(_feedbackNode.feedbackData?.[0].message).to.equal('This is a success message');
467
+ clock.tick(20000);
468
+ expect(_feedbackNode.feedbackData?.[0].message).to.equal('This is a success message');
469
+ });
470
+
352
471
  it('shows success message after fixing an error', async () => {
353
472
  class ValidateElementCustomTypes extends ValidateMixin(LitElement) {
354
473
  static get validationTypes() {
@@ -31,6 +31,7 @@ export type ValidatorConfig = {
31
31
  type?: ValidationType;
32
32
  node?: FormControlHost;
33
33
  fieldName?: string | Promise<string>;
34
+ visibilityDuration?: number;
34
35
  };
35
36
 
36
37
  /**
@@ -29,6 +29,8 @@ function validateSvg(svg) {
29
29
 
30
30
  /**
31
31
  * Custom element for rendering SVG icons
32
+ *
33
+ * @customElement lion-icon
32
34
  */
33
35
  export class LionIcon extends LitElement {
34
36
  static get properties() {
@@ -31,6 +31,15 @@ function formatBytes(bytes, decimals = 2) {
31
31
  return `${parseFloat((bytes / k ** i).toFixed(dm))}${sizes[i]}`;
32
32
  }
33
33
 
34
+ /**
35
+ * LionInputFile: A file input component
36
+ * This component allows users to select files, displays selected files, and handles file uploads.
37
+ *
38
+ * @slot file-select-button - [private] The button to open the file dialog
39
+ * @slot selected-file-list - [private] The list of selected files
40
+ *
41
+ * @customElement lion-input-file
42
+ */
34
43
  export class LionInputFile extends ScopedElementsMixin(LocalizeMixin(LionField)) {
35
44
  static get scopedElements() {
36
45
  return {
@@ -18,6 +18,9 @@ import { localizeNamespaceLoader } from './localizeNamespaceLoader.js';
18
18
  * @typedef {FormatOptions & {regionCode: RegionCode; formatStrategy: PhoneNumberFormat; formatCountryCodeStyle: string;}} FormatOptionsTel
19
19
  */
20
20
 
21
+ /**
22
+ * @customElement lion-input-tel
23
+ */
21
24
  export class LionInputTel extends LocalizeMixin(LionInput) {
22
25
  /**
23
26
  * @configure LitElement
@@ -40,6 +40,8 @@ import { regionCodeToLocale } from './regionCodeToLocale.js';
40
40
  * possible. Also, it doesn't need to be a `FormControl`, because it's purely a helper element
41
41
  * to provide better UX: the modelValue (the text field) contains all needed info, since it's in
42
42
  * `e164` format that contains all info (both region code and national phone number).
43
+ *
44
+ * @customElement lion-input-tel-dropdown
43
45
  */
44
46
  export class LionInputTelDropdown extends LionInputTel {
45
47
  refs = {
@@ -7,6 +7,8 @@ import { ListboxMixin } from './ListboxMixin.js';
7
7
  /**
8
8
  * LionListbox: implements the wai-aria listbox design pattern and integrates it as a Lion
9
9
  * FormControl
10
+ *
11
+ * @customElement lion-listbox
10
12
  */
11
13
  export class LionListbox extends ListboxMixin(
12
14
  FocusMixin(InteractionStateMixin(ValidateMixin(LitElement))),
@@ -9,6 +9,10 @@ import { isEqualConfig } from './utils/is-equal-config.js';
9
9
  */
10
10
 
11
11
  /**
12
+ * @slot backdrop - The backdrop element for the overlay
13
+ * @slot content - The content element for the overlay
14
+ * @slot invoker - The invoker element for the overlay
15
+ *
12
16
  * @type {OverlayMixin}
13
17
  * @param {import('@open-wc/dedupe-mixin').Constructor<import('lit').LitElement>} superclass
14
18
  */
@@ -5,6 +5,10 @@ import { getLocalizeManager, LocalizeMixin } from '@lion/ui/localize-no-side-eff
5
5
  /**
6
6
  * @typedef {import('lit').TemplateResult} TemplateResult
7
7
  */
8
+
9
+ /**
10
+ * @customElement lion-progress-indicator
11
+ */
8
12
  export class LionProgressIndicator extends LocalizeMixin(LitElement) {
9
13
  static get properties() {
10
14
  return {
@@ -2,7 +2,9 @@ import { LitElement } from 'lit';
2
2
  import { ChoiceGroupMixin, FormGroupMixin } from '@lion/ui/form-core.js';
3
3
 
4
4
  /**
5
- * A wrapper around multiple radios.
5
+ * LionRadioGroup: A wrapper around multiple radios.
6
+ *
7
+ * @customElement lion-radio-group
6
8
  */
7
9
  export class LionRadioGroup extends ChoiceGroupMixin(FormGroupMixin(LitElement)) {
8
10
  connectedCallback() {
@@ -4,6 +4,10 @@ import { LionField } from '@lion/ui/form-core.js';
4
4
  /**
5
5
  * @typedef {import('../../localize/types/LocalizeMixinTypes.js').FormatNumberOptions} FormatOptions
6
6
  */
7
+
8
+ /**
9
+ * @customElement lion-field-with-select
10
+ */
7
11
  class LionFieldWithSelect extends LionField {
8
12
  /** @type {any} */
9
13
  static get properties() {
@@ -11,6 +11,8 @@ import { SlotMixin } from '@lion/ui/core.js';
11
11
 
12
12
  /**
13
13
  * LionSelectInvoker: invoker button consuming a selected element
14
+ *
15
+ * @customElement lion-select-invoker
14
16
  */
15
17
  export class LionSelectInvoker extends SlotMixin(LionButton) {
16
18
  static get styles() {
@@ -22,6 +22,8 @@ function detectInteractionMode() {
22
22
 
23
23
  /**
24
24
  * LionSelectRich: wraps the <lion-listbox> element
25
+ *
26
+ * @customElement lion-field-with-select
25
27
  */
26
28
  export class LionSelectRich extends SlotMixin(ScopedElementsMixin(OverlayMixin(LionListbox))) {
27
29
  static get scopedElements() {
@@ -8,7 +8,6 @@ import { css, html, LitElement } from 'lit';
8
8
  * `LionStep` is one of many in a LionSteps Controller
9
9
  *
10
10
  * @customElement lion-step
11
- * @extends {LitElement}
12
11
  */
13
12
  export class LionStep extends LitElement {
14
13
  static get properties() {
@@ -8,7 +8,6 @@ import { css, html, LitElement } from 'lit';
8
8
  * `LionSteps` is a controller for a multi step system.
9
9
  *
10
10
  * @customElement lion-steps
11
- * @extends {LitElement}
12
11
  */
13
12
  export class LionSteps extends LitElement {
14
13
  static get styles() {
@@ -3,6 +3,9 @@ import { ChoiceInputMixin, LionField } from '@lion/ui/form-core.js';
3
3
  import { ScopedElementsMixin } from '../../core/src/ScopedElementsMixin.js';
4
4
  import { LionSwitchButton } from './LionSwitchButton.js';
5
5
 
6
+ /**
7
+ * @customElement lion-switch
8
+ */
6
9
  export class LionSwitch extends ScopedElementsMixin(ChoiceInputMixin(LionField)) {
7
10
  static get styles() {
8
11
  return [