@robin-rossow/vue-input-number 2.0.1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # Vue Input Number
2
2
  Input field component to display a formatted number value. It is meant to be used with Vue 3.
3
3
 
4
+ [Demo](https://robinrossow.github.io/vue-input-number/)
5
+
4
6
  ## Installation
5
7
 
6
8
  ### Install via NPM
@@ -21,18 +23,14 @@ import { VueInputNumber } from '@robin-rossow/vue-input-number'
21
23
  ```
22
24
 
23
25
  ### Props
24
- | Props | Required | Type | Default |
25
- |------------------------|----------|---------------------------------------|-------------------------|
26
- | v-model | ✅ | string | number | undefined | - |
27
- | outputType | ❌ | 'Number' | 'String' | 'Number' |
28
- | min | ❌ | number | Number.MIN_SAFE_INTEGER |
29
- | max | ❌ | number | Number.MAX_SAFE_INTEGER |
30
- | precision | ❌ | number | 0 |
31
- | thousandSeparator | ❌ | string | undefined | ',' |
32
- | decimalSeparator | ❌ | string | undefined | ',' |
33
- | currency | ❌ | string | '' |
34
- | currencySymbolPosition | ❌ | 'prefix' |' suffix' | 'prefix' |
35
- | emptyValue | ❌ | number | '' | '' |
26
+ | Props | Required | Type | Default |
27
+ |------------------------|---------|--------------------------------------------|----------|
28
+ | v-model | ✅ | Ref<string &#124; number &#124; undefined> | - |
29
+ | outputType | ❌ | 'Number' &#124; 'String' | 'Number' |
30
+ | precision | ❌ | number | 0 |
31
+ | thousandSeparator | ❌ | string | ',' |
32
+ | decimalSeparator | ❌ | string | '.' |
33
+ | emptyValue | ❌ | '' &#124; 0 | '' |
36
34
 
37
35
  ## License
38
36
  vue-number-input is open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT)
@@ -1,14 +1,10 @@
1
1
  export interface Props {
2
2
  modelValue: string | number | undefined;
3
3
  outputType?: 'Number' | 'String';
4
- min?: number;
5
- max?: number;
6
4
  precision?: number;
7
- thousandSeparator?: string | undefined;
8
- decimalSeparator?: string | undefined;
9
- currency?: string;
10
- currencySymbolPosition?: 'prefix' | 'suffix';
11
- emptyValue?: number | '';
5
+ thousandSeparator?: string;
6
+ decimalSeparator?: string;
7
+ emptyValue?: '' | 0;
12
8
  }
13
9
  declare const __VLS_export: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
14
10
  "update:modelValue": (...args: any[]) => void;
@@ -20,14 +16,10 @@ declare const __VLS_export: import("vue").DefineComponent<Props, {}, {}, {}, {},
20
16
  onFocus?: ((...args: any[]) => any) | undefined;
21
17
  }>, {
22
18
  outputType: "Number" | "String";
23
- min: number;
24
- max: number;
25
19
  precision: number;
26
20
  thousandSeparator: string;
27
21
  decimalSeparator: string;
28
- currency: string;
29
- currencySymbolPosition: "prefix" | "suffix";
30
- emptyValue: number | "";
22
+ emptyValue: "" | 0;
31
23
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
32
24
  declare const _default: typeof __VLS_export;
33
25
  export default _default;
@@ -1,113 +1,96 @@
1
- import { defineComponent as I, ref as y, computed as m, onMounted as _, watch as F, withDirectives as $, openBlock as w, createElementBlock as k, mergeProps as B, vModelDynamic as P } from "vue";
2
- var l = { symbol: "$", format: "%s%v", decimal: ".", thousand: ",", precision: 2, grouping: 3, stripZeros: !1, fallback: 0, round: 0 };
3
- function g(u, t = l.decimal, e = l.fallback) {
4
- let n = new RegExp(`[^0-9-(-)-${t}]`, "g"), a = ("" + u).replace(n, "").replace(t, ".").replace(/\(([-]*\d*[^)]?\d+)\)/g, "-$1").replace(/\((.*)\)/, ""), r = (a.match(/-/g) || "").length % 2, i = parseFloat(a.replace(/-/g, "")) * (r ? -1 : 1);
5
- return isNaN(i) ? e : i;
1
+ import { defineComponent as w, useTemplateRef as I, ref as b, computed as h, onMounted as S, watch as $, withDirectives as T, openBlock as k, createElementBlock as B, mergeProps as C, vModelDynamic as F } from "vue";
2
+ var i = { symbol: "$", format: "%s%v", decimal: ".", thousand: ",", precision: 2, grouping: 3, stripZeros: !1, fallback: 0, round: 0 };
3
+ function g(n, t = i.decimal, e = i.fallback) {
4
+ let u = new RegExp(`[^0-9-(-)-${t}]`, "g"), a = ("" + n).replace(u, "").replace(t, ".").replace(/\(([-]*\d*[^)]?\d+)\)/g, "-$1").replace(/\((.*)\)/, ""), r = (a.match(/-/g) || "").length % 2, l = parseFloat(a.replace(/-/g, "")) * (r ? -1 : 1);
5
+ return isNaN(l) ? e : l;
6
6
  }
7
- function h(u, t, e) {
8
- t ??= l.precision, e ??= l.round;
9
- let n = Math.pow(10, t), a;
10
- return e > 0 ? a = Math.ceil : e < 0 ? a = Math.floor : a = Math.round, (a((u + 1e-8) * n) / n).toFixed(t);
7
+ function c(n, t, e) {
8
+ t ??= i.precision, e ??= i.round;
9
+ let u = Math.pow(10, t), a;
10
+ return e > 0 ? a = Math.ceil : e < 0 ? a = Math.floor : a = Math.round, (a((n + 1e-8) * u) / u).toFixed(t);
11
11
  }
12
- function T(u, t) {
13
- let e = u.split(t), n = "";
14
- if (e[0] !== void 0 && (n = e[0]), e[1] !== void 0) {
12
+ function x(n, t) {
13
+ let e = n.split(t), u = "";
14
+ if (e[0] !== void 0 && (u = e[0]), e[1] !== void 0) {
15
15
  let a = e[1].replace(/0+$/, "");
16
- a.length > 0 && (n = n + t + a);
16
+ a.length > 0 && (u = u + t + a);
17
17
  }
18
- return n;
18
+ return u;
19
19
  }
20
- function A(u, t = {}) {
21
- t = Object.assign({}, l, t);
22
- let e = u < 0 ? "-" : "", n = parseInt(h(Math.abs(u), t.precision, t.round), 10) + "", a = n.length > 3 ? n.length % 3 : 0, r = e + (a ? n.substr(0, a) + t.thousand : "") + n.substr(a).replace(/(\d{3})(?=\d)/g, "$1" + t.thousand) + (t.precision > 0 ? t.decimal + h(Math.abs(u), t.precision).split(".")[1] : "");
23
- return t.stripZeros ? T(r, t.decimal) : r;
20
+ function D(n, t = {}) {
21
+ t = Object.assign({}, i, t);
22
+ let e = n < 0 ? "-" : "", u = parseInt(c(Math.abs(n), t.precision, t.round), 10) + "", a = u.length > 3 ? u.length % 3 : 0, r = e + (a ? u.substr(0, a) + t.thousand : "") + u.substr(a).replace(/(\d{3})(?=\d)/g, "$1" + t.thousand) + (t.precision > 0 ? t.decimal + c(Math.abs(n), t.precision).split(".")[1] : "");
23
+ return t.stripZeros ? x(r, t.decimal) : r;
24
24
  }
25
- function D(u) {
26
- return typeof u == "string" && u.match("%v") ? { pos: u, neg: u.replace("-", "").replace("%v", "-%v"), zero: u } : u;
27
- }
28
- function N(u, t = {}) {
29
- t = Object.assign({}, l, t);
30
- let e = D(t.format), n;
31
- return u > 0 ? n = e.pos : u < 0 ? n = e.neg : n = e.zero, n.replace("%s", t.symbol).replace("%v", A(Math.abs(u), t));
32
- }
33
- const R = /* @__PURE__ */ I({
25
+ const L = /* @__PURE__ */ w({
34
26
  __name: "VueInputNumber",
35
27
  props: {
36
28
  modelValue: {},
37
29
  outputType: { default: "Number" },
38
- min: { default: Number.MIN_SAFE_INTEGER },
39
- max: { default: Number.MAX_SAFE_INTEGER },
40
30
  precision: { default: 0 },
41
31
  thousandSeparator: { default: "," },
42
32
  decimalSeparator: { default: "." },
43
- currency: { default: "" },
44
- currencySymbolPosition: { default: "prefix" },
45
33
  emptyValue: { default: "" }
46
34
  },
47
35
  emits: ["update:modelValue", "blur", "focus"],
48
- setup(u, { emit: t }) {
49
- const e = u, n = t, a = y(""), r = y(!1), i = m(() => e.currency ? e.currencySymbolPosition === "suffix" ? "%v %s" : "%s %v" : "%v"), s = m(() => c(g(a.value, e.decimalSeparator)) || 0);
50
- function d(o) {
51
- return N(o, {
52
- symbol: e.currency,
53
- format: i.value,
36
+ setup(n, { emit: t }) {
37
+ const e = n, u = t, a = I("number-input"), r = b(""), l = b(!1);
38
+ function p(o) {
39
+ return D(o, {
54
40
  thousand: e.thousandSeparator,
55
41
  decimal: e.decimalSeparator,
56
42
  precision: Number(e.precision)
57
43
  });
58
44
  }
59
- const M = m(() => d(s.value)), f = m(() => N(s.value, {
60
- symbol: "",
61
- format: "%v",
62
- thousand: e.thousandSeparator,
63
- decimal: e.decimalSeparator,
64
- precision: Number(e.precision)
65
- }));
66
- function S(o) {
67
- r.value = !1, a.value = M.value, p(), n("blur", o);
68
- }
45
+ const d = h(() => Number(c(g(r.value, e.decimalSeparator), e.precision)) || 0), v = h(() => p(d.value));
69
46
  function V(o) {
70
- r.value = !0, a.value = f.value, n("focus", o);
47
+ s(a.value.value), u("blur", o);
71
48
  }
72
- function x() {
73
- r.value || p();
49
+ function y(o) {
50
+ l.value = !0, u("focus", o);
74
51
  }
75
- function c(o) {
76
- return o < e.min ? e.min : o > e.max ? e.max : o;
52
+ function N() {
53
+ m();
77
54
  }
78
- function b(o) {
79
- if (!o) {
80
- a.value = e.emptyValue === "" ? "" : String(c(e.emptyValue));
55
+ function s(o) {
56
+ if (typeof o > "u" || o === "") {
57
+ r.value = e.emptyValue === 0 ? p(0) : "";
81
58
  return;
82
59
  }
83
- if (typeof o == "string") {
84
- a.value = d(c(g(o, e.decimalSeparator)));
60
+ if (typeof o == "number") {
61
+ r.value = p(o);
85
62
  return;
86
63
  }
87
- a.value = d(c(o));
64
+ r.value = p(g(o, e.decimalSeparator));
88
65
  }
89
- function p() {
90
- if (!s.value) {
91
- n("update:modelValue", e.emptyValue);
92
- return;
66
+ function m() {
67
+ if (!a.value.value) {
68
+ if (e.outputType.toLowerCase() === "string") {
69
+ e.emptyValue === 0 ? u("update:modelValue", p(0)) : u("update:modelValue", e.emptyValue);
70
+ return;
71
+ }
72
+ if (e.outputType.toLowerCase() === "number") {
73
+ e.emptyValue === 0 ? u("update:modelValue", 0) : u("update:modelValue", "");
74
+ return;
75
+ }
93
76
  }
94
- const o = e.outputType.toLowerCase() === "string" ? f.value : s.value;
95
- n("update:modelValue", o);
77
+ const o = e.outputType.toLowerCase() === "string" ? v.value : d.value;
78
+ u("update:modelValue", o);
96
79
  }
97
- return _(() => {
98
- b(e.modelValue), p();
99
- }), F(e, () => {
100
- r.value || (b(e.modelValue), p());
101
- }), (o, v) => $((w(), k("input", B(o.$attrs, {
102
- "onUpdate:modelValue": v[0] || (v[0] = (E) => a.value = E),
103
- onBlur: S,
104
- onInput: x,
105
- onFocus: V
80
+ return S(() => {
81
+ s(e.modelValue);
82
+ }), $(e, () => {
83
+ l.value || (s(e.modelValue), m());
84
+ }), (o, f) => T((k(), B("input", C({ ref: "number-input" }, o.$attrs, {
85
+ "onUpdate:modelValue": f[0] || (f[0] = (M) => r.value = M),
86
+ onBlur: V,
87
+ onInput: N,
88
+ onFocus: y
106
89
  }), null, 16)), [
107
- [P, a.value]
90
+ [F, r.value]
108
91
  ]);
109
92
  }
110
93
  });
111
94
  export {
112
- R as VueInputNumber
95
+ L as VueInputNumber
113
96
  };
@@ -1 +1 @@
1
- (function(i,r){typeof exports=="object"&&typeof module<"u"?r(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],r):(i=typeof globalThis<"u"?globalThis:i||self,r(i.VueInputNumber={},i.Vue))})(this,(function(i,r){"use strict";var s={symbol:"$",format:"%s%v",decimal:".",thousand:",",precision:2,grouping:3,stripZeros:!1,fallback:0,round:0};function b(u,t=s.decimal,e=s.fallback){let n=new RegExp(`[^0-9-(-)-${t}]`,"g"),o=(""+u).replace(n,"").replace(t,".").replace(/\(([-]*\d*[^)]?\d+)\)/g,"-$1").replace(/\((.*)\)/,""),l=(o.match(/-/g)||"").length%2,c=parseFloat(o.replace(/-/g,""))*(l?-1:1);return isNaN(c)?e:c}function y(u,t,e){t??=s.precision,e??=s.round;let n=Math.pow(10,t),o;return e>0?o=Math.ceil:e<0?o=Math.floor:o=Math.round,(o((u+1e-8)*n)/n).toFixed(t)}function S(u,t){let e=u.split(t),n="";if(e[0]!==void 0&&(n=e[0]),e[1]!==void 0){let o=e[1].replace(/0+$/,"");o.length>0&&(n=n+t+o)}return n}function V(u,t={}){t=Object.assign({},s,t);let e=u<0?"-":"",n=parseInt(y(Math.abs(u),t.precision,t.round),10)+"",o=n.length>3?n.length%3:0,l=e+(o?n.substr(0,o)+t.thousand:"")+n.substr(o).replace(/(\d{3})(?=\d)/g,"$1"+t.thousand)+(t.precision>0?t.decimal+y(Math.abs(u),t.precision).split(".")[1]:"");return t.stripZeros?S(l,t.decimal):l}function M(u){return typeof u=="string"&&u.match("%v")?{pos:u,neg:u.replace("-","").replace("%v","-%v"),zero:u}:u}function h(u,t={}){t=Object.assign({},s,t);let e=M(t.format),n;return u>0?n=e.pos:u<0?n=e.neg:n=e.zero,n.replace("%s",t.symbol).replace("%v",V(Math.abs(u),t))}const x=r.defineComponent({__name:"VueInputNumber",props:{modelValue:{},outputType:{default:"Number"},min:{default:Number.MIN_SAFE_INTEGER},max:{default:Number.MAX_SAFE_INTEGER},precision:{default:0},thousandSeparator:{default:","},decimalSeparator:{default:"."},currency:{default:""},currencySymbolPosition:{default:"prefix"},emptyValue:{default:""}},emits:["update:modelValue","blur","focus"],setup(u,{emit:t}){const e=u,n=t,o=r.ref(""),l=r.ref(!1),c=r.computed(()=>e.currency?e.currencySymbolPosition==="suffix"?"%v %s":"%s %v":"%v"),p=r.computed(()=>d(b(o.value,e.decimalSeparator))||0);function f(a){return h(a,{symbol:e.currency,format:c.value,thousand:e.thousandSeparator,decimal:e.decimalSeparator,precision:Number(e.precision)})}const I=r.computed(()=>f(p.value)),g=r.computed(()=>h(p.value,{symbol:"",format:"%v",thousand:e.thousandSeparator,decimal:e.decimalSeparator,precision:Number(e.precision)}));function E(a){l.value=!1,o.value=I.value,m(),n("blur",a)}function T(a){l.value=!0,o.value=g.value,n("focus",a)}function _(){l.value||m()}function d(a){return a<e.min?e.min:a>e.max?e.max:a}function v(a){if(!a){o.value=e.emptyValue===""?"":String(d(e.emptyValue));return}if(typeof a=="string"){o.value=f(d(b(a,e.decimalSeparator)));return}o.value=f(d(a))}function m(){if(!p.value){n("update:modelValue",e.emptyValue);return}const a=e.outputType.toLowerCase()==="string"?g.value:p.value;n("update:modelValue",a)}return r.onMounted(()=>{v(e.modelValue),m()}),r.watch(e,()=>{l.value||(v(e.modelValue),m())}),(a,N)=>r.withDirectives((r.openBlock(),r.createElementBlock("input",r.mergeProps(a.$attrs,{"onUpdate:modelValue":N[0]||(N[0]=F=>o.value=F),onBlur:E,onInput:_,onFocus:T}),null,16)),[[r.vModelDynamic,o.value]])}});i.VueInputNumber=x,Object.defineProperty(i,Symbol.toStringTag,{value:"Module"})}));
1
+ (function(i,n){typeof exports=="object"&&typeof module<"u"?n(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],n):(i=typeof globalThis<"u"?globalThis:i||self,n(i.VueInputNumber={},i.Vue))})(this,(function(i,n){"use strict";var p={symbol:"$",format:"%s%v",decimal:".",thousand:",",precision:2,grouping:3,stripZeros:!1,fallback:0,round:0};function f(r,t=p.decimal,e=p.fallback){let u=new RegExp(`[^0-9-(-)-${t}]`,"g"),o=(""+r).replace(u,"").replace(t,".").replace(/\(([-]*\d*[^)]?\d+)\)/g,"-$1").replace(/\((.*)\)/,""),l=(o.match(/-/g)||"").length%2,s=parseFloat(o.replace(/-/g,""))*(l?-1:1);return isNaN(s)?e:s}function c(r,t,e){t??=p.precision,e??=p.round;let u=Math.pow(10,t),o;return e>0?o=Math.ceil:e<0?o=Math.floor:o=Math.round,(o((r+1e-8)*u)/u).toFixed(t)}function V(r,t){let e=r.split(t),u="";if(e[0]!==void 0&&(u=e[0]),e[1]!==void 0){let o=e[1].replace(/0+$/,"");o.length>0&&(u=u+t+o)}return u}function g(r,t={}){t=Object.assign({},p,t);let e=r<0?"-":"",u=parseInt(c(Math.abs(r),t.precision,t.round),10)+"",o=u.length>3?u.length%3:0,l=e+(o?u.substr(0,o)+t.thousand:"")+u.substr(o).replace(/(\d{3})(?=\d)/g,"$1"+t.thousand)+(t.precision>0?t.decimal+c(Math.abs(r),t.precision).split(".")[1]:"");return t.stripZeros?V(l,t.decimal):l}const N=n.defineComponent({__name:"VueInputNumber",props:{modelValue:{},outputType:{default:"Number"},precision:{default:0},thousandSeparator:{default:","},decimalSeparator:{default:"."},emptyValue:{default:""}},emits:["update:modelValue","blur","focus"],setup(r,{emit:t}){const e=r,u=t,o=n.useTemplateRef("number-input"),l=n.ref(""),s=n.ref(!1);function d(a){return g(a,{thousand:e.thousandSeparator,decimal:e.decimalSeparator,precision:Number(e.precision)})}const b=n.computed(()=>Number(c(f(l.value,e.decimalSeparator),e.precision))||0),M=n.computed(()=>d(b.value));function v(a){m(o.value.value),u("blur",a)}function S(a){s.value=!0,u("focus",a)}function T(){h()}function m(a){if(typeof a>"u"||a===""){l.value=e.emptyValue===0?d(0):"";return}if(typeof a=="number"){l.value=d(a);return}l.value=d(f(a,e.decimalSeparator))}function h(){if(!o.value.value){if(e.outputType.toLowerCase()==="string"){e.emptyValue===0?u("update:modelValue",d(0)):u("update:modelValue",e.emptyValue);return}if(e.outputType.toLowerCase()==="number"){e.emptyValue===0?u("update:modelValue",0):u("update:modelValue","");return}}const a=e.outputType.toLowerCase()==="string"?M.value:b.value;u("update:modelValue",a)}return n.onMounted(()=>{m(e.modelValue)}),n.watch(e,()=>{s.value||(m(e.modelValue),h())}),(a,y)=>n.withDirectives((n.openBlock(),n.createElementBlock("input",n.mergeProps({ref:"number-input"},a.$attrs,{"onUpdate:modelValue":y[0]||(y[0]=w=>l.value=w),onBlur:v,onInput:T,onFocus:S}),null,16)),[[n.vModelDynamic,l.value]])}});i.VueInputNumber=N,Object.defineProperty(i,Symbol.toStringTag,{value:"Module"})}));
package/package.json CHANGED
@@ -1,52 +1,56 @@
1
- {
2
- "name": "@robin-rossow/vue-input-number",
3
- "version": "2.0.1",
4
- "keywords": [
5
- "component",
6
- "currency",
7
- "input",
8
- "text",
9
- "number",
10
- "numeric",
11
- "vue3",
12
- "vue",
13
- "typescript"
14
- ],
15
- "type": "module",
16
- "private": false,
17
- "files": ["dist"],
18
- "main": "./dist/vue-input-number.umd.cjs",
19
- "module": "./dist/vue-input-number.js",
20
- ".": {
21
- "import": {
22
- "types": "./dist/index.d.mts",
23
- "default": "./dist/vue-input-number.js"
24
- },
25
- "require": {
26
- "types": "./dist/index.d.ts",
27
- "default": "./dist/vue-input-number.umd.cjs"
28
- }
29
- },
30
- "types": "./dist/index.d.ts",
31
- "scripts": {
32
- "dev": "vite",
33
- "test": "vitest",
34
- "build": "vite build && vue-tsc --emitDeclarationOnly",
35
- "preview": "vite preview"
36
- },
37
- "dependencies": {
38
- "accounting-js": "^2.0.3",
39
- "vue": "^3.5.25"
40
- },
41
- "devDependencies": {
42
- "@types/node": "^24.10.1",
43
- "@vitejs/plugin-vue": "^6.0.2",
44
- "@vue/test-utils": "^2.4.6",
45
- "@vue/tsconfig": "^0.8.1",
46
- "happy-dom": "^20.6.1",
47
- "typescript": "~5.9.3",
48
- "vite": "^7.3.1",
49
- "vitest": "^4.0.18",
50
- "vue-tsc": "^3.2.4"
51
- }
52
- }
1
+ {
2
+ "name": "@robin-rossow/vue-input-number",
3
+ "version": "3.0.0",
4
+ "keywords": [
5
+ "component",
6
+ "currency",
7
+ "input",
8
+ "text",
9
+ "number",
10
+ "numeric",
11
+ "vue3",
12
+ "vue",
13
+ "typescript"
14
+ ],
15
+ "type": "module",
16
+ "private": false,
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "main": "./dist/vue-input-number.umd.cjs",
21
+ "module": "./dist/vue-input-number.js",
22
+ ".": {
23
+ "import": {
24
+ "types": "./dist/index.d.ts",
25
+ "default": "./dist/vue-input-number.js"
26
+ },
27
+ "require": {
28
+ "types": "./dist/index.d.ts",
29
+ "default": "./dist/vue-input-number.umd.cjs"
30
+ }
31
+ },
32
+ "types": "./dist/index.d.ts",
33
+ "scripts": {
34
+ "dev": "vite",
35
+ "test": "vitest run --coverage",
36
+ "build": "vite build && vue-tsc --emitDeclarationOnly",
37
+ "build-gh-pages": "vite build --config vite-gh-pages.config.ts",
38
+ "preview": "vite preview"
39
+ },
40
+ "dependencies": {
41
+ "accounting-js": "^2.0.3",
42
+ "vue": "^3.5.25"
43
+ },
44
+ "devDependencies": {
45
+ "@types/node": "^24.10.1",
46
+ "@vitejs/plugin-vue": "^6.0.2",
47
+ "@vitest/coverage-v8": "^4.0.18",
48
+ "@vue/test-utils": "^2.4.6",
49
+ "@vue/tsconfig": "^0.8.1",
50
+ "happy-dom": "^20.6.1",
51
+ "typescript": "~5.9.3",
52
+ "vite": "^7.3.1",
53
+ "vitest": "^4.0.18",
54
+ "vue-tsc": "^3.2.4"
55
+ }
56
+ }