diff --git a/.changeset/nervous-lions-trade.md b/.changeset/nervous-lions-trade.md new file mode 100644 index 000000000..22cfd6a0a --- /dev/null +++ b/.changeset/nervous-lions-trade.md @@ -0,0 +1,5 @@ +--- +'@lion/input-amount': patch +--- + +Empty or invalid currency now removes the currency label node, this is restored when the currency is valid again. diff --git a/packages/input-amount/src/LionInputAmount.js b/packages/input-amount/src/LionInputAmount.js index a2a62efca..93ebcff85 100644 --- a/packages/input-amount/src/LionInputAmount.js +++ b/packages/input-amount/src/LionInputAmount.js @@ -30,6 +30,20 @@ export class LionInputAmount extends LocalizeMixin(LionInput) { }; } + get slots() { + return { + ...super.slots, + after: () => { + const el = document.createElement('span'); + // The data-label attribute will make sure that FormControl adds this to + // input[aria-labelledby] + el.setAttribute('data-label', ''); + el.textContent = this.__currencyLabel; + return el; + }, + }; + } + static get styles() { return [ ...super.styles, @@ -49,6 +63,7 @@ export class LionInputAmount extends LocalizeMixin(LionInput) { this.currency = undefined; /** @type {string | undefined} */ this.locale = undefined; + this.__currencyDisplayNodeIsConnected = true; this.defaultValidators.push(new IsNumber()); } @@ -80,6 +95,20 @@ export class LionInputAmount extends LocalizeMixin(LionInput) { } } + /** + * Upon connecting slot mixin, we should check if + * the after slot was created by the slot mixin, + * and if so, we should execute the currency changed flow + * which evaluates whether the slot node should be + * removed for invalid currencies + */ + _connectSlotMixin() { + super._connectSlotMixin(); + if (this._isPrivateSlot('after')) { + this._onCurrencyChanged({ currency: this.currency || null }); + } + } + /** * @param {string} newLocale * @param {string} oldLocale @@ -108,31 +137,34 @@ export class LionInputAmount extends LocalizeMixin(LionInput) { * @protected */ _onCurrencyChanged({ currency }) { + if (!this.__currencyDisplayNode) { + return; + } + this.formatOptions.currency = currency || undefined; - if (this.currency) { - if (!this.__currencyDisplayNode) { - this.__currencyDisplayNode = this._createCurrencyDisplayNode(); + if (currency) { + if (!this.__currencyDisplayNodeIsConnected) { + this.appendChild(this.__currencyDisplayNode); + this.__currencyDisplayNodeIsConnected = true; } this.__currencyDisplayNode.textContent = this.__currencyLabel; - this._calculateValues({ source: null }); - } else { - this.__currencyDisplayNode = undefined; - } - this.__setCurrencyDisplayLabel(); - } - /** - * @returns a newly created node for displaying the currency - * @protected - */ - _createCurrencyDisplayNode() { - const el = document.createElement('span'); - // The data-label attribute will make sure that FormControl adds this to - // input[aria-labelledby] - el.setAttribute('data-label', ''); - el.textContent = this.__currencyLabel; - el.slot = 'after'; - return el; + try { + this._calculateValues({ source: null }); + } catch (e) { + // In case Intl.NumberFormat gives error for invalid currency + // we should catch, remove the node, and rethrow (since it's still a user error) + if (e instanceof RangeError) { + this.__currencyDisplayNode?.remove(); + this.__currencyDisplayNodeIsConnected = false; + } + throw e; + } + this.__setCurrencyDisplayLabel(); + } else { + this.__currencyDisplayNode?.remove(); + this.__currencyDisplayNodeIsConnected = false; + } } /** @@ -140,18 +172,12 @@ export class LionInputAmount extends LocalizeMixin(LionInput) { * @private */ get __currencyDisplayNode() { - return Array.from(this.children).find(child => child.slot === 'after'); - } - - /** - * @private - */ - set __currencyDisplayNode(node) { + const node = Array.from(this.children).find(child => child.slot === 'after'); if (node) { - this.appendChild(node); - } else { - this.__currencyDisplayNode?.remove(); + this.__storedCurrencyDisplayNode = node; } + + return node || this.__storedCurrencyDisplayNode; } /** @private */ diff --git a/packages/input-amount/test/lion-input-amount.test.js b/packages/input-amount/test/lion-input-amount.test.js index effc607f6..d3867f510 100644 --- a/packages/input-amount/test/lion-input-amount.test.js +++ b/packages/input-amount/test/lion-input-amount.test.js @@ -134,7 +134,6 @@ describe('', () => { const el = /** @type {LionInputAmount} */ ( await fixture(``) ); - expect( /** @type {HTMLElement[]} */ (Array.from(el.children)).find(child => child.slot === 'after') ?.innerText, @@ -230,7 +229,7 @@ describe('', () => { expect(currLabel?.getAttribute('aria-label')).to.equal('euros'); }); - it('sets currency label on the after after element', async () => { + it('sets currency label on the after element', async () => { const el = /** @type {LionInputAmount} */ ( await fixture(`