github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/ui/app/components/stepper-input.js (about) 1 import Component from '@ember/component'; 2 import { action } from '@ember/object'; 3 import { debounce } from '@ember/runloop'; 4 import { oneWay } from '@ember/object/computed'; 5 import { classNames, classNameBindings } from '@ember-decorators/component'; 6 import classic from 'ember-classic-decorator'; 7 8 const ESC = 27; 9 10 @classic 11 @classNames('stepper-input') 12 @classNameBindings( 13 'class', 14 'disabled:is-disabled', 15 'disabled:tooltip', 16 'disabled:multiline' 17 ) 18 export default class StepperInput extends Component { 19 min = 0; 20 max = 10; 21 value = 0; 22 debounce = 500; 23 onChange() {} 24 25 // Internal value changes immediately for instant visual feedback. 26 // Value is still the public API and is expected to mutate and re-render 27 // On onChange which is debounced. 28 @oneWay('value') internalValue; 29 30 @action 31 increment() { 32 if (this.internalValue < this.max) { 33 this.incrementProperty('internalValue'); 34 this.update(this.internalValue); 35 } 36 } 37 38 @action 39 decrement() { 40 if (this.internalValue > this.min) { 41 this.decrementProperty('internalValue'); 42 this.update(this.internalValue); 43 } 44 } 45 46 @action 47 setValue(e) { 48 if (e.target.value !== '') { 49 const newValue = Math.floor( 50 Math.min(this.max, Math.max(this.min, e.target.value)) 51 ); 52 this.set('internalValue', newValue); 53 this.update(this.internalValue); 54 } else { 55 e.target.value = this.internalValue; 56 } 57 } 58 59 @action 60 resetTextInput(e) { 61 if (e.keyCode === ESC) { 62 e.target.value = this.internalValue; 63 } 64 } 65 66 @action 67 selectValue(e) { 68 e.target.select(); 69 } 70 71 update(value) { 72 debounce(this, sendUpdateAction, value, this.debounce); 73 } 74 } 75 76 function sendUpdateAction(value) { 77 return this.onChange(value); 78 }