diff --git a/packages/elements/src/number-field/__test__/number-field.step.test.js b/packages/elements/src/number-field/__test__/number-field.step.test.js index 9249552db8..43a9e4b950 100644 --- a/packages/elements/src/number-field/__test__/number-field.step.test.js +++ b/packages/elements/src/number-field/__test__/number-field.step.test.js @@ -1,7 +1,7 @@ import '@refinitiv-ui/elements/number-field'; import '@refinitiv-ui/elemental-theme/light/ef-number-field'; -import { elementUpdated, expect, fixture } from '@refinitiv-ui/test-helpers'; +import { aTimeout, elementUpdated, expect, fixture, oneEvent } from '@refinitiv-ui/test-helpers'; const UP = 1; const DOWN = -1; @@ -220,4 +220,39 @@ describe('number-field/Step', function () { await expectValues(el, [-1, -2, -3, -4, -5], UP, -1.5); }); }); + + describe('Long press spinner', function () { + const dispatchLongTapEvent = async (el, wait = 1000) => { + setTimeout(() => + el.dispatchEvent( + new Event('tapstart', { + bubbles: true + }) + ) + ); + await oneEvent(el, 'tapstart'); + if (wait) { + await aTimeout(wait); + } + setTimeout(() => + el.dispatchEvent( + new Event('tapend', { + bubbles: true + }) + ) + ); + await oneEvent(el, 'tapend'); + }; + + it('Should increases value gradually on long press', async function () { + const el = await fixture(''); + await dispatchLongTapEvent(el.spinnerUpEl); + expect(Number(el.value)).to.greaterThan(1); + }); + it('Should decreases value gradually on long press', async function () { + const el = await fixture(''); + await dispatchLongTapEvent(el.spinnerDownEl); + expect(Number(el.value)).to.lessThan(-1); + }); + }); }); diff --git a/packages/elements/src/number-field/__test__/number-field.test.js b/packages/elements/src/number-field/__test__/number-field.test.js index a2d3656415..eb55cc5be1 100644 --- a/packages/elements/src/number-field/__test__/number-field.test.js +++ b/packages/elements/src/number-field/__test__/number-field.test.js @@ -3,9 +3,9 @@ import '@refinitiv-ui/elements/number-field'; import '@refinitiv-ui/elemental-theme/light/ef-number-field'; import { elementUpdated, expect, fixture, isIE, keyboardEvent, oneEvent } from '@refinitiv-ui/test-helpers'; -const dispatchTapEvent = (el) => { +const dispatchTapStartEvent = (el) => { el.dispatchEvent( - new Event('tap', { + new Event('tapstart', { bubbles: true }) ); @@ -137,19 +137,16 @@ describe('number-field/NumberField', function () { expect(el.value).to.equal('100'); }); it("Should fire input event when step up/down value by user's interactions", async function () { - const spinnerUp = el.shadowRoot.querySelector('[part=spinner-up]'); - const spinnerDown = el.shadowRoot.querySelector('[part=spinner-down]'); - let eventFiredCounter = 0; el.addEventListener('input', () => { eventFiredCounter += 1; }); - setTimeout(() => spinnerUp.click()); + setTimeout(() => dispatchTapStartEvent(el.spinnerUpEl)); await oneEvent(el, 'input'); expect(eventFiredCounter).to.equal(1); - setTimeout(() => spinnerDown.click()); + setTimeout(() => dispatchTapStartEvent(el.spinnerDownEl)); await oneEvent(el, 'input'); expect(eventFiredCounter).to.equal(2); }); @@ -199,29 +196,29 @@ describe('number-field/NumberField', function () { }); it('Should increase the value by 1', async function () { - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - await oneEvent(spinnerUpEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + await oneEvent(spinnerUpEl, 'tapstart'); expect(el.value).to.equal('1'); }); it('Should decrease the value by 1', async function () { - setTimeout(() => dispatchTapEvent(spinnerDownEl)); - await oneEvent(spinnerDownEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerDownEl)); + await oneEvent(spinnerDownEl, 'tapstart'); expect(el.value).to.equal('-1'); }); it('Should not increase the value when it is readonly', async function () { el.setAttribute('readonly', true); await elementUpdated(); - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - await oneEvent(spinnerUpEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + await oneEvent(spinnerUpEl, 'tapstart'); expect(el.value).to.equal(''); }); it('Should not decrease the value when it is readonly', async function () { el.setAttribute('readonly', true); await elementUpdated(); - setTimeout(() => dispatchTapEvent(spinnerDownEl)); - await oneEvent(spinnerDownEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerDownEl)); + await oneEvent(spinnerDownEl, 'tapstart'); expect(el.value).to.equal(''); }); it('Should not increase the value when it is disabled', async function () { @@ -230,8 +227,8 @@ describe('number-field/NumberField', function () { el.setAttribute('disabled', true); await elementUpdated(); - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - await oneEvent(spinnerUpEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + await oneEvent(spinnerUpEl, 'tapstart'); expect(el.value).to.equal(''); } }); @@ -241,40 +238,40 @@ describe('number-field/NumberField', function () { el.setAttribute('disabled', true); await elementUpdated(); - setTimeout(() => dispatchTapEvent(spinnerDownEl)); - await oneEvent(spinnerDownEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerDownEl)); + await oneEvent(spinnerDownEl, 'tapstart'); expect(el.value).to.equal(''); } }); it('Should increase the value by 0.01', async function () { el.setAttribute('step', '0.01'); - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - await oneEvent(spinnerUpEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + await oneEvent(spinnerUpEl, 'tapstart'); expect(el.value).to.equal('0.01'); }); it('Should decrease the value by 0.01', async function () { el.setAttribute('step', '0.01'); - setTimeout(() => dispatchTapEvent(spinnerDownEl)); - await oneEvent(spinnerDownEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerDownEl)); + await oneEvent(spinnerDownEl, 'tapstart'); expect(el.value).to.equal('-0.01'); }); it('Should increase the value by 10', async function () { el.setAttribute('step', 10); - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - await oneEvent(spinnerUpEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + await oneEvent(spinnerUpEl, 'tapstart'); expect(el.value).to.equal('10'); }); it('Should decrease the value by 10', async function () { el.setAttribute('step', 10); - setTimeout(() => dispatchTapEvent(spinnerDownEl)); - await oneEvent(spinnerDownEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerDownEl)); + await oneEvent(spinnerDownEl, 'tapstart'); expect(el.value).to.equal('-10'); }); @@ -282,8 +279,8 @@ describe('number-field/NumberField', function () { it('Should round the value up (ceil) when value is decimal, but step is a whole number when spinner up is clicked', async function () { el.value = '3.3'; - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - await oneEvent(spinnerUpEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + await oneEvent(spinnerUpEl, 'tapstart'); expect(el.value).to.equal('4'); }); @@ -291,8 +288,8 @@ describe('number-field/NumberField', function () { it('Should round the value down (floor) when value is decimal, but step is a whole number when spinner down is clicked', async function () { el.value = '5.5'; - setTimeout(() => dispatchTapEvent(spinnerDownEl)); - await oneEvent(spinnerDownEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerDownEl)); + await oneEvent(spinnerDownEl, 'tapstart'); expect(el.value).to.equal('5'); }); @@ -305,12 +302,12 @@ describe('number-field/NumberField', function () { await elementUpdated(el); - dispatchTapEvent(spinnerUpEl); + dispatchTapStartEvent(spinnerUpEl); await elementUpdated(el); expect(el.value).to.equal('0', 'value should be incremented, when it is less then zero'); - dispatchTapEvent(spinnerUpEl); + dispatchTapStartEvent(spinnerUpEl); await elementUpdated(el); expect(el.value).to.equal('0', 'value should not be greater then zero'); @@ -324,12 +321,12 @@ describe('number-field/NumberField', function () { await elementUpdated(el); - dispatchTapEvent(spinnerDownEl); + dispatchTapStartEvent(spinnerDownEl); await elementUpdated(el); expect(el.value).to.equal('0', 'value should be decremented, when it is grater then zero'); - dispatchTapEvent(spinnerDownEl); + dispatchTapStartEvent(spinnerDownEl); await elementUpdated(el); expect(el.value).to.equal('0', 'value should not be less then zero'); @@ -343,8 +340,8 @@ describe('number-field/NumberField', function () { el.addEventListener('value-changed', () => { valueChangedCount += 1; }); - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - await oneEvent(spinnerUpEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + await oneEvent(spinnerUpEl, 'tapstart'); await elementUpdated(el); expect(el.value).to.equal('1'); expect(upClickedCount).to.equal(1); @@ -359,8 +356,8 @@ describe('number-field/NumberField', function () { el.addEventListener('value-changed', () => { valueChangedCount += 1; }); - setTimeout(() => dispatchTapEvent(spinnerDownEl)); - await oneEvent(spinnerDownEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerDownEl)); + await oneEvent(spinnerDownEl, 'tapstart'); await elementUpdated(el); expect(el.value).to.equal('-1'); expect(downClickedCount).to.equal(1); @@ -375,8 +372,8 @@ describe('number-field/NumberField', function () { el.addEventListener('value-changed', () => { valueChangedCount += 1; }); - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - await oneEvent(spinnerUpEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + await oneEvent(spinnerUpEl, 'tapstart'); await elementUpdated(el); expect(el.value).to.equal(value, 'Should not update value if step-up does prevent default'); expect(valueChangedCount).to.equal(0, 'Should not call value-changed if step-up does prevent default'); @@ -390,8 +387,8 @@ describe('number-field/NumberField', function () { el.addEventListener('value-changed', () => { valueChangedCount += 1; }); - setTimeout(() => dispatchTapEvent(spinnerDownEl)); - await oneEvent(spinnerDownEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerDownEl)); + await oneEvent(spinnerDownEl, 'tapstart'); await elementUpdated(el); expect(el.value).to.equal(value, 'Should not update value if step-down does prevent default'); expect(valueChangedCount).to.equal( @@ -483,21 +480,21 @@ describe('number-field/NumberField', function () { }); it('Should prevent the spinner from updating value to more than Max', async function () { - setTimeout(() => dispatchTapEvent(spinnerUpEl)); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); - await oneEvent(spinnerUpEl, 'tap'); + await oneEvent(spinnerUpEl, 'tapstart'); - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - await oneEvent(spinnerUpEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + await oneEvent(spinnerUpEl, 'tapstart'); expect(el.value).to.equal('10'); }); it('Should prevent the spinner from updating value to less than Min', async function () { - setTimeout(() => dispatchTapEvent(spinnerDownEl)); - setTimeout(() => dispatchTapEvent(spinnerDownEl)); + setTimeout(() => dispatchTapStartEvent(spinnerDownEl)); + setTimeout(() => dispatchTapStartEvent(spinnerDownEl)); - await oneEvent(spinnerDownEl, 'tap'); - await oneEvent(spinnerDownEl, 'tap'); + await oneEvent(spinnerDownEl, 'tapstart'); + await oneEvent(spinnerDownEl, 'tapstart'); expect(el.value).to.equal('-5'); }); @@ -516,8 +513,8 @@ describe('number-field/NumberField', function () { el.reportValidity(); await elementUpdated(); - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - await oneEvent(spinnerUpEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + await oneEvent(spinnerUpEl, 'tapstart'); expect(el.error).to.equal(true); expect(el.value).to.equal('60'); @@ -530,8 +527,8 @@ describe('number-field/NumberField', function () { expect(el.error).to.equal(true); - setTimeout(() => dispatchTapEvent(spinnerDownEl)); - await oneEvent(spinnerDownEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerDownEl)); + await oneEvent(spinnerDownEl, 'tapstart'); expect(el.value).to.equal('15'); @@ -541,8 +538,8 @@ describe('number-field/NumberField', function () { await elementUpdated(); - setTimeout(() => dispatchTapEvent(spinnerDownEl)); - await oneEvent(spinnerDownEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerDownEl)); + await oneEvent(spinnerDownEl, 'tapstart'); expect(el.value).to.equal('2.5'); }); @@ -565,8 +562,8 @@ describe('number-field/NumberField', function () { expect(el.error).to.equal(true); - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - await oneEvent(spinnerUpEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + await oneEvent(spinnerUpEl, 'tapstart'); expect(el.value).to.equal('-5'); }); @@ -576,8 +573,8 @@ describe('number-field/NumberField', function () { await elementUpdated(); - setTimeout(() => dispatchTapEvent(spinnerDownEl)); - await oneEvent(spinnerDownEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerDownEl)); + await oneEvent(spinnerDownEl, 'tapstart'); expect(el.error).to.equal(true); expect(el.value).to.equal('-20'); @@ -596,11 +593,11 @@ describe('number-field/NumberField', function () { }); it('Should be able to step up value correctly', async function () { - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - setTimeout(() => dispatchTapEvent(spinnerUpEl)); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); - await oneEvent(spinnerUpEl, 'tap'); - await oneEvent(spinnerUpEl, 'tap'); + await oneEvent(spinnerUpEl, 'tapstart'); + await oneEvent(spinnerUpEl, 'tapstart'); expect(el.value).to.equal('4'); el.reportValidity(); @@ -650,8 +647,8 @@ describe('number-field/NumberField', function () { await elementUpdated(); - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - await oneEvent(spinnerUpEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + await oneEvent(spinnerUpEl, 'tapstart'); expect(el.value).to.equal('1'); expect(el.error).to.equal(false); @@ -661,10 +658,10 @@ describe('number-field/NumberField', function () { await elementUpdated(); - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - await oneEvent(spinnerUpEl, 'tap'); - await oneEvent(spinnerUpEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + await oneEvent(spinnerUpEl, 'tapstart'); + await oneEvent(spinnerUpEl, 'tapstart'); expect(el.value).to.equal('2'); expect(el.error).to.equal(false); @@ -675,8 +672,8 @@ describe('number-field/NumberField', function () { await elementUpdated(); - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - await oneEvent(spinnerUpEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + await oneEvent(spinnerUpEl, 'tapstart'); expect(el.value).to.equal('2'); expect(el.error).to.equal(false); @@ -687,8 +684,8 @@ describe('number-field/NumberField', function () { await elementUpdated(); - setTimeout(() => dispatchTapEvent(spinnerDownEl)); - await oneEvent(spinnerDownEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerDownEl)); + await oneEvent(spinnerDownEl, 'tapstart'); expect(el.value).to.equal('-2'); expect(el.error).to.equal(false); @@ -699,8 +696,8 @@ describe('number-field/NumberField', function () { await elementUpdated(); - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - await oneEvent(spinnerUpEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + await oneEvent(spinnerUpEl, 'tapstart'); expect(el.value).to.equal('2'); expect(el.error).to.equal(false); @@ -711,8 +708,8 @@ describe('number-field/NumberField', function () { await elementUpdated(); - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - await oneEvent(spinnerUpEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + await oneEvent(spinnerUpEl, 'tapstart'); expect(el.value).to.equal('1'); expect(el.error).to.equal(false); @@ -724,20 +721,20 @@ describe('number-field/NumberField', function () { await elementUpdated(); - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - await oneEvent(spinnerUpEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + await oneEvent(spinnerUpEl, 'tapstart'); expect(el.value).to.equal('1'); expect(el.error).to.equal(false); - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - await oneEvent(spinnerUpEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + await oneEvent(spinnerUpEl, 'tapstart'); expect(el.value).to.equal('3'); expect(el.error).to.equal(false); - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - await oneEvent(spinnerUpEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + await oneEvent(spinnerUpEl, 'tapstart'); expect(el.value).to.equal('5'); expect(el.error).to.equal(false); @@ -749,27 +746,27 @@ describe('number-field/NumberField', function () { await elementUpdated(); - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - await oneEvent(spinnerUpEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + await oneEvent(spinnerUpEl, 'tapstart'); expect(el.value).to.equal('1'); expect(el.error).to.equal(false); - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - await oneEvent(spinnerUpEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + await oneEvent(spinnerUpEl, 'tapstart'); expect(el.value).to.equal('4'); expect(el.error).to.equal(false); - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - await oneEvent(spinnerUpEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + await oneEvent(spinnerUpEl, 'tapstart'); expect(el.value).to.equal('7'); expect(el.error).to.equal(false); }); it('Should be able to step down value correctly', async function () { - setTimeout(() => dispatchTapEvent(spinnerDownEl)); - await oneEvent(spinnerDownEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerDownEl)); + await oneEvent(spinnerDownEl, 'tapstart'); expect(el.value).to.equal('-2'); }); @@ -779,8 +776,8 @@ describe('number-field/NumberField', function () { await elementUpdated(); - setTimeout(() => dispatchTapEvent(spinnerDownEl)); - await oneEvent(spinnerDownEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerDownEl)); + await oneEvent(spinnerDownEl, 'tapstart'); expect(el.value).to.equal('-1'); expect(el.error).to.equal(false); @@ -791,8 +788,8 @@ describe('number-field/NumberField', function () { await elementUpdated(); - setTimeout(() => dispatchTapEvent(spinnerDownEl)); - await oneEvent(spinnerDownEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerDownEl)); + await oneEvent(spinnerDownEl, 'tapstart'); expect(el.value).to.equal('-2'); expect(el.error).to.equal(false); @@ -804,20 +801,20 @@ describe('number-field/NumberField', function () { await elementUpdated(); - setTimeout(() => dispatchTapEvent(spinnerDownEl)); - await oneEvent(spinnerDownEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerDownEl)); + await oneEvent(spinnerDownEl, 'tapstart'); expect(el.value).to.equal('-1'); expect(el.error).to.equal(false); - setTimeout(() => dispatchTapEvent(spinnerDownEl)); - await oneEvent(spinnerDownEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerDownEl)); + await oneEvent(spinnerDownEl, 'tapstart'); expect(el.value).to.equal('-3'); expect(el.error).to.equal(false); - setTimeout(() => dispatchTapEvent(spinnerDownEl)); - await oneEvent(spinnerDownEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerDownEl)); + await oneEvent(spinnerDownEl, 'tapstart'); expect(el.value).to.equal('-5'); expect(el.error).to.equal(false); @@ -829,20 +826,20 @@ describe('number-field/NumberField', function () { await elementUpdated(); - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - await oneEvent(spinnerUpEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + await oneEvent(spinnerUpEl, 'tapstart'); expect(el.value).to.equal('1'); expect(el.error).to.equal(false); - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - await oneEvent(spinnerUpEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + await oneEvent(spinnerUpEl, 'tapstart'); expect(el.value).to.equal('4'); expect(el.error).to.equal(false); - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - await oneEvent(spinnerUpEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + await oneEvent(spinnerUpEl, 'tapstart'); expect(el.value).to.equal('7'); expect(el.error).to.equal(false); @@ -852,13 +849,13 @@ describe('number-field/NumberField', function () { await elementUpdated(); - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - setTimeout(() => dispatchTapEvent(spinnerUpEl)); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); - await oneEvent(spinnerUpEl, 'tap'); - await oneEvent(spinnerUpEl, 'tap'); - await oneEvent(spinnerUpEl, 'tap'); + await oneEvent(spinnerUpEl, 'tapstart'); + await oneEvent(spinnerUpEl, 'tapstart'); + await oneEvent(spinnerUpEl, 'tapstart'); expect(el.value).to.equal('0.003'); }); @@ -867,11 +864,11 @@ describe('number-field/NumberField', function () { await elementUpdated(); - setTimeout(() => dispatchTapEvent(spinnerDownEl)); - setTimeout(() => dispatchTapEvent(spinnerDownEl)); + setTimeout(() => dispatchTapStartEvent(spinnerDownEl)); + setTimeout(() => dispatchTapStartEvent(spinnerDownEl)); - await oneEvent(spinnerDownEl, 'tap'); - await oneEvent(spinnerDownEl, 'tap'); + await oneEvent(spinnerDownEl, 'tapstart'); + await oneEvent(spinnerDownEl, 'tapstart'); expect(el.value).to.equal('-0.002'); }); @@ -882,8 +879,8 @@ describe('number-field/NumberField', function () { await elementUpdated(); - setTimeout(() => dispatchTapEvent(spinnerDownEl)); - await oneEvent(spinnerDownEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerDownEl)); + await oneEvent(spinnerDownEl, 'tapstart'); expect(el.value).to.equal('1'); }); @@ -894,8 +891,8 @@ describe('number-field/NumberField', function () { await elementUpdated(); - setTimeout(() => dispatchTapEvent(spinnerDownEl)); - await oneEvent(spinnerDownEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerDownEl)); + await oneEvent(spinnerDownEl, 'tapstart'); expect(el.value).to.equal('1'); }); @@ -906,13 +903,13 @@ describe('number-field/NumberField', function () { await elementUpdated(); - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - await oneEvent(spinnerUpEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + await oneEvent(spinnerUpEl, 'tapstart'); expect(el.value).to.equal('1.5'); - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - await oneEvent(spinnerUpEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + await oneEvent(spinnerUpEl, 'tapstart'); expect(el.value).to.equal('2.5'); }); @@ -923,10 +920,10 @@ describe('number-field/NumberField', function () { await elementUpdated(); - setTimeout(() => dispatchTapEvent(spinnerDownEl)); - setTimeout(() => dispatchTapEvent(spinnerDownEl)); + setTimeout(() => dispatchTapStartEvent(spinnerDownEl)); + setTimeout(() => dispatchTapStartEvent(spinnerDownEl)); - await oneEvent(spinnerDownEl, 'tap'); + await oneEvent(spinnerDownEl, 'tapstart'); expect(el.value).to.equal('1.5'); }); @@ -937,18 +934,18 @@ describe('number-field/NumberField', function () { await elementUpdated(); - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - await oneEvent(spinnerUpEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + await oneEvent(spinnerUpEl, 'tapstart'); expect(el.value).to.equal('1.5'); - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - await oneEvent(spinnerUpEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + await oneEvent(spinnerUpEl, 'tapstart'); expect(el.value).to.equal('2.5'); - setTimeout(() => dispatchTapEvent(spinnerDownEl)); - await oneEvent(spinnerDownEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerDownEl)); + await oneEvent(spinnerDownEl, 'tapstart'); expect(el.value).to.equal('1.5'); }); @@ -959,19 +956,19 @@ describe('number-field/NumberField', function () { el.setAttribute('value', '-1.86'); await elementUpdated(); - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - await oneEvent(spinnerUpEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + await oneEvent(spinnerUpEl, 'tapstart'); expect(el.value).to.equal( '-0.86', 'Value should be increase by 1 and decimal value should keep stay' ); - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - await oneEvent(spinnerUpEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + await oneEvent(spinnerUpEl, 'tapstart'); expect(el.value).to.equal('0.14', 'Value should be increase by 1 and decimal value should keep stay'); - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - await oneEvent(spinnerUpEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + await oneEvent(spinnerUpEl, 'tapstart'); expect(el.value).to.equal('1.14', 'Value should be increase by 1 and decimal value should keep stay'); }); it('Factor should be 1 when step down', async function () { @@ -979,19 +976,19 @@ describe('number-field/NumberField', function () { el.setAttribute('value', '1.86'); await elementUpdated(); - setTimeout(() => dispatchTapEvent(spinnerDownEl)); - await oneEvent(spinnerDownEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerDownEl)); + await oneEvent(spinnerDownEl, 'tapstart'); expect(el.value).to.equal('0.86', 'Value should be decrease by 1 and decimal value should keep stay'); - setTimeout(() => dispatchTapEvent(spinnerDownEl)); - await oneEvent(spinnerDownEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerDownEl)); + await oneEvent(spinnerDownEl, 'tapstart'); expect(el.value).to.equal( '-0.14', 'Value should be decrease by 1 and decimal value should keep stay' ); - setTimeout(() => dispatchTapEvent(spinnerDownEl)); - await oneEvent(spinnerDownEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerDownEl)); + await oneEvent(spinnerDownEl, 'tapstart'); expect(el.value).to.equal( '-1.14', 'Value should be decrease by 1 and decimal value should keep stay' @@ -1003,8 +1000,8 @@ describe('number-field/NumberField', function () { el.setAttribute('min', '1'); await elementUpdated(); - setTimeout(() => dispatchTapEvent(spinnerDownEl)); - await oneEvent(spinnerDownEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerDownEl)); + await oneEvent(spinnerDownEl, 'tapstart'); expect(el.value).to.equal( '1', 'Follow by native behavior that value should decrease when min is integer.' @@ -1016,8 +1013,8 @@ describe('number-field/NumberField', function () { el.setAttribute('min', '1.1'); await elementUpdated(); - setTimeout(() => dispatchTapEvent(spinnerDownEl)); - await oneEvent(spinnerDownEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerDownEl)); + await oneEvent(spinnerDownEl, 'tapstart'); expect(el.value).to.equal( '1.86', 'Follow by native behavior that value should decrease when min is decimal.' @@ -1029,8 +1026,8 @@ describe('number-field/NumberField', function () { el.setAttribute('max', '2'); await elementUpdated(); - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - await oneEvent(spinnerUpEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + await oneEvent(spinnerUpEl, 'tapstart'); expect(el.value).to.equal( '1.86', 'Follow by native behavior that value should increase when max is integer.' @@ -1042,8 +1039,8 @@ describe('number-field/NumberField', function () { el.setAttribute('max', '2.1'); await elementUpdated(); - setTimeout(() => dispatchTapEvent(spinnerUpEl)); - await oneEvent(spinnerUpEl, 'tap'); + setTimeout(() => dispatchTapStartEvent(spinnerUpEl)); + await oneEvent(spinnerUpEl, 'tapstart'); expect(el.value).to.equal( '1.86', 'Follow by native behavior that value should increase when max is integer.' diff --git a/packages/elements/src/number-field/index.ts b/packages/elements/src/number-field/index.ts index 4d3c136bf6..7d871af712 100644 --- a/packages/elements/src/number-field/index.ts +++ b/packages/elements/src/number-field/index.ts @@ -109,6 +109,16 @@ export class NumberField extends FormFieldElement { `; } + /** + * Time period (ms) before press repetition starts + */ + private repeatDelay = 300; + + /** + * Time period (ms) between each repeat + */ + private repeatRate = 50; + /** * Set spinner's visibility */ @@ -169,6 +179,27 @@ export class NumberField extends FormFieldElement { @query('[part=spinner-down]') private spinnerDownEl?: HTMLInputElement; + /** + * An object's returned from setTimeout to use with repeat delay. + */ + private repeatDelayTimer: NodeJS.Timeout | undefined; + + /** + * An object's returned from setInterval to use with repeat rate. + */ + private repeatRateTimer: NodeJS.Timeout | undefined; + + /** + * Called after the component is first rendered + * @param changedProperties Properties which have changed + * @returns {void} + */ + protected override firstUpdated(changedProperties: PropertyValues): void { + super.firstUpdated(changedProperties); + // To remove press repetition when tap event ends outside of the pressed button + document.addEventListener('tapend', this.clearTimer); + } + /** * Updates the element * @param changedProperties Properties that has changed @@ -334,13 +365,28 @@ export class NumberField extends FormFieldElement { } const target = event.target; - if (target === this.spinnerDownEl) { - this.onApplyStep(Direction.Down); - } else if (target === this.spinnerUpEl) { - this.onApplyStep(Direction.Up); - } + const direction = target === this.spinnerDownEl ? Direction.Down : Direction.Up; + this.onApplyStep(direction); + + // Support long tap at a spinner + this.repeatDelayTimer = setTimeout(() => { + this.repeatRateTimer = setInterval(() => { + this.onApplyStep(direction); + }, this.repeatRate); + }, this.repeatDelay); } + /** + * Clear repeatDelayTimer and repeatRateTimer if exist + * @returns {void} + */ + protected clearTimer = (): void => { + if (this.repeatDelayTimer || this.repeatRateTimer) { + clearTimeout(this.repeatDelayTimer); + clearInterval(this.repeatRateTimer); + } + }; + /** * Step down or up and notify value change * @param direction Up or Down @@ -868,7 +914,7 @@ export class NumberField extends FormFieldElement { */ protected renderSpinner(): TemplateResult { return html` -
+