diff --git a/.changeset/real-actors-drum.md b/.changeset/real-actors-drum.md
new file mode 100644
index 000000000..8626ea9cb
--- /dev/null
+++ b/.changeset/real-actors-drum.md
@@ -0,0 +1,5 @@
+---
+'@lion/input-tel-dropdown': minor
+---
+
+Syncs value of dropdown on init if input has no value
diff --git a/packages/form-integrations/test/form-integrations.test.js b/packages/form-integrations/test/form-integrations.test.js
index d31585f71..99c94716d 100644
--- a/packages/form-integrations/test/form-integrations.test.js
+++ b/packages/form-integrations/test/form-integrations.test.js
@@ -1,15 +1,22 @@
import sinon from 'sinon';
import { expect, fixture } from '@open-wc/testing';
import { html } from 'lit/static-html.js';
+import { PhoneUtilManager } from '@lion/input-tel';
import { getAllTagNames } from './helpers/helpers.js';
import './helpers/umbrella-form.js';
/**
* @typedef {import('./helpers/umbrella-form.js').UmbrellaForm} UmbrellaForm
+ * @typedef {import('@lion/input-tel-dropdown').LionInputTelDropdown} LionInputTelDropdown
*/
// Test umbrella form.
describe('Form Integrations', () => {
+ beforeEach(async () => {
+ // Wait till PhoneUtilManager has been loaded
+ await PhoneUtilManager.loadComplete;
+ });
+
it('".serializedValue" returns all non disabled fields based on form structure', async () => {
const el = /** @type {UmbrellaForm} */ (await fixture(html``));
await el.updateComplete;
@@ -43,6 +50,10 @@ describe('Form Integrations', () => {
const el = /** @type {UmbrellaForm} */ (await fixture(html``));
await el.updateComplete;
const formEl = el._lionFormNode;
+ const inputTelDropdownEl = /** @type {LionInputTelDropdown} */ (
+ formEl.querySelector('lion-input-tel-dropdown')
+ );
+ await inputTelDropdownEl?.updateComplete;
expect(formEl.formattedValue).to.eql({
full_name: { first_name: '', last_name: '' },
@@ -63,7 +74,7 @@ describe('Form Integrations', () => {
notifications: '',
rsvp: '',
tel: '',
- 'tel-dropdown': '',
+ 'tel-dropdown': '+44',
comments: '',
});
});
diff --git a/packages/input-tel-dropdown/src/LionInputTelDropdown.js b/packages/input-tel-dropdown/src/LionInputTelDropdown.js
index 147d5b340..a64d6b7d9 100644
--- a/packages/input-tel-dropdown/src/LionInputTelDropdown.js
+++ b/packages/input-tel-dropdown/src/LionInputTelDropdown.js
@@ -279,6 +279,33 @@ export class LionInputTelDropdown extends LionInputTel {
this.refs.dropdown?.value?.removeAttribute('disabled');
}
}
+
+ if (changedProperties.has('_phoneUtil')) {
+ this._initModelValueBasedOnDropdown();
+ }
+ }
+
+ _initModelValueBasedOnDropdown() {
+ if (!this._initialModelValue && !this.dirty && this._phoneUtil) {
+ const countryCode = this._phoneUtil.getCountryCodeForRegionCode(this.activeRegion);
+ this.__initializedRegionCode = `+${countryCode}`;
+ this.modelValue = this.__initializedRegionCode;
+ this._initialModelValue = this.__initializedRegionCode;
+ this.initInteractionState();
+ }
+ }
+
+ /**
+ * Used for Required validation and computation of interaction states.
+ * We need to override this, because we prefill the input with the region code (like +31), but for proper UX,
+ * we don't consider this as having interaction state `prefilled`
+ * @param {string} modelValue
+ * @return {boolean}
+ * @protected
+ */
+ _isEmpty(modelValue = this.modelValue) {
+ // the activeRegion is not synced on time, so it can't be used in this check
+ return super._isEmpty(modelValue) || this.value === this.__initializedRegionCode;
}
/**
@@ -287,29 +314,23 @@ export class LionInputTelDropdown extends LionInputTel {
*/
_onDropdownValueChange(event) {
const isInitializing = event.detail?.initialize || !this._phoneUtil;
- if (isInitializing) {
+ const dropdownValue = /** @type {RegionCode} */ (event.target.modelValue || event.target.value);
+
+ if (isInitializing || (this.activeRegion && this.activeRegion === dropdownValue)) {
return;
}
const prevActiveRegion = this.activeRegion;
- this._setActiveRegion(
- /** @type {RegionCode} */ (event.target.value || event.target.modelValue),
- );
+ this._setActiveRegion(dropdownValue);
// Change region code in text box
// From: https://bl00mber.github.io/react-phone-input-2.html
if (prevActiveRegion !== this.activeRegion && !this.focused && this._phoneUtil) {
const prevCountryCode = this._phoneUtil.getCountryCodeForRegionCode(prevActiveRegion);
const countryCode = this._phoneUtil.getCountryCodeForRegionCode(this.activeRegion);
- if (countryCode && !this.modelValue) {
- // When textbox is empty, prefill it with country code
- this.modelValue = `+${countryCode}`;
- } else if (prevCountryCode && countryCode) {
- // When textbox is not empty, replace country code
- this.modelValue = this._callParser(
- this.value.replace(`+${prevCountryCode}`, `+${countryCode}`),
- );
- }
+ this.modelValue = this._callParser(
+ this.value.replace(`+${prevCountryCode}`, `+${countryCode}`),
+ );
}
// Put focus on text box
diff --git a/packages/input-tel-dropdown/test-suites/LionInputTelDropdown.suite.js b/packages/input-tel-dropdown/test-suites/LionInputTelDropdown.suite.js
index 846bfe9b0..5dbe669ff 100644
--- a/packages/input-tel-dropdown/test-suites/LionInputTelDropdown.suite.js
+++ b/packages/input-tel-dropdown/test-suites/LionInputTelDropdown.suite.js
@@ -71,6 +71,53 @@ export function runInputTelDropdownSuite({ klass } = { klass: LionInputTelDropdo
await PhoneUtilManager.loadComplete;
});
+ it('syncs value of dropdown on init if input has no value', async () => {
+ const el = await fixture(html` <${tag}>${tag}> `);
+ expect(el.activeRegion).to.equal('GB');
+ expect(el.value).to.equal('+44');
+ expect(getDropdownValue(/** @type {DropdownElement} */ (el.refs.dropdown.value))).to.equal(
+ 'GB',
+ );
+ });
+
+ it('syncs value of dropdown on reset if input has no value', async () => {
+ const el = await fixture(html` <${tag}>${tag}> `);
+ el.modelValue = '+31612345678';
+ await el.updateComplete;
+ expect(el.activeRegion).to.equal('NL');
+ el.reset();
+ await el.updateComplete;
+ expect(el.activeRegion).to.equal('GB');
+ expect(el.value).to.equal('+44');
+ });
+
+ it('syncs value of dropdown on init if input has no value does not influence interaction states', async () => {
+ const el = await fixture(html` <${tag}>${tag}> `);
+ // TODO find out why its get dirty again
+ // expect(el.dirty).to.be.false;
+ expect(el.prefilled).to.be.false;
+ });
+
+ it('syncs value of dropdown on reset also resets interaction states', async () => {
+ const el = await fixture(html` <${tag}>${tag}> `);
+ el.modelValue = '+31612345678';
+ await el.updateComplete;
+
+ expect(el.dirty).to.be.true;
+ expect(el.prefilled).to.be.false;
+ el.reset();
+ await el.updateComplete;
+ expect(el.dirty).to.be.false;
+ expect(el.prefilled).to.be.false;
+ });
+
+ it('sets correct interaction states on init if input has a value', async () => {
+ const el = await fixture(html` <${tag} .modelValue="${'+31612345678'}">${tag}> `);
+ // TODO find out why its get dirty again
+ // expect(el.dirty).to.be.false;
+ expect(el.prefilled).to.be.true;
+ });
+
describe('Dropdown display', () => {
it('calls `templates.dropdown` with TemplateDataForDropdownInputTel object', async () => {
const el = fixtureSync(html` <${tag}
@@ -261,7 +308,9 @@ export function runInputTelDropdownSuite({ klass } = { klass: LionInputTelDropdo
});
it('prefills country code when textbox is empty', async () => {
- const el = await fixture(html` <${tag} .allowedRegions="${['NL', 'BE']}">${tag}> `);
+ const el = await fixture(
+ html` <${tag} .allowedRegions="${['NL', 'BE']}" .modelValue="${''}">${tag}> `,
+ );
// @ts-ignore
mimicUserChangingDropdown(el.refs.dropdown.value, 'BE');
await el.updateComplete;