From a3315cb7be3ed5a96d7c0f3b612b444b9926030b Mon Sep 17 00:00:00 2001 From: dankeboy36 Date: Tue, 23 Sep 2025 12:59:24 +0200 Subject: [PATCH] fix(textfield): do not bind .value for file inputs The native file input cannot accept non-empty values programmatically. Skip mirroring and binding .value for type="file". Only propagating FileList to form internals. This prevents InvalidStateError and keeps file selections intact across renders. Closes #542 Signed-off-by: dankeboy36 --- src/vscode-textfield/vscode-textfield.test.ts | 26 +++++ src/vscode-textfield/vscode-textfield.ts | 95 ++++++++++++------- 2 files changed, 89 insertions(+), 32 deletions(-) diff --git a/src/vscode-textfield/vscode-textfield.test.ts b/src/vscode-textfield/vscode-textfield.test.ts index 7d1812920..9d7571540 100644 --- a/src/vscode-textfield/vscode-textfield.test.ts +++ b/src/vscode-textfield/vscode-textfield.test.ts @@ -277,4 +277,30 @@ describe('vscode-textfield', () => { expect(el.checkValidity()).to.eq(false); }); + + it('mirrors a non-empty value into a file input and triggers unhandledrejection (current bug)', async () => { + const el = await fixture( + html`` + ); + + const rejection = new Promise((resolve) => { + const handler = (ev: PromiseRejectionEvent) => { + window.removeEventListener('unhandledrejection', handler); + resolve(ev.reason); + }; + window.addEventListener('unhandledrejection', handler); + }); + + // mimic the behavior of a file input + el['_value'] = 'C:\\fakepath\\file.txt'; + + el.requestUpdate(); + + const result = await Promise.race([ + rejection, + el.updateComplete.then(() => 'update-completed'), + ]); + + expect(result).to.equal('update-completed'); + }); }); diff --git a/src/vscode-textfield/vscode-textfield.ts b/src/vscode-textfield/vscode-textfield.ts index 70b11d167..8bbb58494 100644 --- a/src/vscode-textfield/vscode-textfield.ts +++ b/src/vscode-textfield/vscode-textfield.ts @@ -303,15 +303,17 @@ export class VscodeTextfield private _internals: ElementInternals; private _dataChanged() { - this._value = this._inputEl.value; - - if (this.type === 'file' && this._inputEl.files) { - for (const f of this._inputEl.files) { - this._internals.setFormValue(f); + if (this.type === 'file') { + if (this._inputEl.files) { + for (const f of this._inputEl.files) { + this._internals.setFormValue(f); + } } - } else { - this._internals.setFormValue(this._inputEl.value); + return; } + + this._value = this._inputEl.value; + this._internals.setFormValue(this._inputEl.value); } private _setValidityFromInput() { @@ -354,31 +356,60 @@ export class VscodeTextfield return html`
- + ${this._type === 'file' + ? html` + + ` + : html` + + `}
`;