From 6f298edf7f6772cec38332009bcc5b610c049433 Mon Sep 17 00:00:00 2001 From: web-padawan Date: Fri, 14 Aug 2026 10:49:32 +0300 Subject: [PATCH] fix: do not validate when date-picker blurs input internally In fullscreen mode text input is disabled, so focusing the input blurs it again right away to hide the virtual keyboard. That blur is an internal detail, but the blur handler could not tell it apart from a real one and ran the full "user left the field" logic. Tapping a required date-picker therefore marked it invalid while the calendar was still opening, before the user could pick anything. The value commit is skipped along with the validation: in this mode the input cannot be typed into, so there is never a typed value to commit. Fixes #12432 Co-Authored-By: Claude Opus 5 --- .../src/vaadin-date-picker-mixin.js | 7 +++ packages/date-picker/test/fullscreen.test.js | 56 ++++++++++++++++++- 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/packages/date-picker/src/vaadin-date-picker-mixin.js b/packages/date-picker/src/vaadin-date-picker-mixin.js index 83265a1999b..f6a50128ac6 100644 --- a/packages/date-picker/src/vaadin-date-picker-mixin.js +++ b/packages/date-picker/src/vaadin-date-picker-mixin.js @@ -459,7 +459,10 @@ export const DatePickerMixin = (subclass) => super._onFocus(event); if (this._noInput && !isKeyboardActive()) { + // Blur to hide the virtual keyboard, but do not validate. + this.__ignoreInternalBlur = true; event.target.blur(); + this.__ignoreInternalBlur = false; } } @@ -470,6 +473,10 @@ export const DatePickerMixin = (subclass) => _onBlur(event) { super._onBlur(event); + if (this.__ignoreInternalBlur) { + return; + } + if (!this.opened) { this.__commitParsedOrFocusedDate(); diff --git a/packages/date-picker/test/fullscreen.test.js b/packages/date-picker/test/fullscreen.test.js index 08f144da95c..707045c1aac 100644 --- a/packages/date-picker/test/fullscreen.test.js +++ b/packages/date-picker/test/fullscreen.test.js @@ -1,6 +1,6 @@ import { expect } from '@vaadin/chai-plugins'; import { sendKeys, setViewport } from '@vaadin/test-runner-commands'; -import { aTimeout, fixtureSync, nextRender, outsideClick, tabKeyDown, tap } from '@vaadin/testing-helpers'; +import { aTimeout, fixtureSync, nextRender, nextUpdate, outsideClick, tabKeyDown, tap } from '@vaadin/testing-helpers'; import sinon from 'sinon'; import '../src/vaadin-date-picker.js'; import { getFocusableCell, open, touchTap, untilOverlayRendered } from './helpers.js'; @@ -156,6 +156,60 @@ describe('fullscreen mode', () => { }); }); + describe('validation', () => { + let validateSpy; + + beforeEach(async () => { + datePicker.required = true; + await nextUpdate(datePicker); + validateSpy = sinon.spy(datePicker, 'validate'); + }); + + it('should not validate when focusing the input', () => { + input.focus(); + expect(validateSpy.called).to.be.false; + expect(datePicker.invalid).to.be.false; + }); + + it('should not validate when opening overlay on input tap', async () => { + input.focus(); + tap(input); + await untilOverlayRendered(datePicker); + expect(validateSpy.called).to.be.false; + expect(datePicker.invalid).to.be.false; + }); + + it('should validate when closing overlay on outside click', async () => { + await open(datePicker); + validateSpy.resetHistory(); + + outsideClick(); + await nextRender(); + + expect(validateSpy.called).to.be.true; + expect(datePicker.invalid).to.be.true; + }); + + it('should validate on blur after the input has been blurred internally', async () => { + input.focus(); + tap(input); + await untilOverlayRendered(datePicker); + datePicker.close(); + await nextRender(); + + // Make the input focusable + datePicker.autoOpenDisabled = true; + await nextUpdate(datePicker); + validateSpy.resetHistory(); + + input.focus(); + input.blur(); + + expect(validateSpy.called).to.be.true; + expect(datePicker.invalid).to.be.true; + }); + }); + describe('buttons', () => { let overlayContent;