running-tools

A collection of tools for runners and their coaches
git clone https://git.ashermorgan.net/running-tools/
Log | Files | Refs | README

commit a5252e2e8b65d8611e7b9f706a356ec532fe160c
parent ee74b3c9cd1bb4c43a21c861c57fb5103635be7e
Author: ashermorgan <59518073+ashermorgan@users.noreply.github.com>
Date:   Mon, 23 Aug 2021 13:41:19 -0700

Add step & wrap props in IntInput and DecimalInput

Diffstat:
Msrc/components/DecimalInput.vue | 28++++++++++++++++++++++++++--
Msrc/components/IntInput.vue | 28++++++++++++++++++++++++++--
Msrc/components/TimeInput.vue | 6+++---
Mtests/unit/components/DecimalInput.spec.js | 102+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
Mtests/unit/components/IntInput.spec.js | 98++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
5 files changed, 237 insertions(+), 25 deletions(-)

diff --git a/src/components/DecimalInput.vue b/src/components/DecimalInput.vue @@ -37,6 +37,22 @@ export default { }, /** + * The step value + */ + step: { + type: Number, + default: 1, + }, + + /** + * Whether to wrap around at the minimum and maximum values + */ + wrap: { + type: Boolean, + default: false, + }, + + /** * The number of digits to show before the decimal point */ padding: { @@ -168,10 +184,18 @@ export default { */ onkeydown(e) { if (e.key === 'ArrowUp') { - this.decValue += 1; + if (this.decValue === this.max && this.wrap && this.min !== null) { + this.decValue = this.min; + } else { + this.decValue += this.step; + } e.preventDefault(); } else if (e.key === 'ArrowDown') { - this.decValue -= 1; + if (this.decValue === this.min && this.wrap && this.max !== null) { + this.decValue = this.max; + } else { + this.decValue -= this.step; + } e.preventDefault(); } }, diff --git a/src/components/IntInput.vue b/src/components/IntInput.vue @@ -37,6 +37,22 @@ export default { }, /** + * The step value + */ + step: { + type: Number, + default: 1, + }, + + /** + * Whether to wrap around at the minimum and maximum values + */ + wrap: { + type: Boolean, + default: false, + }, + + /** * The number of digits to show before the decimal point */ padding: { @@ -157,10 +173,18 @@ export default { */ onkeydown(e) { if (e.key === 'ArrowUp') { - this.intValue += 1; + if (this.intValue === this.max && this.wrap && this.min !== null) { + this.intValue = this.min; + } else { + this.intValue += this.step; + } e.preventDefault(); } else if (e.key === 'ArrowDown') { - this.intValue -= 1; + if (this.intValue === this.min && this.wrap && this.max !== null) { + this.intValue = this.max; + } else { + this.intValue -= this.step; + } e.preventDefault(); } }, diff --git a/src/components/TimeInput.vue b/src/components/TimeInput.vue @@ -1,13 +1,13 @@ <template> <div class="time-input"> <int-input class="hours" aria-label="hours" - :min="0" :max="23" :padding="1" v-model="hours"/> + :min="0" :max="99" :padding="1" v-model="hours"/> <span>:</span> <int-input class="minutes" aria-label="minutes" - :min="0" :max="59" :padding="2" v-model="minutes"/> + :min="0" :max="59" wrap :padding="2" v-model="minutes"/> <span>:</span> <decimal-input class="seconds" aria-label="seconds" - :min="0" :max="59.99" :padding="2" :digits="2" v-model="seconds"/> + :min="0" :max="59.99" wrap :padding="2" :digits="2" v-model="seconds"/> </div> </template> diff --git a/tests/unit/components/DecimalInput.spec.js b/tests/unit/components/DecimalInput.spec.js @@ -21,28 +21,32 @@ describe('components/DecimalInput.vue', () => { expect(wrapper.find('input').element.value).to.equal('1.0'); }); - it('up arrow should increment value', async () => { + it('up arrow should increment value by step', async () => { // Initialize component - const wrapper = mount(DecimalInput); + const wrapper = mount(DecimalInput, { + propsData: { step: 0.2 }, + }); // Press up arrow await wrapper.trigger('keydown', { key: 'ArrowUp' }); - // Assert value is 1.0 and input event was emitted - expect(wrapper.find('input').element.value).to.equal('1.0'); - expect(wrapper.emitted().input).to.deep.equal([[1.0]]); + // Assert value is 0.2 and input event was emitted + expect(wrapper.find('input').element.value).to.equal('0.2'); + expect(wrapper.emitted().input).to.deep.equal([[0.2]]); }); - it('down arrow should increment value', async () => { + it('down arrow should increment value by step', async () => { // Initialize component - const wrapper = mount(DecimalInput); + const wrapper = mount(DecimalInput, { + propsData: { step: 0.2 }, + }); // Press down arrow await wrapper.trigger('keydown', { key: 'ArrowDown' }); - // Assert value is -1.0 and input event was emitted - expect(wrapper.find('input').element.value).to.equal('-1.0'); - expect(wrapper.emitted().input).to.deep.equal([[-1.0]]); + // Assert value is -0.2 and input event was emitted + expect(wrapper.find('input').element.value).to.equal('-0.2'); + expect(wrapper.emitted().input).to.deep.equal([[-0.2]]); }); it('should fire input event when value changes', async () => { @@ -248,6 +252,84 @@ describe('components/DecimalInput.vue', () => { expect(wrapper.emitted().input).to.deep.equal([[10.0]]); }); + it('should not wrap to the maximum if it is null', async () => { + // Initialize component + const wrapper = mount(DecimalInput, { + propsData: { + min: -1.0, max: null, value: -1.0, step: 0.2, wrap: true, + }, + }); + + // Try to decrement value + await wrapper.trigger('keydown', { key: 'ArrowDown' }); + + // Assert value is still -1.0 and no events were emitted + expect(wrapper.find('input').element.value).to.equal('-1.0'); + expect(wrapper.emitted().input).to.equal(undefined); + }); + + it('should not wrap to the minimum if it is null', async () => { + // Initialize component + const wrapper = mount(DecimalInput, { + propsData: { + min: null, max: 1.0, value: 1.0, step: 0.2, wrap: true, + }, + }); + + // Try to increment value + await wrapper.trigger('keydown', { key: 'ArrowUp' }); + + // Assert value is still 1.0 and no events were emitted + expect(wrapper.find('input').element.value).to.equal('1.0'); + expect(wrapper.emitted().input).to.equal(undefined); + }); + + it('should correctly wrap from the minimum to maximum', async () => { + // Initialize component + const wrapper = mount(DecimalInput, { + propsData: { + min: -1.0, max: 1.0, value: -0.9, step: 0.2, wrap: true, + }, + }); + + // Decrement value + await wrapper.trigger('keydown', { key: 'ArrowDown' }); + + // Assert value is -1.0 and input event was emitted + expect(wrapper.find('input').element.value).to.equal('-1.0'); + expect(wrapper.emitted().input).to.deep.equal([[-1.0]]); + + // Decrement value + await wrapper.trigger('keydown', { key: 'ArrowDown' }); + + // Assert value is 1.0 and input event was emitted + expect(wrapper.find('input').element.value).to.equal('1.0'); + expect(wrapper.emitted().input).to.deep.equal([[-1.0], [1.0]]); + }); + + it('should correctly wrap from the maximum to minimum', async () => { + // Initialize component + const wrapper = mount(DecimalInput, { + propsData: { + min: -1.0, max: 1.0, value: 0.9, step: 0.2, wrap: true, + }, + }); + + // Increment value + await wrapper.trigger('keydown', { key: 'ArrowUp' }); + + // Assert value is 1.0 and input event was emitted + expect(wrapper.find('input').element.value).to.equal('1.0'); + expect(wrapper.emitted().input).to.deep.equal([[1.0]]); + + // Increment value + await wrapper.trigger('keydown', { key: 'ArrowUp' }); + + // Assert value is -1.0 and input event was emitted + expect(wrapper.find('input').element.value).to.equal('-1.0'); + expect(wrapper.emitted().input).to.deep.equal([[1.0], [-1.0]]); + }); + it('should format value according to padding and digits props', async () => { // Initialize component const wrapper = mount(DecimalInput, { diff --git a/tests/unit/components/IntInput.spec.js b/tests/unit/components/IntInput.spec.js @@ -21,28 +21,32 @@ describe('components/IntInput.vue', () => { expect(wrapper.find('input').element.value).to.equal('1'); }); - it('up arrow should increment value', async () => { + it('up arrow should increment value by step', async () => { // Initialize component - const wrapper = mount(IntInput); + const wrapper = mount(IntInput, { + propsData: { step: 2 }, + }); // Press up arrow await wrapper.trigger('keydown', { key: 'ArrowUp' }); // Assert value is 1 and input event was emitted - expect(wrapper.find('input').element.value).to.equal('1'); - expect(wrapper.emitted().input).to.deep.equal([[1]]); + expect(wrapper.find('input').element.value).to.equal('2'); + expect(wrapper.emitted().input).to.deep.equal([[2]]); }); - it('down arrow should increment value', async () => { + it('down arrow should increment value by step', async () => { // Initialize component - const wrapper = mount(IntInput); + const wrapper = mount(IntInput, { + propsData: { step: 2 }, + }); // Press down arrow await wrapper.trigger('keydown', { key: 'ArrowDown' }); // Assert value is -1 and input event was emitted - expect(wrapper.find('input').element.value).to.equal('-1'); - expect(wrapper.emitted().input).to.deep.equal([[-1]]); + expect(wrapper.find('input').element.value).to.equal('-2'); + expect(wrapper.emitted().input).to.deep.equal([[-2]]); }); it('should fire input event when value changes', async () => { @@ -226,6 +230,84 @@ describe('components/IntInput.vue', () => { expect(wrapper.emitted().input).to.deep.equal([[10]]); }); + it('should not wrap to the maximum if it is null', async () => { + // Initialize component + const wrapper = mount(IntInput, { + propsData: { + min: -10, max: null, value: -10, step: 2, wrap: true, + }, + }); + + // Try to decrement value + await wrapper.trigger('keydown', { key: 'ArrowDown' }); + + // Assert value is still -10 and no events were emitted + expect(wrapper.find('input').element.value).to.equal('-10'); + expect(wrapper.emitted().input).to.equal(undefined); + }); + + it('should not wrap to the minimum if it is null', async () => { + // Initialize component + const wrapper = mount(IntInput, { + propsData: { + min: null, max: 10, value: 10, step: 2, wrap: true, + }, + }); + + // Try to increment value + await wrapper.trigger('keydown', { key: 'ArrowUp' }); + + // Assert value is still 10 and no events were emitted + expect(wrapper.find('input').element.value).to.equal('10'); + expect(wrapper.emitted().input).to.equal(undefined); + }); + + it('should correctly wrap from the minimum to maximum', async () => { + // Initialize component + const wrapper = mount(IntInput, { + propsData: { + min: -10, max: 10, value: -9, step: 2, wrap: true, + }, + }); + + // Decrement value + await wrapper.trigger('keydown', { key: 'ArrowDown' }); + + // Assert value is -10 and input event was emitted + expect(wrapper.find('input').element.value).to.equal('-10'); + expect(wrapper.emitted().input).to.deep.equal([[-10]]); + + // Decrement value + await wrapper.trigger('keydown', { key: 'ArrowDown' }); + + // Assert value is 10 and input event was emitted + expect(wrapper.find('input').element.value).to.equal('10'); + expect(wrapper.emitted().input).to.deep.equal([[-10], [10]]); + }); + + it('should correctly wrap from the maximum to minimum', async () => { + // Initialize component + const wrapper = mount(IntInput, { + propsData: { + min: -10, max: 10, value: 9, step: 2, wrap: true, + }, + }); + + // Increment value + await wrapper.trigger('keydown', { key: 'ArrowUp' }); + + // Assert value is 10 and input event was emitted + expect(wrapper.find('input').element.value).to.equal('10'); + expect(wrapper.emitted().input).to.deep.equal([[10]]); + + // Increment value + await wrapper.trigger('keydown', { key: 'ArrowUp' }); + + // Assert value is -10 and input event was emitted + expect(wrapper.find('input').element.value).to.equal('-10'); + expect(wrapper.emitted().input).to.deep.equal([[10], [-10]]); + }); + it('should format value according to padding prop', async () => { // Initialize component const wrapper = mount(IntInput, {