From f19befe9c45db4997415cb0bc27e34995271c54e Mon Sep 17 00:00:00 2001 From: vbabu35 <78204273+vbabu35@users.noreply.github.com> Date: Tue, 29 Jul 2025 20:51:22 +0530 Subject: [PATCH] fix: preselection in combobox Co-authored-by: JYOTHI Co-authored-by: Thijs Louisse --- .changeset/rich-queens-shout.md | 5 + .../components/combobox/src/LionCombobox.js | 4 +- .../combobox/test/lion-combobox.test.js | 126 ++++++++++-------- 3 files changed, 77 insertions(+), 58 deletions(-) create mode 100644 .changeset/rich-queens-shout.md diff --git a/.changeset/rich-queens-shout.md b/.changeset/rich-queens-shout.md new file mode 100644 index 000000000..3bbb8d18b --- /dev/null +++ b/.changeset/rich-queens-shout.md @@ -0,0 +1,5 @@ +--- +'@lion/ui': patch +--- + +[combobox] fix preselection in combobox when modelValue present diff --git a/packages/ui/components/combobox/src/LionCombobox.js b/packages/ui/components/combobox/src/LionCombobox.js index 8328a5e9f..b345901ec 100644 --- a/packages/ui/components/combobox/src/LionCombobox.js +++ b/packages/ui/components/combobox/src/LionCombobox.js @@ -1180,9 +1180,7 @@ export class LionCombobox extends LocalizeMixin(OverlayMixin(CustomChoiceGroupMi */ // eslint-disable-next-line no-unused-vars _syncToTextboxCondition(modelValue, oldModelValue, { phase } = {}) { - return ( - this.autocomplete === 'inline' || this.autocomplete === 'both' || phase === 'overlay-close' - ); + return this.autocomplete === 'both' || this.autocomplete === 'inline' || !this.focused; } /** diff --git a/packages/ui/components/combobox/test/lion-combobox.test.js b/packages/ui/components/combobox/test/lion-combobox.test.js index e1af919c3..210c4ff94 100644 --- a/packages/ui/components/combobox/test/lion-combobox.test.js +++ b/packages/ui/components/combobox/test/lion-combobox.test.js @@ -640,38 +640,39 @@ describe('lion-combobox', () => { }); it('syncs textbox to modelValue', async () => { - const el = /** @type {LionCombobox} */ ( - await fixture(html` - - Aha - Bhb - - `) - ); - const { _inputNode } = getComboboxMembers(el); + for (const autocompleteMode of ['none', 'list', 'inline', 'both']) { + const el = /** @type {LionCombobox} */ ( + await fixture(html` + + Aa + Bb + + `) + ); + const { _inputNode } = getComboboxMembers(el); + + expect(_inputNode.value).to.equal('Aa', `autocompleteMode is ${autocompleteMode}`); - /** @param {string} autocompleteMode */ - async function performChecks(autocompleteMode) { el.formElements[0].click(); await el.updateComplete; - // FIXME: fix properly for Webkit - // expect(_inputNode.value).to.equal('Aha', `autocompleteMode is ${autocompleteMode}`); + expect(_inputNode.value).to.equal('Aa', `autocompleteMode is ${autocompleteMode}`); expect(el.checkedIndex).to.equal(0, `autocompleteMode is ${autocompleteMode}`); - await mimicUserTyping(el, 'Ah'); + await mimicUserTyping(el, 'B'); await el.updateComplete; - expect(_inputNode.value).to.equal('Ah', `autocompleteMode is ${autocompleteMode}`); - - await el.updateComplete; - expect(el.checkedIndex).to.equal(-1, `autocompleteMode is ${autocompleteMode}`); + if (autocompleteMode === 'none' || autocompleteMode === 'list') { + expect(el.modelValue).to.deep.equal( + { type: 'unparseable', viewValue: 'B' }, + `autocompleteMode is ${autocompleteMode}`, + ); + await el.updateComplete; + expect(el.checkedIndex).to.equal(-1, `autocompleteMode is ${autocompleteMode}`); + } else { + expect(el.modelValue).to.equal('Bb', `autocompleteMode is ${autocompleteMode}`); + expect(el.checkedIndex).to.equal(1, `autocompleteMode is ${autocompleteMode}`); + } } - - el.autocomplete = 'none'; - await performChecks('none'); - - el.autocomplete = 'list'; - await performChecks('list'); }); it('works with Required validator', async () => { @@ -992,6 +993,27 @@ describe('lion-combobox', () => { expect(el.modelValue).to.eql(['Art']); }); + it('allows prefilling the combobox', async () => { + const autocompleteValues = ['inline', 'none', 'both', 'list']; + + for (const autocompleteValue of autocompleteValues) { + const el = /** @type {LionCombobox} */ ( + await fixture(html` + + Artichoke + Chard + Chicory + Victoria Plum + + `) + ); + + expect(el.modelValue).to.equal('Chard'); + // @ts-expect-error + expect(el._inputNode.value).to.equal('Chard'); + } + }); + it('submits form on [Enter] when listbox is closed', async () => { const submitSpy = sinon.spy(e => e.preventDefault()); const el = /** @type {HTMLFormElement} */ ( @@ -2318,8 +2340,7 @@ describe('lion-combobox', () => { `) ); - // This ensures autocomplete would be off originally - el.autocomplete = 'list'; + await mimicUserTypingAdvanced(el, ['v', 'i']); // so we have options ['Victoria Plum'] await el.updateComplete; expect(el.checkedIndex).to.equal(3); @@ -2445,24 +2466,27 @@ describe('lion-combobox', () => { expect(_inputNode.value).to.equal(''); - el.setCheckedIndex(-1); - el.autocomplete = 'none'; - el.setCheckedIndex(0); - expect(_inputNode.value).to.equal(''); - el.setCheckedIndex(-1); el.autocomplete = 'list'; - el.setCheckedIndex(0); - expect(_inputNode.value).to.equal(''); + await mimicUserTypingAdvanced(el, ['a', 'r', 't']); + expect(_inputNode.value).to.equal('art'); el.setCheckedIndex(-1); + el.value = ''; + el.autocomplete = 'none'; + await mimicUserTypingAdvanced(el, ['a', 'r', 't']); + expect(_inputNode.value).to.equal('art'); + + el.setCheckedIndex(-1); + el.value = ''; el.autocomplete = 'inline'; - el.setCheckedIndex(0); + await mimicUserTypingAdvanced(el, ['a', 'r', 't']); expect(_inputNode.value).to.equal('Artichoke'); el.setCheckedIndex(-1); + el.value = ''; el.autocomplete = 'both'; - el.setCheckedIndex(0); + await mimicUserTypingAdvanced(el, ['a', 'r', 't']); expect(_inputNode.value).to.equal('Artichoke'); }); @@ -2482,30 +2506,28 @@ describe('lion-combobox', () => { expect(_inputNode.value).to.eql(''); el.setCheckedIndex(-1); - el.autocomplete = 'none'; - el.setCheckedIndex([0]); - el.setCheckedIndex([1]); - expect(_inputNode.value).to.equal(''); - el.setCheckedIndex(-1); el.autocomplete = 'list'; - el.setCheckedIndex([0]); - el.setCheckedIndex([1]); - expect(_inputNode.value).to.equal(''); + await mimicUserTypingAdvanced(el, ['a', 'r', 't']); + expect(_inputNode.value).to.equal('art'); el.setCheckedIndex(-1); + el.value = ''; + el.autocomplete = 'none'; + await mimicUserTypingAdvanced(el, ['a', 'r', 't']); + expect(_inputNode.value).to.equal('art'); + + el.setCheckedIndex(-1); + el.value = ''; el.autocomplete = 'inline'; - el.setCheckedIndex([0]); + await mimicUserTypingAdvanced(el, ['a', 'r', 't']); expect(_inputNode.value).to.equal('Artichoke'); - el.setCheckedIndex([1]); - expect(_inputNode.value).to.equal('Chard'); el.setCheckedIndex(-1); + el.value = ''; el.autocomplete = 'both'; - el.setCheckedIndex([0]); + await mimicUserTypingAdvanced(el, ['a', 'r', 't']); expect(_inputNode.value).to.equal('Artichoke'); - el.setCheckedIndex([1]); - expect(_inputNode.value).to.equal('Chard'); }); describe('Subclassers', () => { @@ -2754,12 +2776,6 @@ describe('lion-combobox', () => { async function performChecks(autocompleteMode) { await el.updateComplete; - el.formElements[0].click(); - - // FIXME: fix properly for Webkit - // expect(_inputNode.value).to.equal('Aha', autocompleteMode); - expect(el.checkedIndex).to.equal(0, autocompleteMode); - await mimicUserTypingAdvanced(el, ['A', 'r', 't', 'i']); await el.updateComplete; expect(_inputNode.value).to.equal('Arti', `autocompleteMode is ${autocompleteMode}`);