JSFiddle - React, Tailwind, and code Playground
by neonDog
HTML
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha2/css/bootstrap.min.css">
<link rel="stylesheet" href="https://maxst.icons8.com/vue-static/landings/line-awesome/font-awesome-line-awesome/css/all.min.css">
<div class="row" style="width: 80%;">
<div class="col-1">
<div id="spinner"></div>
</div>
<div class="col-1">
<div id="spinner2"></div>
</div>
<div class="col-1">
<div id="spinner3"></div>
</div>
</div>
SCSS
.neon-spinner {
.input-group-append {
display: flex;
flex-direction: column;
}
.input-wrap { //Copying normal .input-group > .form-control styles
display:flex;
flex-direction: row;
position: relative;
flex: 1 1 auto;
width: 1%;
min-width: 0;
}
.unit-dropdown {
position:absolute;
top: 0;
bottom: 0;
right: 3px;
z-index: 10;
opacity: 0.5;
border-radius: 4px;
font-weight: bold;
display: flex;
align-items: center;
.btn.unit-dropdown-text {
width:100%;
padding: 2px;
font-size: 0.5em;
}
}
.btn.btn-xs {
padding: 1px;
height: 100%;
font-size: 0.6em;
//cursor: n-resize;
&[data-dir="up"] {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
border-top-left-radius: 0;
}
&[data-dir="down"] {
border-top: 0;
border-top-left-radius: 0;
border-top-right-radius: 0;
border-bottom-left-radius: 0;
}
}
}
JavaScript
const roundToNearest = (x, to, down) => Math[down ? 'ceil' : 'floor'](x/to)*to;
class NeonSpinner {
constructor(container, settings={}) {
const defaults = {
units: [null, 'px', 'em', 'rem', '%', 'vw', 'vh'],
step: 1,
min: -2,
max: 50,
emptyValue: null,
draggable: true,
roundToNearest: true,
onInput:(value, unit) => { console.error(value, unit) },
onChange:(value, unit)=>{ console.warn(value, unit) },
template: `
<div class="input-wrap">
<input type="text" class="form-control form-control-sm">
<div class="unit-dropdown dropdown">
<div class="unit-dropdown-text btn btn-secondary">rem</div>
</div>
</div>
<div class="input-group-append">
<button class="btn btn-xs btn-outline-secondary neon-spinner-click" type="button" data-action="spin" data-dir="up"><i class="fa fa-angle-up"></i></button>
<button class="btn btn-xs btn-outline-secondary neon-spinner-click" type="button" data-action="spin" data-dir="down"><i class="fa fa-angle-down"></i></button>
</div>`
};
this.options = Object.assign({}, defaults, settings);
this.container = container;
this.render();
this.value = this.options.emptyValue;
this.unit = this.options.units[0] || null; //Default to first unit declared
this._mousedown = this._mousedown.bind(this);
this._mouseup = this._mouseup.bind(this);
this._change = this._change.bind(this);
this._input = this._input.bind(this);
this.eventListeners();
this.input.max = this.options.max;
this.input.min = this.options.min;
}
render() {
this.container.innerHTML = this.options.template;
this.container.className = 'input-group neon-spinner';
this.input = this.container.getElementsByTagName('input')[0];
this.unitDropdownText = this.container.getElementsByClassName('unit-dropdown-text')[0];
}
fireEvent(type) {
...