nexabase-report 0.2.1 → 0.2.3
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 +12 -0
- package/dist/{html2canvas-B-tAhudp.js → html2canvas-lgGzgSKy.js} +2 -2
- package/dist/{html2canvas-DzGPejdJ.js → html2canvas-xaUg0sZY.js} +1 -1
- package/dist/{html2pdf-DKyKa-Ei.js → html2pdf-BaxxmOjO.js} +3 -3
- package/dist/{index-3RAwseHQ.js → index-BjDXUsdw.js} +68722 -68571
- package/dist/{index.es-CKVR7NaR.js → index.es-D4FSgTc5.js} +2 -2
- package/dist/{jspdf.es.min-JIgjvvpV.js → jspdf.es.min-h5IBy_7w.js} +2 -2
- package/dist/nexabase-report.es.js +1 -1
- package/dist/nexabase-report.umd.js +212 -212
- package/dist/style.css +61 -0
- package/examples/AnexoFactura.pdf +0 -0
- package/examples/factura_de_recolecci/303/263n_de_residuos.json +528 -0
- package/examples/integration-angular.html +99 -0
- package/examples/integration-api.html +80 -0
- package/examples/integration-react.html +80 -0
- package/examples/integration-vanilla.html +66 -0
- package/examples/integration-vue.html +85 -0
- package/examples/report-factura-residuos.json +2 -1
- package/package.json +13 -3
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="es">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>NexaReport — Carga desde API</title>
|
|
7
|
+
<link rel="stylesheet" href="../dist/style.css">
|
|
8
|
+
<style>
|
|
9
|
+
body { margin: 0; font-family: system-ui, sans-serif; }
|
|
10
|
+
#app { height: 100vh; display: flex; flex-direction: column; }
|
|
11
|
+
header { padding: 12px 20px; background: #1e293b; color: #fff; display: flex; align-items: center; gap: 12px; }
|
|
12
|
+
header h1 { margin: 0; font-size: 18px; font-weight: 600; }
|
|
13
|
+
header small { opacity: 0.7; }
|
|
14
|
+
.controls { padding: 8px 20px; background: #f8fafc; border-bottom: 1px solid #e2e8f0; display: flex; gap: 8px; align-items: center; }
|
|
15
|
+
.controls button { padding: 6px 14px; background: #3b82f6; color: #fff; border: none; border-radius: 4px; cursor: pointer; font-size: 13px; }
|
|
16
|
+
.controls button:hover { background: #2563eb; }
|
|
17
|
+
.controls input { flex: 1; padding: 6px 10px; border: 1px solid #cbd5e1; border-radius: 4px; font-size: 13px; }
|
|
18
|
+
#status { font-size: 12px; color: #64748b; }
|
|
19
|
+
nexa-viewer { flex: 1; display: block; }
|
|
20
|
+
</style>
|
|
21
|
+
</head>
|
|
22
|
+
<body>
|
|
23
|
+
<div id="app">
|
|
24
|
+
<header>
|
|
25
|
+
<h1>NexaReport</h1>
|
|
26
|
+
<small>Carga desde API · Demo</small>
|
|
27
|
+
</header>
|
|
28
|
+
<div class="controls">
|
|
29
|
+
<span style="font-size:13px;font-weight:600">Reporte:</span>
|
|
30
|
+
<input id="reportUrl" type="text" value="/examples/report-productos.json" placeholder="URL del JSON de definición" />
|
|
31
|
+
<button id="btnLoad">Cargar</button>
|
|
32
|
+
<span id="status">Listo</span>
|
|
33
|
+
</div>
|
|
34
|
+
<nexa-viewer id="viewer" minimal></nexa-viewer>
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
<script src="../dist/nexabase-report.umd.js"></script>
|
|
38
|
+
<script>
|
|
39
|
+
window.NexaReport.registerNexaReport();
|
|
40
|
+
|
|
41
|
+
const viewer = document.getElementById('viewer');
|
|
42
|
+
const statusEl = document.getElementById('status');
|
|
43
|
+
const reportUrl = document.getElementById('reportUrl');
|
|
44
|
+
|
|
45
|
+
async function loadReport(url) {
|
|
46
|
+
statusEl.textContent = 'Cargando definición...';
|
|
47
|
+
try {
|
|
48
|
+
const res = await fetch(url);
|
|
49
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
50
|
+
const definition = await res.json();
|
|
51
|
+
viewer.definition = definition;
|
|
52
|
+
|
|
53
|
+
// Si el reporte tiene dataSources, cargar datos de ejemplo
|
|
54
|
+
if (definition.dataSources && definition.dataSources.length > 0) {
|
|
55
|
+
const alias = definition.dataSources[0].alias || 'main';
|
|
56
|
+
statusEl.textContent = `Cargando datos para "${alias}"...`;
|
|
57
|
+
// En producción, aquí llamarías a tu API real
|
|
58
|
+
viewer.data = [
|
|
59
|
+
{ nombre: 'Producto A', precio: 100, cantidad: 5 },
|
|
60
|
+
{ nombre: 'Producto B', precio: 200, cantidad: 3 },
|
|
61
|
+
{ nombre: 'Producto C', precio: 150, cantidad: 8 },
|
|
62
|
+
];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
statusEl.textContent = `Reporte: ${definition.metadata?.name || 'sin nombre'} (${new Date().toLocaleTimeString()})`;
|
|
66
|
+
} catch (err) {
|
|
67
|
+
statusEl.textContent = `Error: ${err.message}`;
|
|
68
|
+
console.error(err);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
document.getElementById('btnLoad').addEventListener('click', () => {
|
|
73
|
+
loadReport(reportUrl.value);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// Cargar reporte por defecto al iniciar
|
|
77
|
+
loadReport(reportUrl.value);
|
|
78
|
+
</script>
|
|
79
|
+
</body>
|
|
80
|
+
</html>
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="es">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>NexaReport — React</title>
|
|
7
|
+
<link rel="stylesheet" href="../dist/style.css">
|
|
8
|
+
<style>
|
|
9
|
+
body { margin: 0; font-family: system-ui, sans-serif; }
|
|
10
|
+
#root { height: 100vh; display: flex; flex-direction: column; }
|
|
11
|
+
header { padding: 12px 20px; background: #1e293b; color: #fff; display: flex; align-items: center; gap: 12px; }
|
|
12
|
+
header h1 { margin: 0; font-size: 18px; font-weight: 600; }
|
|
13
|
+
header small { opacity: 0.7; }
|
|
14
|
+
nexa-viewer { flex: 1; display: block; }
|
|
15
|
+
</style>
|
|
16
|
+
</head>
|
|
17
|
+
<body>
|
|
18
|
+
<div id="root">
|
|
19
|
+
<header>
|
|
20
|
+
<h1>NexaReport</h1>
|
|
21
|
+
<small>React · Demo</small>
|
|
22
|
+
</header>
|
|
23
|
+
<nexa-viewer id="viewer" minimal></nexa-viewer>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
|
|
27
|
+
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
|
|
28
|
+
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
|
|
29
|
+
<script src="../dist/nexabase-report.umd.js"></script>
|
|
30
|
+
<script type="text/babel">
|
|
31
|
+
NexaReport.registerNexaReport();
|
|
32
|
+
|
|
33
|
+
const reportDef = {
|
|
34
|
+
metadata: { version: '1', name: 'Órdenes', createdAt: new Date().toISOString() },
|
|
35
|
+
layout: {
|
|
36
|
+
page: { format: 'A4', orientation: 'portrait', margins: { top: 1, right: 1, bottom: 1, left: 1 } },
|
|
37
|
+
bands: [
|
|
38
|
+
{ id: 'b_hdr', type: 'ReportHeader', height: 60, elements: [
|
|
39
|
+
{ id: 'e_titulo', type: 'Text', x: 20, y: 10, width: 500, height: 30,
|
|
40
|
+
content: 'Órdenes de Compra', style: { fontSize: '22px', fontWeight: 'bold' } }
|
|
41
|
+
]},
|
|
42
|
+
{ id: 'b_data', type: 'DataBand', height: 30, dataSource: 'main', elements: [
|
|
43
|
+
{ id: 'e_orden', type: 'Text', x: 20, y: 5, width: 100, height: 20,
|
|
44
|
+
binding: 'orden', style: { fontSize: '12px' } },
|
|
45
|
+
{ id: 'e_cliente', type: 'Text', x: 140, y: 5, width: 200, height: 20,
|
|
46
|
+
binding: 'cliente', style: { fontSize: '12px' } },
|
|
47
|
+
{ id: 'e_monto', type: 'Text', x: 370, y: 5, width: 100, height: 20,
|
|
48
|
+
binding: 'monto', style: { fontSize: '12px', textAlign: 'right' } }
|
|
49
|
+
]},
|
|
50
|
+
{ id: 'b_ftr', type: 'PageFooter', height: 30, elements: [
|
|
51
|
+
{ id: 'e_page', type: 'Text', x: 20, y: 5, width: 200, height: 20,
|
|
52
|
+
content: 'Página {[Page]} de {[TotalPages]}', style: { fontSize: '10px', color: '#666' } }
|
|
53
|
+
]}
|
|
54
|
+
]
|
|
55
|
+
},
|
|
56
|
+
dataSources: [{ id: 'ds1', collection: '', alias: 'main', enabled: true }]
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const data = [
|
|
60
|
+
{ orden: 'ORD-001', cliente: 'Juan Pérez', monto: 15000 },
|
|
61
|
+
{ orden: 'ORD-002', cliente: 'María López', monto: 23000 },
|
|
62
|
+
{ orden: 'ORD-003', cliente: 'Carlos Ruiz', monto: 8700 },
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
function ReportViewer() {
|
|
66
|
+
const viewerRef = React.useRef(null);
|
|
67
|
+
React.useEffect(() => {
|
|
68
|
+
if (viewerRef.current) {
|
|
69
|
+
viewerRef.current.definition = reportDef;
|
|
70
|
+
viewerRef.current.data = data;
|
|
71
|
+
}
|
|
72
|
+
}, []);
|
|
73
|
+
return React.createElement('nexa-viewer', { ref: viewerRef, minimal: true });
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const root = ReactDOM.createRoot(document.getElementById('root'));
|
|
77
|
+
root.render(React.createElement(ReportViewer));
|
|
78
|
+
</script>
|
|
79
|
+
</body>
|
|
80
|
+
</html>
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="es">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>NexaReport — HTML puro</title>
|
|
7
|
+
<link rel="stylesheet" href="../dist/style.css">
|
|
8
|
+
<style>
|
|
9
|
+
body { margin: 0; font-family: system-ui, sans-serif; }
|
|
10
|
+
#app { height: 100vh; display: flex; flex-direction: column; }
|
|
11
|
+
header { padding: 12px 20px; background: #1e293b; color: #fff; display: flex; align-items: center; gap: 12px; }
|
|
12
|
+
header h1 { margin: 0; font-size: 18px; font-weight: 600; }
|
|
13
|
+
header small { opacity: 0.7; }
|
|
14
|
+
nexa-viewer { flex: 1; display: block; }
|
|
15
|
+
</style>
|
|
16
|
+
</head>
|
|
17
|
+
<body>
|
|
18
|
+
<div id="app">
|
|
19
|
+
<header>
|
|
20
|
+
<h1>NexaReport</h1>
|
|
21
|
+
<small>Vanilla HTML · Demo</small>
|
|
22
|
+
</header>
|
|
23
|
+
<nexa-viewer id="viewer" minimal></nexa-viewer>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
<script src="../dist/nexabase-report.umd.js"></script>
|
|
27
|
+
<script>
|
|
28
|
+
window.NexaReport.registerNexaReport();
|
|
29
|
+
|
|
30
|
+
const viewer = document.getElementById('viewer');
|
|
31
|
+
|
|
32
|
+
// Definición inline del reporte
|
|
33
|
+
viewer.definition = {
|
|
34
|
+
metadata: { version: '1', name: 'Productos', createdAt: new Date().toISOString() },
|
|
35
|
+
layout: {
|
|
36
|
+
page: { format: 'A4', orientation: 'portrait', margins: { top: 1, right: 1, bottom: 1, left: 1 } },
|
|
37
|
+
bands: [
|
|
38
|
+
{ id: 'b_hdr', type: 'ReportHeader', height: 60, elements: [
|
|
39
|
+
{ id: 'e_titulo', type: 'Text', x: 20, y: 10, width: 500, height: 30,
|
|
40
|
+
content: 'Listado de Productos', style: { fontSize: '22px', fontWeight: 'bold' } }
|
|
41
|
+
]},
|
|
42
|
+
{ id: 'b_data', type: 'DataBand', height: 30, dataSource: 'main', elements: [
|
|
43
|
+
{ id: 'e_nombre', type: 'Text', x: 20, y: 5, width: 250, height: 20,
|
|
44
|
+
binding: 'nombre', style: { fontSize: '12px' } },
|
|
45
|
+
{ id: 'e_precio', type: 'Text', x: 300, y: 5, width: 100, height: 20,
|
|
46
|
+
binding: 'precio', style: { fontSize: '12px', textAlign: 'right' } }
|
|
47
|
+
]},
|
|
48
|
+
{ id: 'b_ftr', type: 'PageFooter', height: 30, elements: [
|
|
49
|
+
{ id: 'e_page', type: 'Text', x: 20, y: 5, width: 200, height: 20,
|
|
50
|
+
content: 'Página {[Page]} de {[TotalPages]}', style: { fontSize: '10px', color: '#666' } }
|
|
51
|
+
]}
|
|
52
|
+
]
|
|
53
|
+
},
|
|
54
|
+
dataSources: [{ id: 'ds1', collection: '', alias: 'main', enabled: true }]
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
viewer.data = [
|
|
58
|
+
{ nombre: 'Laptop Gamer', precio: 25000 },
|
|
59
|
+
{ nombre: 'Mouse Inalámbrico', precio: 850 },
|
|
60
|
+
{ nombre: 'Teclado Mecánico', precio: 1200 },
|
|
61
|
+
{ nombre: 'Monitor 27"', precio: 5800 },
|
|
62
|
+
{ nombre: 'Audífonos Bluetooth', precio: 990 },
|
|
63
|
+
];
|
|
64
|
+
</script>
|
|
65
|
+
</body>
|
|
66
|
+
</html>
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="es">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>NexaReport — Vue 3</title>
|
|
7
|
+
<link rel="stylesheet" href="../dist/style.css">
|
|
8
|
+
<style>
|
|
9
|
+
body { margin: 0; font-family: system-ui, sans-serif; }
|
|
10
|
+
#app { height: 100vh; display: flex; flex-direction: column; }
|
|
11
|
+
header { padding: 12px 20px; background: #1e293b; color: #fff; display: flex; align-items: center; gap: 12px; }
|
|
12
|
+
header h1 { margin: 0; font-size: 18px; font-weight: 600; }
|
|
13
|
+
header small { opacity: 0.7; }
|
|
14
|
+
nexa-viewer { flex: 1; display: block; }
|
|
15
|
+
</style>
|
|
16
|
+
</head>
|
|
17
|
+
<body>
|
|
18
|
+
<div id="app">
|
|
19
|
+
<header>
|
|
20
|
+
<h1>NexaReport</h1>
|
|
21
|
+
<small>Vue 3 · Demo</small>
|
|
22
|
+
</header>
|
|
23
|
+
<nexa-viewer id="viewer" minimal></nexa-viewer>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
|
|
27
|
+
<script src="../dist/nexabase-report.umd.js"></script>
|
|
28
|
+
<script>
|
|
29
|
+
const { createApp, ref } = Vue;
|
|
30
|
+
NexaReport.registerNexaReport();
|
|
31
|
+
|
|
32
|
+
const reportDef = {
|
|
33
|
+
metadata: { version: '1', name: 'Ventas', createdAt: new Date().toISOString() },
|
|
34
|
+
layout: {
|
|
35
|
+
page: { format: 'A4', orientation: 'portrait', margins: { top: 1, right: 1, bottom: 1, left: 1 } },
|
|
36
|
+
bands: [
|
|
37
|
+
{ id: 'b_hdr', type: 'ReportHeader', height: 60, elements: [
|
|
38
|
+
{ id: 'e_titulo', type: 'Text', x: 20, y: 10, width: 500, height: 30,
|
|
39
|
+
content: 'Reporte de Ventas', style: { fontSize: '22px', fontWeight: 'bold' } }
|
|
40
|
+
]},
|
|
41
|
+
{ id: 'b_data', type: 'DataBand', height: 30, dataSource: 'main', elements: [
|
|
42
|
+
{ id: 'e_prod', type: 'Text', x: 20, y: 5, width: 200, height: 20,
|
|
43
|
+
binding: 'producto', style: { fontSize: '12px' } },
|
|
44
|
+
{ id: 'e_cant', type: 'Text', x: 250, y: 5, width: 80, height: 20,
|
|
45
|
+
binding: 'cantidad', style: { fontSize: '12px', textAlign: 'center' } },
|
|
46
|
+
{ id: 'e_total', type: 'Text', x: 350, y: 5, width: 100, height: 20,
|
|
47
|
+
binding: 'total', style: { fontSize: '12px', textAlign: 'right' } }
|
|
48
|
+
]},
|
|
49
|
+
{ id: 'b_ftr', type: 'PageFooter', height: 30, elements: [
|
|
50
|
+
{ id: 'e_page', type: 'Text', x: 20, y: 5, width: 200, height: 20,
|
|
51
|
+
content: 'Página {[Page]} de {[TotalPages]}', style: { fontSize: '10px', color: '#666' } }
|
|
52
|
+
]}
|
|
53
|
+
]
|
|
54
|
+
},
|
|
55
|
+
dataSources: [{ id: 'ds1', collection: '', alias: 'main', enabled: true }]
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const data = [
|
|
59
|
+
{ producto: 'Laptop', cantidad: 2, total: 50000 },
|
|
60
|
+
{ producto: 'Mouse', cantidad: 10, total: 8500 },
|
|
61
|
+
{ producto: 'Teclado', cantidad: 5, total: 6000 },
|
|
62
|
+
{ producto: 'Monitor', cantidad: 3, total: 17400 },
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
const app = createApp({
|
|
66
|
+
setup() {
|
|
67
|
+
const definition = ref(null);
|
|
68
|
+
const reportData = ref([]);
|
|
69
|
+
|
|
70
|
+
definition.value = reportDef;
|
|
71
|
+
reportData.value = data;
|
|
72
|
+
|
|
73
|
+
return { definition, reportData };
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
app.mount('#app');
|
|
78
|
+
|
|
79
|
+
// Sincronizar props con el custom element
|
|
80
|
+
const viewer = document.getElementById('viewer');
|
|
81
|
+
viewer.definition = reportDef;
|
|
82
|
+
viewer.data = data;
|
|
83
|
+
</script>
|
|
84
|
+
</body>
|
|
85
|
+
</html>
|
|
@@ -136,9 +136,10 @@
|
|
|
136
136
|
"tableColumns": [
|
|
137
137
|
{ "id": "col1", "title": "Fecha Recolección", "width": 140, "binding": "fechaRecoleccion" },
|
|
138
138
|
{ "id": "col2", "title": "Nombre del Residuo", "width": 280, "binding": "nombreResiduo" },
|
|
139
|
-
{ "id": "col3", "title": "Cantidad (kg)", "width": 120, "binding": "cantidad" },
|
|
139
|
+
{ "id": "col3", "title": "Cantidad (kg)", "width": 120, "binding": "cantidad", "footerText": "{[sum(cantidad)]}" },
|
|
140
140
|
{ "id": "col4", "title": "Doc. Relacionado", "width": 160, "binding": "documentoRelacionado" }
|
|
141
141
|
],
|
|
142
|
+
"tableShowFooter": true,
|
|
142
143
|
"style": { "fontSize": "11px" }
|
|
143
144
|
}
|
|
144
145
|
]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexabase-report",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "Professional report designer and viewer for NexaBase — drag & drop designer, PDF/Excel export, charts, crosstabs, subreports.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "NexaBase Team",
|
|
@@ -57,7 +57,14 @@
|
|
|
57
57
|
"scripts": {
|
|
58
58
|
"dev": "vite",
|
|
59
59
|
"build": "vue-tsc -b && vite build",
|
|
60
|
-
"preview": "vite preview"
|
|
60
|
+
"preview": "vite preview",
|
|
61
|
+
"test": "vitest run",
|
|
62
|
+
"test:watch": "vitest",
|
|
63
|
+
"test:coverage": "vitest run --coverage",
|
|
64
|
+
"release:patch": "npm test && npm run build && npm version patch && npm publish",
|
|
65
|
+
"release:minor": "npm test && npm run build && npm version minor && npm publish",
|
|
66
|
+
"release:major": "npm test && npm run build && npm version major && npm publish",
|
|
67
|
+
"prepack": "npm run build"
|
|
61
68
|
},
|
|
62
69
|
"dependencies": {
|
|
63
70
|
"@nexabase/sdk": "^2.17.6",
|
|
@@ -79,10 +86,13 @@
|
|
|
79
86
|
"devDependencies": {
|
|
80
87
|
"@types/node": "^22.13.0",
|
|
81
88
|
"@vitejs/plugin-vue": "^5.2.0",
|
|
89
|
+
"@vitest/coverage-v8": "^4.1.5",
|
|
82
90
|
"@vue/tsconfig": "^0.9.1",
|
|
91
|
+
"jsdom": "^29.1.1",
|
|
83
92
|
"typescript": "~6.0.2",
|
|
84
93
|
"vite": "^5.4.14",
|
|
85
94
|
"vite-plugin-dts": "^4.5.4",
|
|
95
|
+
"vitest": "^4.1.5",
|
|
86
96
|
"vue-tsc": "^3.2.6"
|
|
87
97
|
}
|
|
88
|
-
}
|
|
98
|
+
}
|