nexabase-report 0.1.0 → 0.1.2

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,48 @@
1
- # NexaBase Report (Designer + Viewer)
1
+ # nexabase-report
2
2
 
3
- Librería para diseñar y visualizar reportes tipo banded (inspirada en Stimulsoft) con exportación a PDF/Excel/Word.
3
+ [![npm version](https://img.shields.io/npm/v/nexabase-report)](https://www.npmjs.com/package/nexabase-report)
4
+ [![license](https://img.shields.io/npm/l/nexabase-report)](LICENSE)
5
+
6
+ > Librería Vue 3 + TypeScript para diseñar y visualizar reportes tipo banded (inspirada en Stimulsoft / DevExpress). Incluye **diseñador WYSIWYG**, **visor framework-agnostic** como Custom Element, y **exportación 100% cliente** a PDF, Excel, Word y CSV.
7
+
8
+ ## Tabla de contenidos
9
+
10
+ - [Características](#características)
11
+ - [Instalación](#instalación)
12
+ - [Uso rápido](#uso-rápido)
13
+ - [React](#react)
14
+ - [Vue 3](#vue-3)
15
+ - [Angular](#angular)
16
+ - [HTML puro (CDN)](#html-puro-cdn)
17
+ - [API del Viewer](#api-del-viewer)
18
+ - [Props](#props)
19
+ - [Métodos](#métodos)
20
+ - [Eventos](#eventos)
21
+ - [Formato de datos](#formato-de-datos)
22
+ - [Variables de sistema](#variables-de-sistema)
23
+ - [Funciones de expresiones](#funciones-de-expresiones)
24
+ - [Exportación programática](#exportación-programática)
25
+ - [Solución de problemas](#solución-de-problemas)
26
+ - [Documentación adicional](#documentación-adicional)
27
+
28
+ ---
29
+
30
+ ## Características
31
+
32
+ | Característica | Descripción |
33
+ |----------------|-------------|
34
+ | **Custom Element** | `<nexa-viewer>` funciona en Vue, React, Angular, Svelte o HTML puro |
35
+ | **Diseñador WYSIWYG** | Arrastra y suelta bandas, textos, tablas, imágenes, gráficos |
36
+ | **Exportación cliente** | PDF (vectorial con jsPDF), Excel (SheetJS), Word (docx), CSV |
37
+ | **Gráficos** | ECharts integrado (barras, líneas, pastel, etc.) |
38
+ | **Tablas dinámicas** | Crosstabs (pivot tables) nativos |
39
+ | **Códigos QR / Barras** | jsbarcode + qrcode |
40
+ | **Formato condicional** | Reglas visuales por campo y valor |
41
+ | **Master-Detail** | Subreportes anidados |
42
+ | **Motor de expresiones** | Seguro (sin `eval`): `FormatNumber`, `IIF`, `ISNULL`, etc. |
43
+ | **Sin backend requerido** | Los datos se pasan directamente por props |
44
+
45
+ ---
4
46
 
5
47
  ## Instalación
6
48
 
@@ -8,99 +50,281 @@ Librería para diseñar y visualizar reportes tipo banded (inspirada en Stimulso
8
50
  npm install nexabase-report
9
51
  ```
10
52
 
11
- ## Uso rápido: Viewer (apps externas)
53
+ También necesitarás importar los estilos globales **una vez** en tu app:
54
+
55
+ ```ts
56
+ import 'nexabase-report/style.css';
57
+ ```
12
58
 
13
- El Viewer se expone como Custom Element: `<nexa-viewer />`.
59
+ ---
14
60
 
15
- ### 1) Vue 3
61
+ ## Uso rápido
16
62
 
17
- ```ts
63
+ ### React
64
+
65
+ ```tsx
66
+ import { useEffect, useRef, useState } from 'react';
18
67
  import { registerNexaReport } from 'nexabase-report';
19
68
  import 'nexabase-report/style.css';
20
69
 
21
70
  registerNexaReport();
71
+
72
+ export function ReportViewer() {
73
+ const ref = useRef<HTMLElement>(null);
74
+ const [definition, setDefinition] = useState<any>(null);
75
+ const [data, setData] = useState<any[]>([]);
76
+
77
+ useEffect(() => {
78
+ (async () => {
79
+ const res = await fetch('/report.json');
80
+ setDefinition(await res.json());
81
+ setData([
82
+ { nombre: 'Producto A', precio: 100 },
83
+ { nombre: 'Producto B', precio: 50 },
84
+ ]);
85
+ })();
86
+ }, []);
87
+
88
+ useEffect(() => {
89
+ if (!ref.current) return;
90
+ ref.current.definition = definition;
91
+ ref.current.data = data;
92
+ }, [definition, data]);
93
+
94
+ return <nexa-viewer ref={ref} minimal />;
95
+ }
22
96
  ```
23
97
 
98
+ ### Vue 3
99
+
24
100
  ```vue
101
+ <script setup lang="ts">
102
+ import { ref, watch } from 'vue';
103
+ import { registerNexaReport } from 'nexabase-report';
104
+ import 'nexabase-report/style.css';
105
+
106
+ registerNexaReport();
107
+
108
+ const props = defineProps<{ definition: any; data: any[] }>();
109
+ const viewerRef = ref<HTMLElement | null>(null);
110
+
111
+ watch(
112
+ () => [props.definition, props.data],
113
+ () => {
114
+ const el = viewerRef.value as any;
115
+ if (!el) return;
116
+ el.definition = props.definition;
117
+ el.data = props.data;
118
+ },
119
+ { immediate: true }
120
+ );
121
+ </script>
122
+
25
123
  <template>
26
- <nexa-viewer
27
- :definition="definition"
28
- :data="data"
29
- :parameters="{ fechaDesde: '2026-01-01' }"
30
- minimal
31
- skip-params-dialog
32
- />
124
+ <nexa-viewer ref="viewerRef" minimal style="display:block;height:100%" />
33
125
  </template>
34
126
  ```
35
127
 
36
- ### 2) React
128
+ ### Angular
37
129
 
38
- ```tsx
39
- import { useEffect, useRef } from 'react';
130
+ ```ts
131
+ import { Component, ElementRef, ViewChild, AfterViewInit } from '@angular/core';
40
132
  import { registerNexaReport } from 'nexabase-report';
41
133
  import 'nexabase-report/style.css';
42
134
 
43
135
  registerNexaReport();
44
136
 
45
- export function ReportViewer({ definition, data, parameters }: any) {
46
- const ref = useRef<any>(null);
47
- useEffect(() => {
48
- if (!ref.current) return;
49
- ref.current.definition = definition;
50
- ref.current.data = data;
51
- ref.current.parameters = parameters;
52
- }, [definition, data, parameters]);
137
+ @Component({
138
+ selector: 'app-root',
139
+ template: '<nexa-viewer #viewer minimal></nexa-viewer>',
140
+ })
141
+ export class AppComponent implements AfterViewInit {
142
+ @ViewChild('viewer', { static: true }) viewerRef!: ElementRef<HTMLElement>;
53
143
 
54
- return <nexa-viewer ref={ref} minimal />;
144
+ async ngAfterViewInit() {
145
+ const el = this.viewerRef.nativeElement as any;
146
+ const res = await fetch('/assets/report.json');
147
+ el.definition = await res.json();
148
+ el.data = [{ nombre: 'Producto A', precio: 100 }];
149
+ }
55
150
  }
56
151
  ```
57
152
 
58
- ### 3) HTML puro (CDN / UMD)
153
+ ### HTML puro (CDN)
59
154
 
60
155
  ```html
61
- <link rel="stylesheet" href="https://unpkg.com/nexabase-report@0.1.0/dist/style.css">
62
- <script src="https://unpkg.com/nexabase-report@0.1.0/dist/nexabase-report.umd.js"></script>
63
- <script>
64
- window.NexaReport.registerNexaReport();
65
- </script>
156
+ <!DOCTYPE html>
157
+ <html>
158
+ <head>
159
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/nexabase-report@latest/dist/style.css">
160
+ </head>
161
+ <body>
162
+ <nexa-viewer id="viewer" minimal></nexa-viewer>
66
163
 
67
- <nexa-viewer id="viewer"></nexa-viewer>
68
- <script>
69
- const v = document.getElementById('viewer');
70
- v.definition = {/* ... */};
71
- v.data = [{/* ... */}];
72
- </script>
164
+ <script src="https://cdn.jsdelivr.net/npm/nexabase-report@latest/dist/nexabase-report.umd.js"></script>
165
+ <script>
166
+ window.NexaReport.registerNexaReport();
167
+ const v = document.getElementById('viewer');
168
+ v.definition = { /* ... */ };
169
+ v.data = [ /* ... */ ];
170
+ </script>
171
+ </body>
172
+ </html>
73
173
  ```
74
174
 
75
- ## Probar sin publicar (recomendado)
175
+ ---
76
176
 
77
- Desde este repo:
177
+ ## API del Viewer
78
178
 
79
- ```bash
80
- npm run build
81
- npm pack
179
+ ### Props
180
+
181
+ | Prop | Tipo | Default | Descripción |
182
+ |------|------|---------|-------------|
183
+ | `definition` | `string \| object` | — | Definición del reporte (JSON o objeto) |
184
+ | `data` | `string \| any[] \| Record<string, any[]>` | — | Datos del reporte |
185
+ | `parameters` | `Record<string, any>` | `{}` | Valores de parámetros |
186
+ | `minimal` | `boolean \| string` | `false` | Oculta la toolbar de exportación |
187
+ | `skipParamsDialog` | `boolean` | `false` | Salta el diálogo de parámetros |
188
+ | `showToolbar` | `boolean \| string` | `true` | Muestra/oculta toolbar |
189
+ | `showThumbs` | `boolean \| string` | `true` | Muestra/oculta panel de miniaturas |
190
+ | `currentPage` | `number` | `1` | Página actual (control externo) |
191
+
192
+ ### Métodos (vía ref DOM)
193
+
194
+ ```ts
195
+ const viewer = document.querySelector('nexa-viewer');
196
+
197
+ await viewer.exportPdf();
198
+ await viewer.exportExcel();
199
+ await viewer.exportWord();
200
+ await viewer.exportCsv();
201
+
202
+ viewer.goToPage(3);
203
+ viewer.updateData({ main: [...] });
82
204
  ```
83
205
 
84
- En el proyecto externo:
206
+ ### Eventos
85
207
 
86
- ```bash
87
- npm install /ruta/al/nexabase-report-0.1.0.tgz
208
+ ```ts
209
+ viewer.addEventListener('page-change', (e) => console.log(e.detail));
210
+ viewer.addEventListener('drill-click', (e) => console.log(e.detail));
88
211
  ```
89
212
 
90
- ## Publicar en npm
213
+ ---
91
214
 
92
- Guía paso a paso: [docs/PUBLISHING.md](docs/PUBLISHING.md)
215
+ ## Formato de datos
93
216
 
94
- Resumen:
217
+ ### Single DataSource (array simple)
95
218
 
96
- ```bash
97
- npm run build
98
- npm pack --dry-run
99
- npm version patch
100
- npm publish --access public
219
+ ```json
220
+ [
221
+ { "id": 1, "nombre": "Juan", "ventas": 1500 },
222
+ { "id": 2, "nombre": "María", "ventas": 2300 }
223
+ ]
224
+ ```
225
+
226
+ ### Multiple DataSources (objeto con alias)
227
+
228
+ ```json
229
+ {
230
+ "clientes": [
231
+ { "id": 1, "nombre": "Juan" }
232
+ ],
233
+ "pedidos": [
234
+ { "id": 101, "cliente_id": 1, "total": 500 }
235
+ ]
236
+ }
101
237
  ```
102
238
 
103
- ## Documentación
239
+ ---
240
+
241
+ ## Variables de sistema
242
+
243
+ | Variable | Descripción | Ejemplo |
244
+ |----------|-------------|---------|
245
+ | `{{Page}}` | Página actual | `1` |
246
+ | `{{TotalPages}}` | Total de páginas | `5` |
247
+ | `{{Today}}` | Fecha actual | `2024-01-15` |
248
+ | `{{Now}}` | Fecha y hora actual | `2024-01-15 14:30` |
249
+ | `{{ReportName}}` | Nombre del reporte | `Ventas Mensuales` |
250
+ | `{{RowNumber}}` | Número de fila | `1` |
251
+ | `{{TotalRows}}` | Total de filas | `50` |
252
+ | `{{EvenRow}}` / `{{OddRow}}` | Fila par/impar | `true` / `false` |
253
+
254
+ ---
255
+
256
+ ## Funciones de expresiones
257
+
258
+ Usar sintaxis `{[...]}`:
259
+
260
+ ```
261
+ {[FormatNumber(precio, 'es-ES')]} → 1.234,56
262
+ {[FormatDate(fecha, 'dd/MM/yyyy')]} → 15/01/2024
263
+ {[FormatCurrency(total, 'USD')]} → $1,234.56
264
+ {[IIF(total > 100, 'OK', 'Bajo')]} → OK
265
+ {[ISNULL(campo, 'Sin dato')]} → Sin dato
266
+ {[UPPER(nombre)]} → JUAN
267
+ {[SUBSTRING(texto, 1, 3)]} → pri
268
+ {[ABS(-5)]} → 5
269
+ {[CEIL(5.3)]} → 6
270
+ {[FLOOR(5.9)]} → 5
271
+ ```
272
+
273
+ ---
274
+
275
+ ## Exportación programática
276
+
277
+ ```ts
278
+ // React / Vue / Angular
279
+ const viewer = viewerRef.current;
280
+ await viewer.exportPdf();
281
+
282
+ // HTML puro
283
+ const viewer = document.getElementById('viewer');
284
+ await viewer.exportPdf();
285
+ ```
286
+
287
+ ---
288
+
289
+ ## Solución de problemas
290
+
291
+ ### `<nexa-viewer>` no se renderiza
292
+
293
+ Asegúrate de llamar `registerNexaReport()` **antes** de montar el componente, e importar `nexabase-report/style.css`.
294
+
295
+ ### TypeScript: `'nexa-viewer' is not a known element`
296
+
297
+ En React/Vue/Angular, el custom element no está en el JSX/TSX estándar. Agrega declaraciones de tipo locales:
298
+
299
+ ```ts
300
+ declare module 'nexabase-report' {
301
+ export function registerNexaReport(): void;
302
+ }
303
+
304
+ declare global {
305
+ namespace JSX {
306
+ interface IntrinsicElements {
307
+ 'nexa-viewer': any;
308
+ }
309
+ }
310
+ }
311
+ ```
312
+
313
+ En Angular usa `CUSTOM_ELEMENTS_SCHEMA` en tu `@Component`.
314
+
315
+ ### Los datos no aparecen
316
+
317
+ Verifica que `dataSource` en la definición del reporte coincida con el alias de tus datos. El primer datasource suele tener alias `"main"`.
318
+
319
+ ---
320
+
321
+ ## Documentación adicional
322
+
323
+ - [API del Viewer](docs/VIEWER_API.md)
324
+ - [Integración externa](docs/EXTERNAL_INTEGRATION.md)
325
+ - [Plan de QA](docs/QA_PLAN.md)
326
+ - [Guía de publicación](docs/PUBLISHING.md)
327
+
328
+ ## Licencia
104
329
 
105
- - API del Viewer: [docs/VIEWER_API.md](docs/VIEWER_API.md)
106
- - Integración externa: [docs/EXTERNAL_INTEGRATION.md](docs/EXTERNAL_INTEGRATION.md)
330
+ MIT © NexaBase Team
Binary file
@@ -1,4 +1,4 @@
1
- import { c as MQ } from "./index-BJcVIdAR.js";
1
+ import { c as MQ } from "./index-D3l3xYdG.js";
2
2
  var nt = { exports: {} };
3
3
  /*!
4
4
  * html2canvas 1.4.1 <https://html2canvas.hertzen.com>
@@ -1,5 +1,5 @@
1
- import { a as c } from "./index-BJcVIdAR.js";
2
- import { r as f } from "./html2canvas-CSJ68r_Q.js";
1
+ import { a as c } from "./index-D3l3xYdG.js";
2
+ import { r as f } from "./html2canvas-Bt7A8WrM.js";
3
3
  function l(r, n) {
4
4
  for (var o = 0; o < n.length; o++) {
5
5
  const e = n[o];
@@ -1,6 +1,6 @@
1
- import { g as De, a as Ke, c as Te } from "./index-BJcVIdAR.js";
2
- import { j as Ge } from "./jspdf.es.min-CDx0J4wI.js";
3
- import { r as Be } from "./html2canvas-CSJ68r_Q.js";
1
+ import { g as De, a as Ke, c as Te } from "./index-D3l3xYdG.js";
2
+ import { j as Ge } from "./jspdf.es.min-M0h3R1kR.js";
3
+ import { r as Be } from "./html2canvas-Bt7A8WrM.js";
4
4
  function Ue(ge, we) {
5
5
  for (var me = 0; me < we.length; me++) {
6
6
  const ce = we[me];