nexabase-report 0.2.14 → 0.3.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
@@ -5,22 +5,7 @@
5
5
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.6-blue)](https://www.typescriptlang.org/)
6
6
  [![Vue 3](https://img.shields.io/badge/Vue-3.5-green)](https://vuejs.org/)
7
7
 
8
- > Librería Vue 3 + TypeScript para diseñar y visualizar reportes tipo banded (inspirada en Stimulsoft / DevExpress). Incluye **diseñador WYSIWYG** con multilingüe (ES/EN/PT), **visor framework-agnostic** como Custom Element, y **exportación 100% cliente** a PDF vectorial, Excel, Word y CSV.
9
-
10
- ---
11
-
12
- ## Tabla de contenidos
13
-
14
- - [Características](#características)
15
- - [Instalación](#instalación)
16
- - [Uso rápido](#uso-rápido)
17
- - [Diseñador (NexaDesigner)](#diseñador-nexadesigner)
18
- - [API del Viewer](#api-del-viewer)
19
- - [Formato de datos](#formato-de-datos)
20
- - [Variables y expresiones](#variables-y-expresiones)
21
- - [Ejemplos](#ejemplos)
22
- - [Documentación adicional](#documentación-adicional)
23
- - [Publicación](#publicación)
8
+ > Librería Vue 3 + TypeScript para diseñar y visualizar reportes tipo banded (inspirada en Stimulsoft / DevExpress). Incluye **diseñador WYSIWYG** multilingüe (ES/EN/PT), **visor como Custom Element** framework-agnostic, y **exportación 100% cliente** a PDF, Excel, Word y CSV.
24
9
 
25
10
  ---
26
11
 
@@ -29,21 +14,27 @@
29
14
  | Característica | Descripción |
30
15
  |----------------|-------------|
31
16
  | **Custom Element** | `<nexa-viewer>` funciona en Vue, React, Angular, Svelte, Blazor o HTML puro |
32
- | **Diseñador WYSIWYG** | `NexaDesigner.vue` — lienzo, ribbon, sidebars, multilingüe ES/EN/PT |
33
- | **Visor standalone** | `<nexa-viewer>` sin Vue en el proyecto consumidor |
34
- | **Exportación 100% cliente** | PDF vectorial (jsPDF), Excel (SheetJS), Word (docx), CSV (UTF-8 BOM) |
35
- | **Gráficos** | ECharts integrado (barras, líneas, pastel, área, scatter, radar, etc.) |
36
- | **Tablas dinámicas** | Crosstabs nativos con agregaciones (sum, count, avg, min, max) |
17
+ | **Diseñador WYSIWYG** | `NexaDesigner.vue` — ribbon, lienzo con snap-to-grid, sidebars, i18n |
18
+ | **Visor standalone** | Sin dependencia de Vue en el consumidor |
19
+ | **Exportación 100% cliente** | PDF (html2pdf.js + fallback jsPDF vectorial), Excel (SheetJS), Word (docx), CSV (UTF-8 BOM) |
20
+ | **Motor de paginación** | Algoritmo en dos fases: streaming + particionado por página, con splitting de tablas a través de páginas |
21
+ | **Renderers** | Texto, imágenes, barras, QR, shapes, drill-down, charts (ECharts), crosstabs, subreportes, widgets |
22
+ | **Watermarks** | Modo tile (texto repetido en grilla) o single posicionado (center, top-left, bottom-right, etc.) |
23
+ | **TOC** | Tabla de contenidos auto-generada en página 1 con enlaces a secciones |
24
+ | **Dashboard** | Modo de visualización con grilla de widgets |
25
+ | **Gráficos** | ECharts (barras, líneas, pastel, área, scatter, radar, etc.) |
26
+ | **Tablas dinámicas** | Crosstabs con agregaciones (sum, count, avg, min, max) |
37
27
  | **Códigos QR / Barras** | jsbarcode + qrcode con bindings a datos |
38
- | **Formato condicional** | Reglas visuales por campo y operador (eq, gt, contains, between, etc.) |
39
- | **Master-Detail** | Relaciones padre-hijo entre bandas con filtro automático |
40
- | **Drill-Down** | Navegación a reportes destino con paso de parámetros |
41
- | **Subreportes** | Anidamiento de reportes desde definición embebida o remota |
42
- | **Motor de expresiones** | Seguro (sin `eval`): `FormatNumber`, `FormatDate`, `IIF`, `ISNULL`, agregaciones |
43
- | **Parámetros** | Diálogo de entrada, valores por props, `skipParamsDialog` |
44
- | **Paginación** | Automática por altura de página con thumbnails y navegación |
45
- | **Shapes** | Rectángulos, elipses, líneas y flechas con estilo configurable |
46
- | **i18n** | Interfaz multilingüe del diseñador: español, inglés, portugués |
28
+ | **Formato condicional** | Reglas por operador (eq, gt, contains, between, regex, etc.) |
29
+ | **Master-Detail** | DataBand con DetailBand hijo, filtro por campo clave |
30
+ | **Drill-Down** | Navegación a reporte destino con paso de parámetros |
31
+ | **Subreportes** | Anidamiento vía definición embebida o remota (API REST) |
32
+ | **Motor de expresiones** | Seguro (sin `eval`): `FormatNumber`, `FormatDate`, `IIF`, `ISNULL`, agregaciones, `SUBSTRING`, etc. |
33
+ | **Parámetros** | Diálogo de entrada con tipos (text, number, date, boolean, select), validación, skip opcional |
34
+ | **Shapes** | Rectángulos, elipses, líneas y flechas |
35
+ | **Búsqueda** | Highlight inline con navegación entre resultados |
36
+ | **Zoom** | Zoom +/- 10%, fitToWidth, fitToPage, modo continuo/página simple |
37
+ | **i18n** | Visor y diseñador en español, inglés, portugués |
47
38
 
48
39
  ---
49
40
 
@@ -53,7 +44,7 @@
53
44
  npm install nexabase-report
54
45
  ```
55
46
 
56
- Importar estilos **una sola vez** al inicio de la app:
47
+ Importar estilos una sola vez al inicio:
57
48
 
58
49
  ```ts
59
50
  import 'nexabase-report/style.css';
@@ -86,8 +77,6 @@ import 'nexabase-report/style.css';
86
77
  </html>
87
78
  ```
88
79
 
89
- Ver ejemplo completo: [`examples/../viewer.html`](examples/../viewer.html)
90
-
91
80
  ### React
92
81
 
93
82
  ```tsx
@@ -118,11 +107,6 @@ import { registerNexaReport } from 'nexabase-report';
118
107
  import 'nexabase-report/style.css';
119
108
 
120
109
  registerNexaReport();
121
-
122
- const props = defineProps<{
123
- definition: any;
124
- data: any[];
125
- }>();
126
110
  </script>
127
111
 
128
112
  <template>
@@ -198,16 +182,16 @@ export class ReportComponent {
198
182
 
199
183
  ## Diseñador (NexaDesigner)
200
184
 
201
- El diseñador WYSIWYG es un componente Vue 3 que se integra en apps con Vue. Incluye:
185
+ Diseñador WYSIWYG como componente Vue 3:
202
186
 
203
- - **Ribbon** con formato de texto (fuente, tamaño, color, negrita, cursiva)
204
- - **Lienzo** con snap-to-grid, rulers y selección múltiple
205
- - **Panel de propiedades** modular (estilo, datos, condicional)
206
- - **Diccionario de datos** con campos del datasource
207
- - **Multilingüe**: español, inglés y portugués (cambiable desde toolbar)
208
- - **Import/Export** de definiciones JSON
209
- - **Deshacer/Rehacer** (Ctrl+Z / Ctrl+Y)
210
- - **Clipboard** (copiar/pegar elementos entre bandas)
187
+ - **Ribbon** formato de texto (fuente, tamaño, color, negrita, cursiva, alineación)
188
+ - **Lienzo** snap-to-grid (5 px), rulers, selección múltiple, arrastrar/redimensionar
189
+ - **Panel de propiedades** secciones: apariencia, datos, bordes, formato condicional
190
+ - **Diccionario de datos** campos del datasource con drag al lienzo
191
+ - **Multilingüe** español, inglés, portugués, cambiable desde la barra
192
+ - **Import/Export** definiciones JSON
193
+ - **Deshacer/Rehacer** Ctrl+Z / Ctrl+Y
194
+ - **Clipboard** copiar/pegar elementos entre bandas
211
195
 
212
196
  ### Uso
213
197
 
@@ -218,7 +202,7 @@ import 'nexabase-report/style.css';
218
202
  import { ref } from 'vue';
219
203
 
220
204
  const designerRef = ref(null);
221
- const locale = ref('es'); // 'es' | 'en' | 'pt'
205
+ const locale = ref('es');
222
206
 
223
207
  function onSave(reportDef: any) {
224
208
  console.log('Reporte guardado:', reportDef);
@@ -226,12 +210,7 @@ function onSave(reportDef: any) {
226
210
  </script>
227
211
 
228
212
  <template>
229
- <NexaDesigner
230
- ref="designerRef"
231
- :locale="locale"
232
- @save="onSave"
233
- style="height: 100vh"
234
- />
213
+ <NexaDesigner ref="designerRef" :locale="locale" @save="onSave" style="height: 100vh" />
235
214
  </template>
236
215
  ```
237
216
 
@@ -250,54 +229,219 @@ function onSave(reportDef: any) {
250
229
 
251
230
  ---
252
231
 
253
- ## API del Viewer
232
+ ## Visor (`<nexa-viewer>`)
233
+
234
+ El visor se registra como Custom Element y funciona sin Vue en el proyecto consumidor.
235
+
236
+ ### Formas de uso
237
+
238
+ ```html
239
+ <nexa-viewer
240
+ minimal
241
+ showToolbar
242
+ showThumbs
243
+ locale="es"
244
+ currentPage="1"
245
+ skipParamsDialog
246
+ ></nexa-viewer>
247
+ ```
248
+
249
+ Como Vue SFC directamente:
250
+
251
+ ```vue
252
+ <script setup lang="ts">
253
+ import { NexaViewerElement, registerNexaReport } from 'nexabase-report';
254
+ import 'nexabase-report/style.css';
255
+
256
+ registerNexaReport();
257
+ </script>
258
+
259
+ <template>
260
+ <nexa-viewer
261
+ :definition="reportDef"
262
+ :data="reportData"
263
+ :parameters="params"
264
+ locale="es"
265
+ @page-change="onPageChange"
266
+ @drill-click="onDrillClick"
267
+ />
268
+ </template>
269
+ ```
254
270
 
255
271
  ### Props
256
272
 
257
273
  | Prop | Tipo | Default | Descripción |
258
274
  |------|------|---------|-------------|
259
275
  | `definition` | `string \| NexaReportDefinition` | — | Definición del reporte (objeto o JSON string) |
260
- | `data` | `string \| any[] \| Record<string, any[]>` | — | Datos: array simple, objeto multi-alias, o JSON string |
261
- | `parameters` | `Record<string, any>` | — | Valores iniciales para los parámetros |
276
+ | `data` | `string \| any[] \| Record<string, any[]>` | — | Datos: array simple (alias "main"), objeto multi-alias, o JSON string |
277
+ | `parameters` | `Record<string, any>` | — | Valores iniciales de parámetros |
262
278
  | `minimal` | `boolean` | `false` | Oculta toolbar y thumbnails |
263
- | `showToolbar` | `boolean` | `true` | Muestra barra superior de exportación |
264
- | `showThumbs` | `boolean` | `true` | Muestra miniaturas laterales |
279
+ | `showToolbar` | `boolean` | `true` | Forzar toolbar visible (útil en minimal) |
280
+ | `showThumbs` | `boolean` | `true` | Forzar miniaturas visibles (útil en minimal) |
265
281
  | `skipParamsDialog` | `boolean` | `false` | Salta el diálogo de parámetros al cargar |
266
- | `currentPage` | `number` | `1` | Página inicial |
267
- | `apiBaseUrl` | `string` | | URL base de NexaBase (backend) |
268
- | `apiKey` | `string` | — | API key para NexaBase |
282
+ | `currentPage` | `number` | `1` | Página inicial (soporta v-model) |
283
+ | `locale` | `string` | `'es'` | Idioma: `'es'`, `'en'`, `'pt'` |
284
+ | `apiBaseUrl` | `string` | — | URL base para subreportes/drill-down remotos |
285
+ | `apiKey` | `string` | — | API Key para requests al backend |
269
286
 
270
- ### Métodos (DOM)
287
+ ### Métodos (acceso vía ref o DOM)
271
288
 
272
289
  ```ts
273
290
  const v = document.querySelector('nexa-viewer');
274
291
 
275
- await v.exportPdf(); // PDF vectorial (jsPDF)
276
- await v.exportPdfWithBookmarks(); // PDF + panel de marcadores
292
+ // Exportación
293
+ await v.exportPdf(); // pdf (html2pdf.js fallback jsPDF vectorial)
294
+ await v.exportPdfWithBookmarks(); // pdf con marcadores
277
295
  await v.exportExcel(); // .xlsx (SheetJS)
278
296
  await v.exportWord(); // .docx
279
- await v.exportCsv(); // .csv (UTF-8 BOM)
297
+ await v.exportCsv(); // .csv con UTF-8 BOM
298
+
299
+ // Navegación
300
+ v.goToPage(5);
301
+
302
+ // Datos
303
+ v.updateData(nuevosDatos);
304
+
305
+ // Parámetros
306
+ v.applyParams();
307
+ v.applyParamsWithValidation();
308
+ v.validateParams(); // retorna errores
280
309
 
281
- v.goToPage(3); // Navegar a página
282
- v.updateData(nuevosDatos); // Actualizar datos sin recargar definición
310
+ // Utilidad
311
+ v.getDictionaryFields(); // retorna campos disponibles
283
312
 
284
- console.log(v.pageNumber, v.totalPages, v.paramValues);
313
+ // Propiedades de lectura
314
+ v.pageNumber; // número actual
315
+ v.totalPages; // total de páginas
316
+ v.paramValues; // valores actuales de parámetros
317
+ v.showParamsDialog; // estado del diálogo
318
+ v.paramValidationErrors; // errores de validación
285
319
  ```
286
320
 
287
321
  ### Eventos
288
322
 
289
323
  ```ts
290
- v.addEventListener('page-change', e => console.log(e.detail.page));
291
- v.addEventListener('drill-click', e => console.log(e.detail));
324
+ v.addEventListener('page-change', e => console.log(e.detail.page));
325
+ v.addEventListener('drill-click', e => console.log(e.detail));
292
326
  v.addEventListener('subreport-toggle', e => console.log(e.detail));
293
- v.addEventListener('data-request', e => console.log(e.detail.alias));
327
+ v.addEventListener('data-request', e => console.log(e.detail.alias));
294
328
  ```
295
329
 
296
330
  ---
297
331
 
332
+ ## Arquitectura del visor
333
+
334
+ ### Template
335
+
336
+ ```
337
+ <nexa-viewer>
338
+ ├── Toolbar (condicional)
339
+ │ ├── Exportación: PDF, Excel, Word, CSV, imprimir
340
+ │ ├── Zoom: −, %, +, fitToWidth, fitToPage
341
+ │ └── Paginación: ◀, input/total, ▶, búsqueda, info
342
+
343
+ ├── Sidebar (condicional, 220px)
344
+ │ ├── Pestaña Pages — miniaturas vía html2canvas
345
+ │ ├── Pestaña TOC — tabla de contenidos con navegación
346
+ │ └── Pestaña Params — formulario de parámetros (text, number, date, boolean, select)
347
+
348
+ ├── Viewport (scrollable)
349
+ │ └── Pages root (transform: scale(Z%) )
350
+ │ ├── Dashboard: grilla de DashboardWidgetRenderer
351
+ │ └── Reporte: v-for pages
352
+ │ └── report-page (sombra, fondo blanco)
353
+ │ ├── Watermark (tile o single posicionado)
354
+ │ ├── TOC page (si página 1 y generateTOC)
355
+ │ └── Bands
356
+ │ ├── DataBand tabular → Table, Chart, Crosstab, SubReport
357
+ │ └── DataBand iterativa → Text, Image, Barcode, QR, Shape, DrillDown
358
+
359
+ ├── Modal DrillDown (reporte anidado vía API)
360
+ └── Modal About
361
+ ```
362
+
363
+ ### PaginationEngine
364
+
365
+ El motor de paginación es una clase (`src/lib/viewer/services/PaginationEngine.ts`) que opera en **dos fases**:
366
+
367
+ **Fase 1 — generateStream()**: Generator que produce un stream de `PageBandDef`:
368
+ 1. Emite `ReportHeader` primero
369
+ 2. Bandas estáticas (ni DataBand ni DetailBand)
370
+ 3. Para cada `DataBand`:
371
+ - **Tabular** (Table, Chart, Crosstab, SubReport): emite la banda completa con todas las filas en `rows`
372
+ - **Iterativa** (una instancia por fila): emite una banda por fila, intercalando GroupHeader/GroupFooter según agrupación y procesando DetailBand hijos (master-detail)
373
+ 4. Emite `ReportFooter` al final
374
+
375
+ **Fase 2 — generatePages()**: Algoritmo de particionado:
376
+ - Calcula altura disponible: `pageHeight - pageHeader - pageFooter`
377
+ - Itera el stream, acumulando bandas
378
+ - Si una banda **tabular** no cabe:
379
+ - **Tabla**: calcula filas que entran (`(h disponible - h header) / h fila`), corta en chunks, coloca cada chunk en página nueva
380
+ - **Tabla agrupada**: corta por grupos completos (respeta `tableShowGroupHeader`/`tableShowGroupFooter`)
381
+ - Charts/Crosstabs: saltan a página nueva enteros
382
+ - Respeta `pageBreakBefore` / `pageBreakAfter`
383
+ - Asigna coordenadas Y absolutas para posicionamiento CSS
384
+ - Cada ~10 páginas cede el hilo (`setTimeout`) para no bloquear en datasets grandes
385
+
386
+ Métodos estáticos auxiliares: `applyFilters`, `applySort`, `applyJoins`, `matchesFilterValue` (soporta eq, ne, gt, gte, lt, lte, contains, starts_with, ends_with, is_null, is_not_null, between, regex).
387
+
388
+ ### Renderers
389
+
390
+ | Renderer | Archivo | Descripción |
391
+ |----------|---------|-------------|
392
+ | TextRenderer | `viewer/renderers/TextRenderer.vue` | Texto plano con soporte de highlight de búsqueda |
393
+ | ImageRenderer | `viewer/renderers/ImageRenderer.vue` | `<img>` con resolución de binding/URL |
394
+ | BarcodeRenderer | `viewer/renderers/BarcodeRenderer.vue` | SVG vía jsbarcode (CODE128 default) |
395
+ | QRCodeRenderer | `viewer/renderers/QRCodeRenderer.vue` | QR vía librería qrcode |
396
+ | ShapeRenderer | `viewer/renderers/ShapeRenderer.vue` | Rectángulo, elipse, línea, flecha (CSS inline) |
397
+ | DrillDownRenderer | `viewer/renderers/DrillDownRenderer.vue` | Elemento clickeable que emite `drill-click` |
398
+ | FallbackRenderer | `viewer/renderers/FallbackRenderer.vue` | Muestra tipo no soportado |
399
+ | SubreportRenderer | `viewer/renderers/SubreportRenderer.vue` | `<nexa-viewer>` anidado (embebido o remoto) |
400
+ | ChartRenderer | `viewer/ChartRenderer.vue` | ECharts (barras, líneas, pastel, etc.) |
401
+ | CrosstabRenderer | `viewer/CrosstabRenderer.vue` | Tabla dinámica con agrupación fila/columna |
402
+ | DashboardWidgetRenderer | `viewer/DashboardWidgetRenderer.vue` | Widgets en modo dashboard |
403
+
404
+ Total: **11 renderers** (8 en `viewer/renderers/` + 3 en `viewer/`).
405
+
406
+ ### Zoom (`useZoom`)
407
+
408
+ - Rango: 25%–250%, default 100%
409
+ - `zoomIn()` / `zoomOut()` — ±10 puntos
410
+ - `fitToWidth()` — escala al ancho del viewport
411
+ - `fitToPage()` — escala al alto y ancho
412
+ - Modos: `continuous` (scroll vertical) / `single` (página por página)
413
+ - Atajo: Ctrl+`+`, Ctrl+`-`, Ctrl+`0`
414
+
415
+ ### Búsqueda (`useSearch`)
416
+
417
+ - `searchQuery` con debounce de 200ms
418
+ - Escanea hasta 250 páginas, case-insensitive, máx 500 resultados
419
+ - Navegación: `nextMatch()` / `prevMatch()` con scroll automático
420
+ - Highlight: `getHighlightParts(text)` retorna segmentos marcados/no marcados
421
+ - Input de búsqueda en toolbar con atajo de teclado
422
+
423
+ ### Watermarks
424
+
425
+ - **Tile**: texto repetido en grilla (20 spans CSS grid), opacidad configurable, rotado
426
+ - **Single**: posicionado absoluto (center, top-left, top-right, bottom-left, bottom-right, top-center, bottom-center)
427
+ - Opacidad, color, tamaño, rotación por configuración
428
+
429
+ ### TOC (Tabla de Contenidos)
430
+
431
+ - Generación automática si `generateTOC: true` en la definición
432
+ - Se Renderiza en página 1
433
+ - Cada ítem: texto + dots + número de página
434
+ - Navegación: click → `goToPage(n)` con scroll
435
+
436
+ ### Dashboard
437
+
438
+ Si `documentType === 'Dashboard'`, el reporte se Renderiza como grilla de widgets (`DashboardWidgetRenderer`) en lugar de páginas con bandas.
439
+
440
+ ---
441
+
298
442
  ## Formato de datos
299
443
 
300
- ### Array simple (único DataSource)
444
+ ### Array simple
301
445
 
302
446
  ```json
303
447
  [
@@ -306,7 +450,9 @@ v.addEventListener('data-request', e => console.log(e.detail.alias));
306
450
  ]
307
451
  ```
308
452
 
309
- ### Múltiples DataSources (objeto con alias)
453
+ El DataSource se asocia automáticamente al alias `"main"`.
454
+
455
+ ### Múltiples DataSources
310
456
 
311
457
  ```json
312
458
  {
@@ -314,13 +460,12 @@ v.addEventListener('data-request', e => console.log(e.detail.alias));
314
460
  { "id": 1, "nombre": "Juan", "ciudad": "Bogotá" }
315
461
  ],
316
462
  "pedidos": [
317
- { "cliente_id": 1, "producto": "Camisa", "cantidad": 3 },
318
- { "cliente_id": 1, "producto": "Pantalón", "cantidad": 2 }
463
+ { "cliente_id": 1, "producto": "Camisa", "cantidad": 3 }
319
464
  ]
320
465
  }
321
466
  ```
322
467
 
323
- El reporte usa `dataSource: "clientes"` (o el alias correspondiente) en la banda.
468
+ Cada banda referencia su DataSource por alias: `dataSource: "clientes"`.
324
469
 
325
470
  ### Parámetros
326
471
 
@@ -365,35 +510,40 @@ viewer.parameters = {
365
510
  | `{[IIF(total > 100000, 'ALTO', 'BAJO')]}` | `ALTO` |
366
511
  | `{[ISNULL(cliente, 'Sin nombre')]}` | `Sin nombre` |
367
512
  | `{[UPPER(nombre)]}` | `JUAN PÉREZ` |
513
+ | `{[LOWER(nombre)]}` | `juan pérez` |
368
514
  | `{[SUBSTRING(texto, 0, 3)]}` | `Hel` |
369
- | `{[ABS(-5)]}` / `{[CEIL(5.3)]}` / `{[FLOOR(5.9)]}` | `5` / `6` / `5` |
370
- | `{[SUM(cantidad)]}` / `{[COUNT(id)]}` / `{[AVG(precio)]}` | Agregaciones |
515
+ | `{[LENGTH(nombre)]}` | `10` |
516
+ | `{[TRIM(texto)]}` | sin espacios |
517
+ | `{[ABS(-5)]}` | `5` |
518
+ | `{[CEIL(5.3)]}` | `6` |
519
+ | `{[FLOOR(5.9)]}` | `5` |
520
+ | `{[SUM(cantidad)]}` | suma |
521
+ | `{[COUNT(id)]}` | conteo |
522
+ | `{[AVG(precio)]}` | promedio |
523
+ | `{[MIN(precio)]}` | mínimo |
524
+ | `{[MAX(precio)]}` | máximo |
371
525
  | `{[CONCAT(nombre, ' - ', ciudad)]}` | `Juan - Bogotá` |
526
+ | `{[REPLACE(texto, 'a', 'o')]}` | reemplazo |
372
527
 
373
528
  ---
374
529
 
375
530
  ## Ejemplos
376
531
 
377
- Los reportes de ejemplo están en `examples/` y son compatibles tanto con el diseñador como con el viewer.
532
+ Los reportes de ejemplo están en `examples/` y son compatibles con diseñador y visor.
378
533
 
379
534
  | Archivo | Descripción |
380
535
  |---------|-------------|
381
536
  | `report-factura.json` | Factura con ítems, cliente y totales |
382
- | `factura_de_recolección_de_residuos.json` | Factura ambiental con múltiples DataSources |
537
+ | `factura_de_recolección_de_residuos.json` | Factura ambiental multi-DataSource |
383
538
  | `report-factura-residuos.json` | Factura de residuos con GroupHeader/Footer |
384
- | `report-anexo-factura.json` | Anexo complementario con tabla expandida |
385
- | `report-ventas-logo-tabla.json` | Reporte corporativo con logo y tabla agrupada |
386
- | `report-agrupado-por-cliente.json` | GroupHeader + Table con agrupación por cliente |
539
+ | `report-anexo-factura.json` | Anexo con tabla expandida |
540
+ | `report-ventas-logo-tabla.json` | Corporativo con logo y tabla agrupada |
541
+ | `report-agrupado-por-cliente.json` | GroupHeader + agrupación por cliente |
387
542
  | `report-productos.json` | Lista simple de productos |
388
- | `report-crosstab-categoria-mes.json` | Tabla dinámica (crosstab) categoría × mes |
389
- | `report-grafico-ventas-por-mes.json` | Gráfico de barras (ECharts) |
390
- | `report-master-detail-ordenes.json` | Master-Detail con subreportes relacionados |
391
- | `report-codigos-qr-barcode.json` | Códigos QR y barras desde datos |
392
-
393
- ```bash
394
- # Probar un ejemplo local
395
- curl -s https://raw.githubusercontent.com/nexabase/nexabase-report/main/examples/report-factura.json
396
- ```
543
+ | `report-crosstab-categoria-mes.json` | Crosstab categoría × mes |
544
+ | `report-grafico-ventas-por-mes.json` | Gráfico de barras ECharts |
545
+ | `report-master-detail-ordenes.json` | Master-Detail con subreportes |
546
+ | `report-codigos-qr-barcode.json` | Códigos QR y barras |
397
547
 
398
548
  ---
399
549
 
@@ -405,28 +555,28 @@ npm version patch|minor|major
405
555
  npm publish --access public
406
556
  ```
407
557
 
408
- Disponible en CDN automáticamente tras publicar:
558
+ CDN automático:
409
559
 
410
560
  ```html
411
561
  <script src="https://cdn.jsdelivr.net/npm/nexabase-report@0.2/dist/nexabase-report.umd.js"></script>
412
562
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/nexabase-report@0.2/dist/style.css">
413
563
  ```
414
564
 
415
- Ver [`docs/PUBLISHING.md`](docs/PUBLISHING.md) para CI/CD y registry privado.
565
+ Ver [`docs/PUBLISHING.md`](docs/PUBLISHING.md) para CI/CD y registro privado.
416
566
 
417
567
  ---
418
568
 
419
569
  ## Documentación adicional
420
570
 
421
- - [API completa del Viewer](docs/VIEWER_API.md) — Props, métodos, eventos, tipos
422
- - [API REST (funciones serverless)](docs/API_REST.md) — Endpoints para listar/render/exportar
571
+ - [API completa del Viewer](docs/VIEWER_API.md) — props, métodos, eventos, tipos
572
+ - [API REST](docs/API_REST.md) — endpoints serverless
423
573
  - [Integración externa](docs/EXTERNAL_INTEGRATION.md) — ASP.NET, Django, Laravel, Rails
424
- - [Plan de QA](docs/QA_PLAN.md) — Checklist de pruebas manuales
574
+ - [Plan de QA](docs/QA_PLAN.md) — checklist de pruebas manuales
425
575
  - [Checklist de regresión exportación](docs/EXPORT_REGRESSION.md) — PDF, Excel, Word, CSV
426
- - [Guía de publicación npm](docs/PUBLISHING.md) — Build, versionado, CI/CD
576
+ - [Guía de publicación npm](docs/PUBLISHING.md) — build, versionado, CI/CD
427
577
 
428
578
  ---
429
579
 
430
580
  ## Licencia
431
581
 
432
- MIT © NexaBase Team
582
+ MIT © NexaBase Team
@@ -1,5 +1,5 @@
1
- import { a as c } from "./index-CrlafZ0y.js";
2
- import { r as f } from "./html2canvas-Bz1P596e.js";
1
+ import { a as c } from "./index-DLc-dsvr.js";
2
+ import { r as f } from "./html2canvas-B37RfnAd.js";
3
3
  function l(r, n) {
4
4
  for (var o = 0; o < n.length; o++) {
5
5
  const e = n[o];
@@ -1,4 +1,4 @@
1
- import { c as MQ } from "./index-CrlafZ0y.js";
1
+ import { c as MQ } from "./index-DLc-dsvr.js";
2
2
  var nt = { exports: {} };
3
3
  /*!
4
4
  * html2canvas 1.4.1 <https://html2canvas.hertzen.com>
@@ -1,6 +1,6 @@
1
- import { g as De, a as Ke, c as Te } from "./index-CrlafZ0y.js";
2
- import { j as Ge } from "./jspdf.es.min-DEtCEkBC.js";
3
- import { r as Be } from "./html2canvas-Bz1P596e.js";
1
+ import { g as De, a as Ke, c as Te } from "./index-DLc-dsvr.js";
2
+ import { j as Ge } from "./jspdf.es.min-P9H2mKOY.js";
3
+ import { r as Be } from "./html2canvas-B37RfnAd.js";
4
4
  function Ue(ge, we) {
5
5
  for (var me = 0; me < we.length; me++) {
6
6
  const ce = we[me];