UNPKG

@mgcodeur/vue-number-input

Version:

A customizable Vue 3 number input component with increment/decrement buttons and long-press adjustment.

164 lines (163 loc) 5.37 kB
import { defineComponent as M, createElementBlock as v, openBlock as r, createElementVNode as i, ref as b, computed as I, watch as x, withDirectives as j, normalizeStyle as g, createBlock as $, renderSlot as z, vModelText as B } from "vue"; const S = ["width", "height", "stroke-width"], A = /* @__PURE__ */ M({ __name: "MinusIcon", props: { size: { default: 24 }, color: { default: "currentColor" }, strokeWidth: { default: 2 } }, setup(h) { return (u, n) => (r(), v("svg", { xmlns: "http://www.w3.org/2000/svg", width: u.size, height: u.size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": u.strokeWidth, "stroke-linecap": "round", "stroke-linejoin": "round", class: "icon icon-tabler icons-tabler-outline icon-tabler-minus" }, n[0] || (n[0] = [ i("path", { stroke: "none", d: "M0 0h24v24H0z", fill: "none" }, null, -1), i("path", { d: "M5 12l14 0" }, null, -1) ]), 8, S)); } }), C = ["width", "height", "stroke-width"], T = /* @__PURE__ */ M({ __name: "PlusIcon", props: { size: { default: 24 }, color: { default: "currentColor" }, strokeWidth: { default: 2 } }, setup(h) { return (u, n) => (r(), v("svg", { xmlns: "http://www.w3.org/2000/svg", width: u.size, height: u.size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": u.strokeWidth, "stroke-linecap": "round", "stroke-linejoin": "round", class: "icon icon-tabler icons-tabler-outline icon-tabler-plus" }, n[0] || (n[0] = [ i("path", { stroke: "none", d: "M0 0h24v24H0z", fill: "none" }, null, -1), i("path", { d: "M12 5l0 14" }, null, -1), i("path", { d: "M5 12l14 0" }, null, -1) ]), 8, C)); } }), P = { class: "v-number-input" }, W = { key: 0 }, E = ["step", "min", "max", "placeholder"], F = { key: 0 }, D = /* @__PURE__ */ M({ __name: "NumberInput", props: { adjustmentSpeed: { default: 100 }, inputPosition: { default: "center" }, max: { default: 1 / 0 }, min: { default: -1 / 0 }, modelValue: { default: 0 }, placeholder: { default: "0" }, step: { default: 1 }, textAlign: { default: "center" } }, emits: ["update:modelValue"], setup(h, { emit: u }) { const n = h, w = u, a = (e) => Math.min(n.max, Math.max(n.min, e)), s = (e) => Number(Number(e).toFixed(y())), c = (e) => s(e).toFixed(y()), y = () => { var e; return ((e = n.step.toString().split(".")[1]) == null ? void 0 : e.length) || 0; }, o = b(c(s(a(n.modelValue)))), p = b(null), l = b(s(a(n.modelValue))), k = I( () => ({ center: { input: 1, minus: 0, plus: 2 }, left: { input: 0, minus: 1, plus: 2 }, right: { input: 2, minus: 0, plus: 1 } })[n.inputPosition] ); function V(e) { const t = s(a((l.value ?? 0) + (e === "increment" ? n.step : -n.step))); l.value = t, o.value = c(t), w("update:modelValue", t); } function N() { const e = Number(o.value); o.value === "" || isNaN(e) ? l.value = s(Math.max(n.min, 0)) : l.value = s(a(e)), o.value = c(l.value), w("update:modelValue", l.value); } function _(e) { o.value = e.target.value; const t = Number(o.value); o.value !== "" && !isNaN(t) && (l.value = s(a(t)), w("update:modelValue", l.value)); } function f(e) { p.value || (V(e), p.value = window.setInterval(() => V(e), n.adjustmentSpeed)); } function d() { p.value && clearInterval(p.value), p.value = null; } return x( () => n.modelValue, (e) => { const t = s(a(e)); t !== l.value && (l.value = t, o.value = c(t)); }, { immediate: !0 } ), (e, t) => (r(), v("div", P, [ i("button", { class: "v-number-input__button", onMousedown: t[0] || (t[0] = (m) => f("decrement")), onMouseup: d, onMouseleave: d, onTouchstart: t[1] || (t[1] = (m) => f("decrement")), onTouchend: d, style: g({ order: k.value.minus }) }, [ e.$slots["minus-icon"] ? (r(), v("span", W, [ z(e.$slots, "minus-icon") ])) : (r(), $(A, { key: 1, size: 12, "stroke-width": 1.5 })) ], 36), j(i("input", { type: "number", "onUpdate:modelValue": t[2] || (t[2] = (m) => o.value = m), step: e.step, min: e.min, max: e.max, placeholder: e.placeholder, class: "v-number-input__input", onInput: _, onBlur: N, style: g({ textAlign: e.textAlign, order: k.value.input }), lang: "en" }, null, 44, E), [ [B, o.value] ]), i("button", { class: "v-number-input__button", onMousedown: t[3] || (t[3] = (m) => f("increment")), onMouseup: d, onMouseleave: d, onTouchstart: t[4] || (t[4] = (m) => f("increment")), onTouchend: d, style: g({ order: k.value.plus }) }, [ e.$slots["plus-icon"] ? (r(), v("span", F, [ z(e.$slots, "plus-icon") ])) : (r(), $(T, { key: 1, size: 12 })) ], 36) ])); } }); export { D as VueNumberInput };