Skip to content

Commit

Permalink
fix: force scroller update after revealing a date (#8217) (#8219)
Browse files Browse the repository at this point in the history
Co-authored-by: Sergey Vinogradov <mr.vursen@gmail.com>
  • Loading branch information
vaadin-bot and vursen authored Nov 22, 2024
1 parent 3f8e157 commit b3d57b7
Show file tree
Hide file tree
Showing 14 changed files with 87 additions and 66 deletions.
4 changes: 2 additions & 2 deletions integration/tests/context-menu-date-picker.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import '@vaadin/context-menu';
import '@vaadin/date-picker';
import { isTouch } from '@vaadin/component-base/src/browser-utils';
import { getMenuItems, openMenu } from '@vaadin/context-menu/test/helpers';
import { getFocusedCell, open } from '@vaadin/date-picker/test/helpers';
import { getFocusableCell, open } from '@vaadin/date-picker/test/helpers';

describe('date picker in context menu', () => {
let menu;
Expand All @@ -27,7 +27,7 @@ describe('date picker in context menu', () => {
const datePicker = getMenuItems(menu)[0];
await open(datePicker);

const date = getFocusedCell(datePicker._overlayContent);
const date = getFocusableCell(datePicker);
date.click();
await nextFrame();

Expand Down
4 changes: 2 additions & 2 deletions integration/tests/dialog-date-picker.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe('date-picker in dialog', () => {
await sendKeys({ press: 'Tab' });

await nextRender();
await waitForScrollToFinish(overlayContent);
await waitForScrollToFinish(datePicker);

// Focus the Today button
await sendKeys({ press: 'Tab' });
Expand All @@ -63,7 +63,7 @@ describe('date-picker in dialog', () => {
await sendKeys({ press: 'Tab' });

await nextRender();
await waitForScrollToFinish(overlayContent);
await waitForScrollToFinish(datePicker);

const spy = sinon.spy(datePicker.inputElement, 'focus');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,7 @@ export const DatePickerOverlayContentMixin = (superClass) =>

if (!animate) {
this._monthScroller.position = targetPosition;
this._monthScroller.forceUpdate();
this._targetPosition = undefined;
this._repositionYearScroller();
this.__tryFocusDate();
Expand Down Expand Up @@ -626,6 +627,7 @@ export const DatePickerOverlayContentMixin = (superClass) =>
);

this._monthScroller.position = this._targetPosition;
this._monthScroller.forceUpdate();
this._targetPosition = undefined;

revealResolve();
Expand Down
7 changes: 7 additions & 0 deletions packages/date-picker/src/vaadin-infinite-scroller.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Copyright (c) 2016 - 2024 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
*/
import { flush } from '@polymer/polymer/lib/utils/flush.js';
import { timeOut } from '@vaadin/component-base/src/async.js';
import { Debouncer } from '@vaadin/component-base/src/debounce.js';
import { generateUniqueId } from '@vaadin/component-base/src/unique-id-utils.js';
Expand Down Expand Up @@ -205,11 +206,17 @@ export class InfiniteScroller extends HTMLElement {
* waiting for the debouncer to resolve.
*/
forceUpdate() {
if (this._debouncerScrollFinish) {
this._debouncerScrollFinish.flush();
}

if (this._debouncerUpdateClones) {
this._buffers[0].updated = this._buffers[1].updated = false;
this._updateClones();
this._debouncerUpdateClones.cancel();
}

flush();
}

/**
Expand Down
5 changes: 2 additions & 3 deletions packages/date-picker/test/custom-input.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,8 @@ describe('custom input', () => {
});

it('should propagate theme attribute to month calendar', async () => {
const overlayContent = datePicker._overlayContent;
await waitForScrollToFinish(overlayContent);
const monthCalendar = overlayContent.querySelector('vaadin-month-calendar');
await waitForScrollToFinish(datePicker);
const monthCalendar = datePicker._overlayContent.querySelector('vaadin-month-calendar');
expect(monthCalendar.getAttribute('theme')).to.equal('foo');
});
});
Expand Down
4 changes: 2 additions & 2 deletions packages/date-picker/test/dropdown.common.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
} from '@vaadin/testing-helpers';
import { sendKeys } from '@web/test-runner-commands';
import sinon from 'sinon';
import { getFocusedCell, monthsEqual, open, waitForOverlayRender } from './helpers.js';
import { getFocusableCell, monthsEqual, open, waitForOverlayRender } from './helpers.js';

describe('dropdown', () => {
let datePicker, input, overlay;
Expand Down Expand Up @@ -235,7 +235,7 @@ describe('dropdown', () => {

describe('date tap', () => {
function dateTap() {
const date = getFocusedCell(datePicker._overlayContent);
const date = getFocusableCell(datePicker);
mousedown(date);
date.focus();
date.click();
Expand Down
6 changes: 3 additions & 3 deletions packages/date-picker/test/events.common.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ describe('events', () => {

it('should not be fired on programmatic value change when having user input', async () => {
await sendKeys({ type: '1/2/2000' });
await waitForScrollToFinish(datePicker._overlayContent);
await waitForScrollToFinish(datePicker);
datePicker.value = '2000-01-01';
await close(datePicker);
expect(changeSpy.called).to.be.false;
Expand All @@ -52,7 +52,7 @@ describe('events', () => {
describe('with user input', () => {
beforeEach(async () => {
await sendKeys({ type: '1/1/2022' });
await waitForScrollToFinish(datePicker._overlayContent);
await waitForScrollToFinish(datePicker);
hasInputValueChangedSpy.resetHistory();
});

Expand Down Expand Up @@ -86,7 +86,7 @@ describe('events', () => {
describe('with value', () => {
beforeEach(async () => {
await sendKeys({ type: '1/1/2022' });
await waitForScrollToFinish(datePicker._overlayContent);
await waitForScrollToFinish(datePicker);
await sendKeys({ press: 'Enter' });
valueChangedSpy.resetHistory();
hasInputValueChangedSpy.resetHistory();
Expand Down
6 changes: 3 additions & 3 deletions packages/date-picker/test/fullscreen.common.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { expect } from '@esm-bundle/chai';
import { aTimeout, fixtureSync, nextRender, nextUpdate, outsideClick, tabKeyDown, tap } from '@vaadin/testing-helpers';
import { sendKeys, setViewport } from '@web/test-runner-commands';
import sinon from 'sinon';
import { getFocusedCell, open, touchTap, waitForOverlayRender } from './helpers.js';
import { getFocusableCell, open, touchTap, waitForOverlayRender } from './helpers.js';

describe('fullscreen mode', () => {
let datePicker, input, overlay, width, height;
Expand Down Expand Up @@ -74,7 +74,7 @@ describe('fullscreen mode', () => {

it('should focus date element when opening overlay', async () => {
await open(datePicker);
const cell = getFocusedCell(datePicker._overlayContent);
const cell = getFocusableCell(datePicker);
expect(cell).to.be.instanceOf(HTMLTableCellElement);
expect(cell.getAttribute('part')).to.include('today');
});
Expand Down Expand Up @@ -166,7 +166,7 @@ describe('fullscreen mode', () => {
});

it('should move focus to date cell button on Cancel button Tab', async () => {
const cell = getFocusedCell(overlayContent);
const cell = getFocusableCell(datePicker);
const spy = sinon.spy(cell, 'focus');

// Move focus to Cancel button
Expand Down
33 changes: 24 additions & 9 deletions packages/date-picker/test/helpers.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { fire, listenOnce, makeSoloTouchEvent, nextRender } from '@vaadin/testing-helpers';
import { flush } from '@polymer/polymer/lib/utils/flush.js';
import { afterNextRender } from '@polymer/polymer/lib/utils/render-status.js';
import { isElementFocused } from '@vaadin/a11y-base/src/focus-utils.js';

export function activateScroller(scroller) {
scroller.active = true;
Expand Down Expand Up @@ -108,24 +109,38 @@ export function getFirstVisibleItem(scroller, bufferOffset = 0) {
});
}

export function getFocusedMonth(overlayContent) {
const months = [...overlayContent.querySelectorAll('vaadin-month-calendar')];
return months.find((month) => {
return !!month.shadowRoot.querySelector('[part~="focused"]');
/**
* @param {HTMLElement} root vaadin-date-picker or vaadin-date-picker-overlay-content
*/
export function getFocusableCell(root) {
const overlayContent = root._overlayContent ?? root;
const focusableMonth = [...overlayContent.querySelectorAll('vaadin-month-calendar')].find((month) => {
return !!month.shadowRoot.querySelector('[tabindex="0"]');
});

if (focusableMonth) {
return focusableMonth.shadowRoot.querySelector('[tabindex="0"]');
}
}

export function getFocusedCell(overlayContent) {
const focusedMonth = getFocusedMonth(overlayContent);
return focusedMonth.shadowRoot.querySelector('[part~="focused"]');
/**
* @param {HTMLElement} root vaadin-date-picker or vaadin-date-picker-overlay-content
*/
export function getFocusedCell(root) {
const focusableCell = getFocusableCell(root);
if (focusableCell && isElementFocused(focusableCell)) {
return focusableCell;
}
}

/**
* Waits for the scroll to finish in the date-picker overlay content.
*
* @param {HTMLElement} overlayContent
* @param {HTMLElement} root vaadin-date-picker or vaadin-date-picker-overlay-content
*/
export async function waitForScrollToFinish(overlayContent) {
export async function waitForScrollToFinish(root) {
const overlayContent = root._overlayContent ?? root;

if (overlayContent._revealPromise) {
// The overlay content is scrolling.
await overlayContent._revealPromise;
Expand Down
13 changes: 6 additions & 7 deletions packages/date-picker/test/keyboard-input.common.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,7 @@ describe('keyboard', () => {
// FIXME: flaky test often failing locally due to scroll animation
it.skip('should display focused date while overlay focused', async () => {
await sendKeys({ type: '1/2/2000' });
const content = datePicker._overlayContent;
await waitForScrollToFinish(content);
await waitForScrollToFinish(datePicker);

// Move focus to the calendar
await sendKeys({ press: 'Tab' });
Expand Down Expand Up @@ -212,7 +211,7 @@ describe('keyboard', () => {
// Move focus to the calendar
await sendKeys({ press: 'Tab' });
await waitForOverlayRender();
const cell = getFocusedCell(overlayContent);
const cell = getFocusedCell(datePicker);
const spy = sinon.spy(input, 'focus');
tap(cell);
expect(spy.calledOnce).to.be.true;
Expand Down Expand Up @@ -284,9 +283,9 @@ describe('keyboard', () => {
// Move focus to the calendar
await sendKeys({ press: 'Tab' });

await waitForScrollToFinish(overlayContent);
await waitForScrollToFinish(datePicker);

const cell = getFocusedCell(overlayContent);
const cell = getFocusedCell(datePicker);
expect(cell).to.be.instanceOf(HTMLTableCellElement);
expect(cell.getAttribute('part')).to.contain('today');
});
Expand All @@ -300,9 +299,9 @@ describe('keyboard', () => {
await sendKeys({ press: 'Tab' });
await sendKeys({ up: 'Shift' });

await waitForScrollToFinish(overlayContent);
await waitForScrollToFinish(datePicker);

const cell = getFocusedCell(overlayContent);
const cell = getFocusedCell(datePicker);
expect(cell).to.be.instanceOf(HTMLTableCellElement);
expect(cell.getAttribute('part')).to.contain('today');
});
Expand Down
38 changes: 19 additions & 19 deletions packages/date-picker/test/keyboard-navigation.common.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ describe('keyboard navigation', () => {
// Move focus to the calendar
await sendKeys({ press: 'Tab' });

const cell = getFocusedCell(datePicker._overlayContent);
const cell = getFocusedCell(datePicker);
expect(cell.date).to.eql(new Date(today.getFullYear(), today.getMonth(), today.getDate()));
});

Expand All @@ -47,7 +47,7 @@ describe('keyboard navigation', () => {
// Move focus to the calendar
await sendKeys({ press: 'Tab' });

const cell = getFocusedCell(datePicker._overlayContent);
const cell = getFocusedCell(datePicker);
expect(cell.date).to.eql(new Date(today.getFullYear(), today.getMonth(), today.getDate()));
});
});
Expand All @@ -66,7 +66,7 @@ describe('keyboard navigation', () => {
// Move focus to the calendar
await sendKeys({ press: 'Tab' });

const cell = getFocusedCell(datePicker._overlayContent);
const cell = getFocusedCell(datePicker);
expect(cell.date).to.eql(new Date(2001, 0, 1));
});

Expand Down Expand Up @@ -101,7 +101,7 @@ describe('keyboard navigation', () => {
// Move focus to the calendar
await sendKeys({ press: 'Tab' });

const cell = getFocusedCell(datePicker._overlayContent);
const cell = getFocusedCell(datePicker);
expect(cell.date).to.eql(new Date(2001, 0, 1));
});

Expand All @@ -115,7 +115,7 @@ describe('keyboard navigation', () => {
// Move focus to the calendar
await sendKeys({ press: 'Tab' });

const cell = getFocusedCell(datePicker._overlayContent);
const cell = getFocusedCell(datePicker);
expect(cell.date).to.eql(new Date(2001, 0, 1));
});
});
Expand All @@ -142,20 +142,20 @@ describe('keyboard navigation', () => {

// Move focus inside the dropdown to the typed date.
await sendKeys({ press: 'ArrowDown' });
await waitForScrollToFinish(datePicker._overlayContent);
await waitForScrollToFinish(datePicker);

// Move focus to the previous week and it should instead move to the min date
await sendKeys({ press: 'ArrowUp' });
await waitForScrollToFinish(datePicker._overlayContent);
await waitForScrollToFinish(datePicker);

let cell = getFocusedCell(datePicker._overlayContent);
let cell = getFocusedCell(datePicker);
expect(cell.date).to.eql(new Date(2010, 0, 1));

// Attempt to move focus to the previous week and it should stay on the min date
await sendKeys({ press: 'ArrowUp' });
await waitForScrollToFinish(datePicker._overlayContent);
await waitForScrollToFinish(datePicker);

cell = getFocusedCell(datePicker._overlayContent);
cell = getFocusedCell(datePicker);
expect(cell.date).to.eql(new Date(2010, 0, 1));
});

Expand All @@ -164,20 +164,20 @@ describe('keyboard navigation', () => {

// Move focus inside the dropdown to the typed date.
await sendKeys({ press: 'ArrowDown' });
await waitForScrollToFinish(datePicker._overlayContent);
await waitForScrollToFinish(datePicker);

// Move focus to the next week and it should instead move to the max date
await sendKeys({ press: 'ArrowDown' });
await waitForScrollToFinish(datePicker._overlayContent);
await waitForScrollToFinish(datePicker);

let cell = getFocusedCell(datePicker._overlayContent);
let cell = getFocusedCell(datePicker);
expect(cell.date).to.eql(new Date(2010, 0, 31));

// Attempt to move focus to the next week and it should stay on the max date
await sendKeys({ press: 'ArrowDown' });
await waitForScrollToFinish(datePicker._overlayContent);
await waitForScrollToFinish(datePicker);

cell = getFocusedCell(datePicker._overlayContent);
cell = getFocusedCell(datePicker);
expect(cell.date).to.eql(new Date(2010, 0, 31));
});

Expand All @@ -186,13 +186,13 @@ describe('keyboard navigation', () => {

// Move focus inside the dropdown to the typed date.
await sendKeys({ press: 'ArrowDown' });
await waitForScrollToFinish(datePicker._overlayContent);
await waitForScrollToFinish(datePicker);

// Move focus to a disabled date
await sendKeys({ press: 'ArrowRight' });
await waitForScrollToFinish(datePicker._overlayContent);
await waitForScrollToFinish(datePicker);

const cell = getFocusedCell(datePicker._overlayContent);
const cell = getFocusedCell(datePicker);
expect(cell.date).to.eql(new Date(2010, 0, 29));
});

Expand All @@ -202,7 +202,7 @@ describe('keyboard navigation', () => {
// Move focus to a disabled date
await sendKeys({ press: 'ArrowDown' });
await sendKeys({ press: 'ArrowRight' });
await waitForScrollToFinish(datePicker._overlayContent);
await waitForScrollToFinish(datePicker);

await sendKeys({ press: 'Enter' });

Expand Down
5 changes: 2 additions & 3 deletions packages/date-picker/test/theme-propagation.common.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,8 @@ describe('theme attribute', () => {
});

it('should propagate theme attribute to month calendar', async () => {
const overlayContent = datePicker._overlayContent;
await waitForScrollToFinish(overlayContent);
const monthCalendar = overlayContent.querySelector('vaadin-month-calendar');
await waitForScrollToFinish(datePicker);
const monthCalendar = datePicker._overlayContent.querySelector('vaadin-month-calendar');
expect(monthCalendar.getAttribute('theme')).to.equal('foo');
});
});
Expand Down
Loading

0 comments on commit b3d57b7

Please sign in to comment.