@lion/ui 0.8.1 → 0.8.2

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 (121) hide show
  1. package/components/calendar/src/LionCalendar.js +6 -0
  2. package/components/core/src/DisabledWithTabIndexMixin.js +7 -0
  3. package/components/core/src/ScopedElementsMixin.js +58 -37
  4. package/components/core/test/ScopedElementsMixin.test.js +131 -0
  5. package/components/core/test/ssr-definitions/ScopedElementsHost.define.js +1 -0
  6. package/components/form-core/src/FormControlMixin.js +6 -0
  7. package/components/form-core/src/utils/SyncUpdatableMixin.js +7 -0
  8. package/components/form-core/src/validate/LionValidationFeedback.js +4 -2
  9. package/components/form-core/test/validate/lion-validation-feedback.test.js +12 -0
  10. package/components/icon/src/LionIcon.js +6 -0
  11. package/components/localize/src/LocalizeManager.js +258 -178
  12. package/components/overlays/src/OverlayMixin.js +7 -0
  13. package/components/progress-indicator/src/LionProgressIndicator.js +6 -0
  14. package/components/steps/src/LionStep.js +6 -0
  15. package/components/steps/src/LionSteps.js +6 -0
  16. package/components/tabs/src/LionTabs.js +6 -0
  17. package/components/tooltip/src/LionTooltip.js +6 -0
  18. package/custom-elements.json +685 -159
  19. package/dist-types/components/calendar/src/LionCalendar.d.ts +5 -0
  20. package/dist-types/components/calendar/src/LionCalendar.d.ts.map +1 -1
  21. package/dist-types/components/core/src/DisabledWithTabIndexMixin.d.ts.map +1 -1
  22. package/dist-types/components/core/src/ScopedElementsMixin.d.ts +43 -6
  23. package/dist-types/components/core/src/ScopedElementsMixin.d.ts.map +1 -1
  24. package/dist-types/components/core/test/ScopedElementsMixin.test.d.ts +2 -0
  25. package/dist-types/components/core/test/ScopedElementsMixin.test.d.ts.map +1 -0
  26. package/dist-types/components/core/test/ssr-definitions/ScopedElementsHost.define.d.ts +2 -0
  27. package/dist-types/components/core/test/ssr-definitions/ScopedElementsHost.define.d.ts.map +1 -0
  28. package/dist-types/components/form-core/src/FormControlMixin.d.ts.map +1 -1
  29. package/dist-types/components/form-core/src/utils/SyncUpdatableMixin.d.ts.map +1 -1
  30. package/dist-types/components/form-core/src/validate/LionValidationFeedback.d.ts.map +1 -1
  31. package/dist-types/components/icon/src/LionIcon.d.ts +5 -0
  32. package/dist-types/components/icon/src/LionIcon.d.ts.map +1 -1
  33. package/dist-types/components/input-datepicker/src/LionInputDatepicker.d.ts +1 -1
  34. package/dist-types/components/input-file/src/LionInputFile.d.ts +1 -1
  35. package/dist-types/components/input-file/src/LionSelectedFileList.d.ts +1 -1
  36. package/dist-types/components/localize/src/LocalizeManager.d.ts +108 -93
  37. package/dist-types/components/localize/src/LocalizeManager.d.ts.map +1 -1
  38. package/dist-types/components/overlays/src/OverlayMixin.d.ts.map +1 -1
  39. package/dist-types/components/progress-indicator/src/LionProgressIndicator.d.ts +5 -0
  40. package/dist-types/components/progress-indicator/src/LionProgressIndicator.d.ts.map +1 -1
  41. package/dist-types/components/select-rich/src/LionSelectRich.d.ts +1 -1
  42. package/dist-types/components/steps/src/LionStep.d.ts +5 -0
  43. package/dist-types/components/steps/src/LionStep.d.ts.map +1 -1
  44. package/dist-types/components/steps/src/LionSteps.d.ts +5 -0
  45. package/dist-types/components/steps/src/LionSteps.d.ts.map +1 -1
  46. package/dist-types/components/switch/src/LionSwitch.d.ts +1 -1
  47. package/dist-types/components/tabs/src/LionTabs.d.ts +5 -0
  48. package/dist-types/components/tabs/src/LionTabs.d.ts.map +1 -1
  49. package/dist-types/components/tooltip/src/LionTooltip.d.ts +5 -0
  50. package/dist-types/components/tooltip/src/LionTooltip.d.ts.map +1 -1
  51. package/dist-types/tsconfig.tsbuildinfo +1 -1
  52. package/docs/components/checkbox-group/overview.md +2 -2
  53. package/docs/components/collapsible/overview.md +1 -1
  54. package/docs/components/combobox/overview.md +1 -1
  55. package/docs/components/combobox/use-cases.md +1 -1
  56. package/docs/components/dialog/overview.md +1 -1
  57. package/docs/components/fieldset/overview.md +5 -5
  58. package/docs/components/form/overview.md +3 -3
  59. package/docs/components/icon/use-cases.md +1 -1
  60. package/docs/components/input/api-table.md +1 -1
  61. package/docs/components/input/overview.md +1 -1
  62. package/docs/components/input-amount/api-table.md +1 -1
  63. package/docs/components/input-amount/overview.md +3 -3
  64. package/docs/components/input-date/api-table.md +1 -1
  65. package/docs/components/input-date/overview.md +3 -3
  66. package/docs/components/input-datepicker/api-table.md +1 -1
  67. package/docs/components/input-datepicker/overview.md +5 -5
  68. package/docs/components/input-email/api-table.md +1 -1
  69. package/docs/components/input-email/overview.md +2 -2
  70. package/docs/components/input-file/api-table.md +1 -1
  71. package/docs/components/input-file/overview.md +1 -1
  72. package/docs/components/input-iban/api-table.md +1 -1
  73. package/docs/components/input-iban/overview.md +2 -2
  74. package/docs/components/input-range/api-table.md +1 -1
  75. package/docs/components/input-range/overview.md +2 -2
  76. package/docs/components/input-stepper/api-table.md +1 -1
  77. package/docs/components/input-stepper/overview.md +1 -1
  78. package/docs/components/input-tel/api-table.md +1 -1
  79. package/docs/components/input-tel/overview.md +1 -1
  80. package/docs/components/input-tel/use-cases.md +6 -6
  81. package/docs/components/input-tel-dropdown/api-table.md +1 -1
  82. package/docs/components/input-tel-dropdown/overview.md +1 -1
  83. package/docs/components/listbox/use-cases.md +1 -1
  84. package/docs/components/radio-group/api-table.md +1 -1
  85. package/docs/components/radio-group/overview.md +3 -3
  86. package/docs/components/select/api-table.md +1 -1
  87. package/docs/components/select/use-cases.md +1 -1
  88. package/docs/components/select-rich/api-table.md +1 -1
  89. package/docs/components/select-rich/use-cases.md +1 -1
  90. package/docs/components/switch/api-table.md +1 -1
  91. package/docs/components/tabs/examples.md +1 -1
  92. package/docs/components/textarea/api-table.md +1 -1
  93. package/docs/fundamentals/index.md +4 -4
  94. package/docs/fundamentals/node-tools/providence-analytics/LocalConfiguration.md +1 -1
  95. package/docs/fundamentals/node-tools/providence-analytics/QueryResult.md +1 -1
  96. package/docs/fundamentals/node-tools/providence-analytics/analyzer.md +1 -1
  97. package/docs/fundamentals/node-tools/providence-analytics/dashboard.md +1 -1
  98. package/docs/fundamentals/node-tools/providence-analytics/overview.md +3 -3
  99. package/docs/fundamentals/node-tools/publish-docs/overview.md +3 -3
  100. package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +2 -2
  101. package/docs/fundamentals/rationales/accessibility.md +1 -1
  102. package/docs/fundamentals/systems/core/SlotMixin.md +1 -1
  103. package/docs/fundamentals/systems/core/overview.md +1 -1
  104. package/docs/fundamentals/systems/form/formatting-and-parsing.md +4 -4
  105. package/docs/fundamentals/systems/form/model-value.md +1 -1
  106. package/docs/fundamentals/systems/form/overview.md +28 -28
  107. package/docs/fundamentals/systems/form/validate.md +2 -2
  108. package/docs/fundamentals/systems/localize/api-table.md +38 -37
  109. package/docs/fundamentals/systems/localize/overview.md +4 -4
  110. package/docs/fundamentals/systems/overlays/configuration.md +2 -2
  111. package/docs/fundamentals/systems/overlays/overview.md +5 -5
  112. package/docs/fundamentals/systems/overlays/use-cases.md +2 -2
  113. package/docs/fundamentals/tools/helpers/overview.md +1 -1
  114. package/docs/fundamentals/tools/singleton-manager/overview.md +4 -4
  115. package/docs/guides/how-to/create-a-custom-field.md +5 -5
  116. package/docs/guides/how-to/create-a-form.md +4 -4
  117. package/docs/guides/how-to/extend-a-native-input.md +2 -2
  118. package/docs/guides/index.md +8 -8
  119. package/docs/guides/principles/index.md +5 -5
  120. package/docs/guides/principles/styling.md +1 -1
  121. package/package.json +1 -1
@@ -369,6 +369,12 @@ export class LionCalendar extends LocalizeMixin(LitElement) {
369
369
  }
370
370
  }
371
371
 
372
+ /**
373
+ * // TODO: check if this is a false positive or if we can improve
374
+ * @configure ReactiveElement
375
+ */
376
+ static enabledWarnings = super.enabledWarnings?.filter(w => w !== 'change-in-update') || [];
377
+
372
378
  /**
373
379
  * @private
374
380
  */
@@ -49,6 +49,13 @@ const DisabledWithTabIndexMixinImplementation = superclass =>
49
49
  }
50
50
  }
51
51
 
52
+ /**
53
+ * // TODO: check if this is a false positive or if we can improve
54
+ * @configure ReactiveElement
55
+ */
56
+ // @ts-expect-error
57
+ static enabledWarnings = super.enabledWarnings?.filter(w => w !== 'change-in-update') || [];
58
+
52
59
  /**
53
60
  * @param {number} value
54
61
  * @private
@@ -1,6 +1,31 @@
1
- /*
1
+ import { dedupeMixin } from '@open-wc/dedupe-mixin';
2
+ import { adoptStyles, isServer } from 'lit';
3
+ import { ScopedElementsMixin as OpenWcLitScopedElementsMixin } from '@open-wc/scoped-elements/lit-element.js';
4
+
5
+ /**
6
+ * @typedef {import('../../form-core/types/validate/ValidateMixinTypes.js').ScopedElementsMap} ScopedElementsMap
7
+ * @typedef {import('@open-wc/dedupe-mixin').Constructor<ScopedElementsHost>} ScopedElementsHostConstructor
8
+ * @typedef {import('@open-wc/scoped-elements/lit-element.js').ScopedElementsHost} ScopedElementsHost
9
+ * @typedef {import('./types.js').ScopedElementsHostV2Constructor} ScopedElementsHostV2Constructor
10
+ * @typedef {import('@open-wc/dedupe-mixin').Constructor<LitElement>} LitElementConstructor
11
+ * @typedef {import('lit').CSSResultOrNative} CSSResultOrNative
12
+ * @typedef {typeof import('lit').LitElement} TypeofLitElement
13
+ * @typedef {import('lit').LitElement} LitElement
14
+ */
15
+
16
+ export function supportsScopedRegistry() {
17
+ return Boolean(
18
+ // @ts-expect-error
19
+ globalThis.ShadowRoot?.prototype.createElement && globalThis.ShadowRoot?.prototype.importNode,
20
+ );
21
+ }
22
+
23
+ /**
2
24
  * This file is combination of '@open-wc/scoped-elements@v3/lit-element.js' and '@open-wc/scoped-elements@v3/html-element.js'.
3
25
  * Then on top of those, some code from '@open-wc/scoped-elements@v2' is brought to to make polyfill not mandatory.
26
+ * This can be a great help for ssr scenarios, allowing elements to be consumed without needing knowledge about internall
27
+ * consumption.
28
+ * (N.B. at this point in time, this is limited to the scenario where there's one version of lion on the page).
4
29
  *
5
30
  * ## Considerations
6
31
  * In its current state, the [scoped-custom-element-registry](https://github.com/webcomponents/polyfills/tree/master/packages/scoped-custom-element-registry) draft spec has uncertainties:
@@ -21,29 +46,7 @@
21
46
  * This can be beneficial for performance, bundle size, ease of use and SSR capabilities.
22
47
  *
23
48
  * We will keep a close eye on developments in spec and polyfill, and will re-evaluate the scoped-elements approach when the time is right.
24
- */
25
-
26
- import { dedupeMixin } from '@open-wc/dedupe-mixin';
27
- import { adoptStyles } from 'lit';
28
- import { ScopedElementsMixin as OpenWcLitScopedElementsMixin } from '@open-wc/scoped-elements/lit-element.js';
29
-
30
- /**
31
- * @typedef {import('@open-wc/scoped-elements/lit-element.js').ScopedElementsHost} ScopedElementsHost
32
- * @typedef {import('../../form-core/types/validate/ValidateMixinTypes.js').ScopedElementsMap} ScopedElementsMap
33
- * @typedef {import('lit').CSSResultOrNative} CSSResultOrNative
34
- * @typedef {import('lit').LitElement} LitElement
35
- * @typedef {typeof import('lit').LitElement} TypeofLitElement
36
- * @typedef {import('@open-wc/dedupe-mixin').Constructor<LitElement>} LitElementConstructor
37
- * @typedef {import('@open-wc/dedupe-mixin').Constructor<ScopedElementsHost>} ScopedElementsHostConstructor
38
- * @typedef {import('./types.js').ScopedElementsHostV2Constructor} ScopedElementsHostV2Constructor
39
- */
40
-
41
- const supportsScopedRegistry = Boolean(
42
- // @ts-expect-error
43
- ShadowRoot.prototype.createElement && ShadowRoot.prototype.importNode,
44
- );
45
-
46
- /**
49
+ *
47
50
  * @template {LitElementConstructor} T
48
51
  * @param {T} superclass
49
52
  * @return {T & ScopedElementsHostConstructor & ScopedElementsHostV2Constructor}
@@ -51,8 +54,29 @@ const supportsScopedRegistry = Boolean(
51
54
  const ScopedElementsMixinImplementation = superclass =>
52
55
  /** @type {ScopedElementsHost} */
53
56
  class ScopedElementsHost extends OpenWcLitScopedElementsMixin(superclass) {
57
+ constructor() {
58
+ super();
59
+
60
+ if (isServer) {
61
+ // We are on the server: this means we can't support scoped registries...
62
+ // So we must treat it like the "no-polyfill scenario", that registers scoped
63
+ // elements used for internal composition on the global registry.
64
+ // On the client that would happen in connectedCallback, so we do it here...
65
+ // N.B. keep in mind that this does not work when we have multiple element (versions)
66
+ // with the same name. (like multiple versions of lion extension layers).
67
+ // If we want to support this, we must re-introduce the shim-behavior of ScopedElementsMixin v1
68
+ // to make this work with ssr as well.
69
+ // @ts-expect-error
70
+ this.registry = customElements;
71
+ // @ts-expect-error
72
+ for (const [name, klass] of Object.entries(this.constructor.scopedElements || {})) {
73
+ this.defineScopedElement(name, klass);
74
+ }
75
+ }
76
+ }
77
+
54
78
  createScopedElement(/** @type {string} */ tagName) {
55
- const root = supportsScopedRegistry ? this.shadowRoot : document;
79
+ const root = supportsScopedRegistry() ? this.shadowRoot : document;
56
80
  // @ts-expect-error polyfill to support createElement on shadowRoot is loaded
57
81
  return root.createElement(tagName);
58
82
  }
@@ -61,12 +85,12 @@ const ScopedElementsMixinImplementation = superclass =>
61
85
  * Defines a scoped element.
62
86
  *
63
87
  * @param {string} tagName
64
- * @param {typeof HTMLElement} klass
88
+ * @param {typeof HTMLElement} classToBeRegistered
65
89
  */
66
- defineScopedElement(tagName, klass) {
67
- // @ts-ignore
90
+ defineScopedElement(tagName, classToBeRegistered) {
68
91
  const registeredClass = this.registry.get(tagName);
69
- if (registeredClass && supportsScopedRegistry === false && registeredClass !== klass) {
92
+ const isAlreadyRegistered = registeredClass && registeredClass === classToBeRegistered;
93
+ if (isAlreadyRegistered && !supportsScopedRegistry()) {
70
94
  // eslint-disable-next-line no-console
71
95
  console.error(
72
96
  [
@@ -80,10 +104,8 @@ const ScopedElementsMixinImplementation = superclass =>
80
104
  );
81
105
  }
82
106
  if (!registeredClass) {
83
- // @ts-ignore
84
- return this.registry.define(tagName, klass);
107
+ return this.registry.define(tagName, classToBeRegistered);
85
108
  }
86
- // @ts-ignore
87
109
  return this.registry.get(tagName);
88
110
  }
89
111
 
@@ -92,12 +114,12 @@ const ScopedElementsMixinImplementation = superclass =>
92
114
  * @returns {ShadowRoot}
93
115
  */
94
116
  attachShadow(options) {
95
- // @ts-ignore
117
+ // @ts-expect-error
96
118
  const { scopedElements } = /** @type {typeof ScopedElementsHost} */ (this.constructor);
97
119
 
98
120
  const shouldCreateRegistry =
99
121
  !this.registry ||
100
- // @ts-ignore
122
+ // @ts-expect-error
101
123
  (this.registry === this.constructor.__registry &&
102
124
  !Object.prototype.hasOwnProperty.call(this.constructor, '__registry'));
103
125
 
@@ -108,8 +130,7 @@ const ScopedElementsMixinImplementation = superclass =>
108
130
  * This is important specifically for superclasses/inheritance
109
131
  */
110
132
  if (shouldCreateRegistry) {
111
- // @ts-ignore
112
- this.registry = supportsScopedRegistry ? new CustomElementRegistry() : customElements;
133
+ this.registry = supportsScopedRegistry() ? new CustomElementRegistry() : customElements;
113
134
  for (const [tagName, klass] of Object.entries(scopedElements ?? {})) {
114
135
  this.defineScopedElement(tagName, klass);
115
136
  }
@@ -131,7 +152,7 @@ const ScopedElementsMixinImplementation = superclass =>
131
152
  );
132
153
 
133
154
  const createdRoot = this.attachShadow(shadowRootOptions);
134
- if (supportsScopedRegistry) {
155
+ if (supportsScopedRegistry()) {
135
156
  // @ts-expect-error
136
157
  this.renderOptions.creationScope = createdRoot;
137
158
  }
@@ -0,0 +1,131 @@
1
+ import { expect, fixture } from '@open-wc/testing';
2
+ import {
3
+ ssrNonHydratedFixture,
4
+ ssrHydratedFixture,
5
+ csrFixture,
6
+ } from '@lit-labs/testing/fixtures.js';
7
+ import { LitElement, html } from 'lit';
8
+ import sinon from 'sinon';
9
+ import { browserDetection } from '../src/browserDetection.js';
10
+
11
+ import { ScopedElementsMixin, supportsScopedRegistry } from '../src/ScopedElementsMixin.js';
12
+
13
+ const hasRealScopedRegistrySupport = supportsScopedRegistry();
14
+ const originalShadowRootProps = {
15
+ // @ts-expect-error
16
+ createElement: globalThis.ShadowRoot?.prototype.createElement,
17
+ // @ts-expect-error
18
+ importNode: globalThis.ShadowRoot?.prototype.importNode,
19
+ };
20
+
21
+ // Even though the polyfill might be loaded in this test or we run it in a browser supporting these features,
22
+ // we mock "no support", so that `supportsScopedRegistry()` returns false inside ScopedElementsMixin..
23
+ function mockNoRegistrySupport() {
24
+ // Are we on a server or do we have no polyfill? Nothing to be done here...
25
+ if (!hasRealScopedRegistrySupport) return;
26
+
27
+ // This will be enough to make the `supportsScopedRegistry()` check fail inside ScopedElementsMixin and bypass scoped registries
28
+ globalThis.ShadowRoot = globalThis.ShadowRoot || { prototype: {} };
29
+ // @ts-expect-error
30
+ globalThis.ShadowRoot.prototype.createElement = null;
31
+ }
32
+
33
+ mockNoRegistrySupport.restore = () => {
34
+ // Are we on a server or do we have no polyfill? Nothing to be done here...
35
+ if (!hasRealScopedRegistrySupport) return;
36
+
37
+ // @ts-expect-error
38
+ globalThis.ShadowRoot.prototype.createElement = originalShadowRootProps.createElement;
39
+ // @ts-expect-error
40
+ globalThis.ShadowRoot.prototype.importNode = originalShadowRootProps.importNode;
41
+ };
42
+
43
+ class ScopedElementsChild extends LitElement {
44
+ render() {
45
+ return html`<span>I'm a child</span>`;
46
+ }
47
+ }
48
+
49
+ class ScopedElementsHost extends ScopedElementsMixin(LitElement) {
50
+ static scopedElements = { 'scoped-elements-child': ScopedElementsChild };
51
+
52
+ render() {
53
+ return html`<scoped-elements-child></scoped-elements-child>`;
54
+ }
55
+ }
56
+ customElements.define('scoped-elements-host', ScopedElementsHost);
57
+
58
+ describe('ScopedElementsMixin', () => {
59
+ it('renders child elements correctly (that were not registered yet on global registry)', async () => {
60
+ // customElements.define('scoped-elements-child', ScopedElementsChild);
61
+ for (const _fixture of [csrFixture, ssrNonHydratedFixture, ssrHydratedFixture]) {
62
+ const el = await _fixture(html`<scoped-elements-host></scoped-elements-host>`, {
63
+ // we must provide modules atm
64
+ modules: ['./ssr-definitions/ScopedElementsHost.define.js'],
65
+ });
66
+
67
+ // Wait for FF support
68
+ if (!browserDetection.isFirefox) {
69
+ expect(
70
+ el.shadowRoot?.querySelector('scoped-elements-child')?.shadowRoot?.innerHTML,
71
+ ).to.contain("<span>I'm a child</span>");
72
+ }
73
+
74
+ // @ts-expect-error
75
+ expect(el.registry.get('scoped-elements-child')).to.not.be.undefined;
76
+ }
77
+ });
78
+
79
+ describe('When scoped registries are supported', () => {
80
+ it('registers elements on local registry', async () => {
81
+ const ceDefineSpy = sinon.spy(customElements, 'define');
82
+
83
+ const el = /** @type {ScopedElementsHost} */ (
84
+ await fixture(html`<scoped-elements-host></scoped-elements-host>`)
85
+ );
86
+
87
+ // @ts-expect-error
88
+ expect(el.registry.get('scoped-elements-child')).to.equal(ScopedElementsChild);
89
+ expect(el.registry).to.not.equal(customElements);
90
+ expect(ceDefineSpy.calledWith('scoped-elements-child')).to.be.false;
91
+
92
+ ceDefineSpy.restore();
93
+ });
94
+ });
95
+
96
+ describe('When scoped registries are not supported', () => {
97
+ class ScopedElementsChildNoReg extends LitElement {
98
+ render() {
99
+ return html`<span>I'm a child</span>`;
100
+ }
101
+ }
102
+
103
+ class ScopedElementsHostNoReg extends ScopedElementsMixin(LitElement) {
104
+ static scopedElements = { 'scoped-elements-child-no-reg': ScopedElementsChildNoReg };
105
+
106
+ render() {
107
+ return html`<scoped-elements-child-no-reg></scoped-elements-child-no-reg>`;
108
+ }
109
+ }
110
+ before(() => {
111
+ mockNoRegistrySupport();
112
+ customElements.define('scoped-elements-host-no-reg', ScopedElementsHostNoReg);
113
+ });
114
+
115
+ after(() => {
116
+ mockNoRegistrySupport.restore();
117
+ });
118
+
119
+ it('registers elements', async () => {
120
+ const ceDefineSpy = sinon.spy(customElements, 'define');
121
+
122
+ const el = /** @type {ScopedElementsHostNoReg} */ (
123
+ await fixture(html`<scoped-elements-host-no-reg></scoped-elements-host-no-reg>`)
124
+ );
125
+
126
+ expect(el.registry).to.equal(customElements);
127
+ expect(ceDefineSpy.calledWith('scoped-elements-child-no-reg')).to.be.true;
128
+ ceDefineSpy.restore();
129
+ });
130
+ });
131
+ });
@@ -0,0 +1 @@
1
+ // ... empty file needed for '@lit-labs/testing/fixtures.js'
@@ -152,6 +152,12 @@ const FormControlMixinImplementation = superclass =>
152
152
  return /** @type {LionValidationFeedback} */ (this.__getDirectSlotChild('feedback'));
153
153
  }
154
154
 
155
+ /**
156
+ * TODO: check if this is a false positive or if we can improve
157
+ * @configure ReactiveElement
158
+ */
159
+ static enabledWarnings = super.enabledWarnings?.filter(w => w !== 'change-in-update') || [];
160
+
155
161
  constructor() {
156
162
  super();
157
163
 
@@ -56,6 +56,13 @@ const SyncUpdatableMixinImplementation = superclass =>
56
56
  this.__SyncUpdatableNamespace.connected = false;
57
57
  }
58
58
 
59
+ /**
60
+ * // TODO: check if this is a false positive or if we can improve
61
+ * @configure ReactiveElement
62
+ */
63
+ // @ts-expect-error
64
+ static enabledWarnings = super.enabledWarnings?.filter(w => w !== 'change-in-update') || [];
65
+
59
66
  /**
60
67
  * Makes the propertyAccessor.`hasChanged` compatible in synchronous updates
61
68
  * @param {string} name
@@ -1,4 +1,4 @@
1
- import { css, html, LitElement } from 'lit';
1
+ import { css, html, LitElement, nothing } from 'lit';
2
2
  import { LocalizeMixin } from '@lion/ui/localize-no-side-effects.js';
3
3
  import { localizeNamespaceLoader } from '../localizeNamespaceLoader.js';
4
4
 
@@ -90,7 +90,9 @@ export class LionValidationFeedback extends LocalizeMixin(LitElement) {
90
90
  this.feedbackData.map(
91
91
  ({ message, type, validator }) => html`
92
92
  <div class="validation-feedback__type">
93
- ${this._localizeManager.msg(`lion-form-core:validation${capitalize(type)}`)}
93
+ ${message && type
94
+ ? this._localizeManager.msg(`lion-form-core:validation${capitalize(type)}`)
95
+ : nothing}
94
96
  </div>
95
97
  ${this._messageTemplate({ message, type, validator })}
96
98
  `,
@@ -91,6 +91,18 @@ describe('lion-validation-feedback', () => {
91
91
  expect(validationFeedbackType?.textContent?.trim()).to.equal('Info');
92
92
  });
93
93
 
94
+ it('it does not share the type if there is no message', async () => {
95
+ const el = /** @type {LionValidationFeedback} */ (
96
+ await fixture(html`<lion-validation-feedback></lion-validation-feedback>`)
97
+ );
98
+
99
+ el.feedbackData = [{ message: '', type: 'error', validator: new AlwaysInvalid() }];
100
+ await el.updateComplete;
101
+
102
+ const validationFeedbackType = el.shadowRoot?.querySelector('.validation-feedback__type');
103
+ expect(validationFeedbackType?.textContent?.trim()).to.not.equal('Error');
104
+ });
105
+
94
106
  describe('accessibility', () => {
95
107
  it('passes a11y audit when with a message', async () => {
96
108
  const el = /** @type {LionValidationFeedback} */ (
@@ -102,6 +102,12 @@ export class LionIcon extends LitElement {
102
102
  this.__svg = nothing;
103
103
  }
104
104
 
105
+ /**
106
+ * TODO: check if this is a false positive or if we can improve
107
+ * @configure ReactiveElement
108
+ */
109
+ static enabledWarnings = super.enabledWarnings?.filter(w => w !== 'change-in-update') || [];
110
+
105
111
  /** @param {import('lit').PropertyValues} changedProperties */
106
112
  update(changedProperties) {
107
113
  super.update(changedProperties);