From 57eec5b599471dd5745b37911b3043457fe4cc64 Mon Sep 17 00:00:00 2001 From: Thijs Louisse Date: Thu, 24 Jul 2025 13:25:06 +0200 Subject: [PATCH] fix: make sure helpText and label respond to empty strings --- .changeset/proud-games-wave.md | 5 ++ .../form-core/src/FormControlMixin.js | 41 ++++++----- .../form-core/test/FormControlMixin.test.js | 68 +++++++++++++++++++ 3 files changed, 96 insertions(+), 18 deletions(-) create mode 100644 .changeset/proud-games-wave.md diff --git a/.changeset/proud-games-wave.md b/.changeset/proud-games-wave.md new file mode 100644 index 000000000..894516bbe --- /dev/null +++ b/.changeset/proud-games-wave.md @@ -0,0 +1,5 @@ +--- +'@lion/ui': patch +--- + +fix: make sure helpText and label respond to empty strings diff --git a/packages/ui/components/form-core/src/FormControlMixin.js b/packages/ui/components/form-core/src/FormControlMixin.js index e2af48ebe..974a07da7 100644 --- a/packages/ui/components/form-core/src/FormControlMixin.js +++ b/packages/ui/components/form-core/src/FormControlMixin.js @@ -52,7 +52,7 @@ const FormControlMixinImplementation = superclass => * @type {string} */ get label() { - return this.__label || (this._labelNode && this._labelNode.textContent) || ''; + return this.__label ?? (this._labelNode?.textContent || ''); } /** @@ -71,7 +71,7 @@ const FormControlMixinImplementation = superclass => * @type {string} */ get helpText() { - return this.__helpText || (this._helpTextNode && this._helpTextNode.textContent) || ''; + return this.__helpText ?? (this._helpTextNode?.textContent || ''); } /** @@ -158,6 +158,21 @@ const FormControlMixinImplementation = superclass => */ static enabledWarnings = super.enabledWarnings?.filter(w => w !== 'change-in-update') || []; + // N.B. add these label/helpText props for types + ce manifest output + // (explicity setting them to undefined does not have desired result) + + /** + * The label text for the input node. + * When no value is defined, textContent of [slot=label] will be used + * @property {string} label + */ + + /** + * The helpt text for the input node. + * When no value is defined, textContent of [slot=help-text] will be used + * @property {string} helpText + */ + constructor() { super(); @@ -171,26 +186,12 @@ const FormControlMixinImplementation = superclass => */ this.readOnly = false; - /** - * The label text for the input node. - * When no value is defined, textContent of [slot=label] will be used - * @type {string} - */ - this.label = ''; - /** * The label will only be visible for srceen readers when true * @type {boolean} */ this.labelSrOnly = false; - /** - * The helpt text for the input node. - * When no value is defined, textContent of [slot=help-text] will be used - * @type {string} - */ - this.helpText = ''; - /** * The model value is the result of the parser function(when available). * It should be considered as the internal value used for validation and reasoning/logic. @@ -293,11 +294,15 @@ const FormControlMixinImplementation = superclass => ); } - if (changedProperties.has('label') && this.__label && this._labelNode) { + if (changedProperties.has('label') && this.__label !== undefined && this._labelNode) { this._labelNode.textContent = this.label; } - if (changedProperties.has('helpText') && this.__helpText && this._helpTextNode) { + if ( + changedProperties.has('helpText') && + this.__helpText !== undefined && + this._helpTextNode + ) { this._helpTextNode.textContent = this.helpText; } diff --git a/packages/ui/components/form-core/test/FormControlMixin.test.js b/packages/ui/components/form-core/test/FormControlMixin.test.js index cae68ad51..53fee8421 100644 --- a/packages/ui/components/form-core/test/FormControlMixin.test.js +++ b/packages/ui/components/form-core/test/FormControlMixin.test.js @@ -86,6 +86,40 @@ describe('FormControlMixin', () => { expect(el.label).to.equal(''); }); + it('supports empty string as label', async () => { + const el = /** @type {FormControlMixinClass} */ ( + await fixture(html` + <${tag} label="With Value">${inputSlot} + `) + ); + + expect(el.label).to.equal('With Value'); + // @ts-expect-error + expect(el._labelNode.innerHTML).to.equal('With Value'); + + el.label = ''; + await el.updateComplete; + + expect(el.label).to.equal(''); + // @ts-expect-error + expect(el._labelNode.innerHTML).to.equal(''); + + // Reset + el.label = 'With Value'; + await el.updateComplete; + + expect(el.label).to.equal('With Value'); + // @ts-expect-error + expect(el._labelNode.innerHTML).to.equal('With Value'); + + el.setAttribute('label', ''); + await el.updateComplete; + + expect(el.label).to.equal(''); + // @ts-expect-error + expect(el._labelNode.innerHTML).to.equal(''); + }); + /** * N.B. For platform controls, the same would be achieved with * However, since FormControl is usually not the activeElement (_inputNode is), this @@ -176,6 +210,40 @@ describe('FormControlMixin', () => { ); expect(el.helpText).to.equal(''); }); + + it('supports empty string as help-text', async () => { + const el = /** @type {FormControlMixinClass} */ ( + await fixture(html` + <${tag} help-text="With Value">${inputSlot} + `) + ); + + expect(el.helpText).to.equal('With Value'); + // @ts-expect-error + expect(el._helpTextNode.innerHTML).to.equal('With Value'); + + el.helpText = ''; + await el.updateComplete; + + expect(el.helpText).to.equal(''); + // @ts-expect-error + expect(el._helpTextNode.innerHTML).to.equal(''); + + // Reset + el.helpText = 'With Value'; + await el.updateComplete; + + expect(el.helpText).to.equal('With Value'); + // @ts-expect-error + expect(el._helpTextNode.innerHTML).to.equal('With Value'); + + el.setAttribute('help-text', ''); + await el.updateComplete; + + expect(el.helpText).to.equal(''); + // @ts-expect-error + expect(el._helpTextNode.innerHTML).to.equal(''); + }); }); describe('Accessibility', () => {