@fuentis/phoenix-ui 0.0.9-alpha.572 → 0.0.9-alpha.573
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/fesm2022/fuentis-phoenix-ui.mjs +163 -29
- package/fesm2022/fuentis-phoenix-ui.mjs.map +1 -1
- package/index.d.ts +0 -4
- package/package.json +1 -1
|
@@ -74,9 +74,9 @@ import * as i14 from 'primeng/floatlabel';
|
|
|
74
74
|
import { FloatLabelModule } from 'primeng/floatlabel';
|
|
75
75
|
import * as i2$4 from 'primeng/selectbutton';
|
|
76
76
|
import { SelectButtonModule } from 'primeng/selectbutton';
|
|
77
|
-
import jsPDF from 'jspdf';
|
|
78
|
-
import autoTable from 'jspdf-autotable';
|
|
79
77
|
import * as XLSX from 'xlsx';
|
|
78
|
+
import pdfMake from 'pdfmake/build/pdfmake';
|
|
79
|
+
import pdfFonts from 'pdfmake/build/vfs_fonts';
|
|
80
80
|
import * as i1$2 from 'primeng/dynamicdialog';
|
|
81
81
|
import { DialogService } from 'primeng/dynamicdialog';
|
|
82
82
|
import * as i2$6 from 'primeng/datepicker';
|
|
@@ -2407,11 +2407,16 @@ function getNestedValue(obj, path) {
|
|
|
2407
2407
|
* - Removes HTML tags
|
|
2408
2408
|
* - Replaces and non-breaking spaces
|
|
2409
2409
|
* - Normalizes Unicode (keeps German umlauts and Serbian letters)
|
|
2410
|
+
* - Removes emoji characters (since PDF fonts don't support them properly)
|
|
2410
2411
|
*/
|
|
2411
2412
|
function sanitizeText(v) {
|
|
2412
2413
|
const s = (v ?? '').toString();
|
|
2413
2414
|
const noHtml = s.replace(/<[^>]*>/g, '');
|
|
2414
|
-
|
|
2415
|
+
// Remove emoji characters - they don't render properly in PDF
|
|
2416
|
+
// Emoji ranges: U+1F300–U+1F9FF, U+2600–U+26FF, U+2700–U+27BF, U+FE00–U+FE0F, U+1F900–U+1F9FF, U+1F1E0–U+1F1FF
|
|
2417
|
+
const emojiRegex = /[\u{1F300}-\u{1F9FF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}\u{FE00}-\u{FE0F}\u{1F900}-\u{1F9FF}\u{1F1E0}-\u{1F1FF}]/gu;
|
|
2418
|
+
const noEmoji = noHtml.replace(emojiRegex, '');
|
|
2419
|
+
return noEmoji
|
|
2415
2420
|
.replace(/ /g, ' ')
|
|
2416
2421
|
.replace(/\u00A0/g, ' ')
|
|
2417
2422
|
.normalize('NFKC')
|
|
@@ -2495,17 +2500,46 @@ function collapseInlineSpaces(s) {
|
|
|
2495
2500
|
.trim();
|
|
2496
2501
|
}
|
|
2497
2502
|
/**
|
|
2498
|
-
*
|
|
2499
|
-
|
|
2503
|
+
* Loads Noto Sans font from CDN for better emoji support
|
|
2504
|
+
*/
|
|
2505
|
+
async function loadNotoSansFont() {
|
|
2506
|
+
try {
|
|
2507
|
+
// Noto Sans has better Unicode and emoji support than Roboto
|
|
2508
|
+
// Try jsDelivr CDN first (more reliable)
|
|
2509
|
+
const response = await fetch('https://cdn.jsdelivr.net/gh/google/fonts@main/ofl/notosans/NotoSans-Regular.ttf');
|
|
2510
|
+
if (!response.ok) {
|
|
2511
|
+
return null;
|
|
2512
|
+
}
|
|
2513
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
2514
|
+
const bytes = new Uint8Array(arrayBuffer);
|
|
2515
|
+
let binary = '';
|
|
2516
|
+
const chunkSize = 8192;
|
|
2517
|
+
for (let i = 0; i < bytes.length; i += chunkSize) {
|
|
2518
|
+
const chunk = bytes.subarray(i, i + chunkSize);
|
|
2519
|
+
binary += String.fromCharCode.apply(null, Array.from(chunk));
|
|
2520
|
+
}
|
|
2521
|
+
return btoa(binary);
|
|
2522
|
+
}
|
|
2523
|
+
catch (error) {
|
|
2524
|
+
console.warn('Failed to load Noto Sans font from CDN:', error);
|
|
2525
|
+
return null;
|
|
2526
|
+
}
|
|
2527
|
+
}
|
|
2528
|
+
/**
|
|
2529
|
+
* Exports table rows to a PDF file using pdfmake.
|
|
2530
|
+
* - Uses pdfmake which has excellent Unicode support for Serbian characters (ć, č, đ, š, ž)
|
|
2500
2531
|
* - Respects only visible columns
|
|
2501
2532
|
* - Translates headers with provided translation function
|
|
2533
|
+
* - Attempts to load Noto Sans font for better emoji support
|
|
2502
2534
|
*/
|
|
2503
|
-
function exportRowsToPdf(columns, rows, columnTypeMap, columnTypeEnum, t, fileName = 'table.pdf', options = {}) {
|
|
2535
|
+
async function exportRowsToPdf(columns, rows, columnTypeMap, columnTypeEnum, t, fileName = 'table.pdf', options = {}) {
|
|
2504
2536
|
if (!columns?.length)
|
|
2505
2537
|
return;
|
|
2506
2538
|
const locale = options.locale || 'en-US';
|
|
2507
|
-
|
|
2508
|
-
const
|
|
2539
|
+
// Prepare headers
|
|
2540
|
+
const headers = columns.map((c) => sanitizeText(t(c.header)));
|
|
2541
|
+
// Prepare body rows
|
|
2542
|
+
const bodyRows = (rows ?? []).map((row) => columns.map((col) => {
|
|
2509
2543
|
const type = columnTypeMap[col.field] || col.columnType;
|
|
2510
2544
|
if (type === columnTypeEnum.LIST || type === columnTypeEnum.LIST_TAG) {
|
|
2511
2545
|
// make each item its own line; keep items intact (no bullets)
|
|
@@ -2521,28 +2555,126 @@ function exportRowsToPdf(columns, rows, columnTypeMap, columnTypeEnum, t, fileNa
|
|
|
2521
2555
|
const raw = String(getDisplayValue(row, col, columnTypeMap, columnTypeEnum, t, locale));
|
|
2522
2556
|
return sanitizeText(collapseInlineSpaces(raw));
|
|
2523
2557
|
}));
|
|
2524
|
-
|
|
2525
|
-
//
|
|
2526
|
-
|
|
2527
|
-
|
|
2558
|
+
// Set up pdfmake fonts - pdfmake has built-in support for Unicode characters
|
|
2559
|
+
// pdfFonts contains the vfs object directly
|
|
2560
|
+
if (pdfFonts && pdfFonts.pdfMake) {
|
|
2561
|
+
pdfMake.vfs = pdfFonts.pdfMake.vfs;
|
|
2562
|
+
}
|
|
2563
|
+
else if (pdfFonts && pdfFonts.vfs) {
|
|
2564
|
+
pdfMake.vfs = pdfFonts.vfs;
|
|
2565
|
+
}
|
|
2566
|
+
else {
|
|
2567
|
+
// Fallback: try to access vfs directly
|
|
2568
|
+
pdfMake.vfs = pdfFonts || {};
|
|
2569
|
+
}
|
|
2570
|
+
// Try to load Noto Sans font which has better emoji support
|
|
2571
|
+
// This is optional - if it fails, we'll use Roboto
|
|
2572
|
+
try {
|
|
2573
|
+
const notoSansFont = await loadNotoSansFont();
|
|
2574
|
+
if (notoSansFont) {
|
|
2575
|
+
// Add Noto Sans to pdfmake fonts
|
|
2576
|
+
if (!pdfMake.fonts) {
|
|
2577
|
+
pdfMake.fonts = {};
|
|
2578
|
+
}
|
|
2579
|
+
pdfMake.fonts.NotoSans = {
|
|
2580
|
+
normal: 'NotoSans-Regular.ttf',
|
|
2581
|
+
bold: 'NotoSans-Bold.ttf',
|
|
2582
|
+
italics: 'NotoSans-Italic.ttf',
|
|
2583
|
+
bolditalics: 'NotoSans-BoldItalic.ttf',
|
|
2584
|
+
};
|
|
2585
|
+
// Add font file to vfs
|
|
2586
|
+
pdfMake.vfs['NotoSans-Regular.ttf'] = notoSansFont;
|
|
2587
|
+
pdfMake.vfs['NotoSans-Bold.ttf'] = notoSansFont; // Use same font for bold
|
|
2588
|
+
}
|
|
2589
|
+
}
|
|
2590
|
+
catch (error) {
|
|
2591
|
+
console.warn('Failed to load Noto Sans font, using default Roboto:', error);
|
|
2592
|
+
}
|
|
2593
|
+
// Use 'auto' widths for pdfmake - it will automatically fit columns to page width
|
|
2594
|
+
// pdfmake works well with Serbian characters and handles auto-sizing better
|
|
2595
|
+
const columnWidths = columns.map((col) => {
|
|
2528
2596
|
const type = columnTypeMap[col.field] || col.columnType;
|
|
2529
2597
|
if (type === columnTypeEnum.LIST || type === columnTypeEnum.LIST_TAG) {
|
|
2530
|
-
|
|
2598
|
+
return 100; // Fixed width for LIST columns
|
|
2531
2599
|
}
|
|
2600
|
+
return 'auto'; // Auto width for other columns - pdfmake will fit them
|
|
2532
2601
|
});
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2602
|
+
// Build table body for pdfmake
|
|
2603
|
+
const tableBody = [
|
|
2604
|
+
// Header row
|
|
2605
|
+
headers.map((header) => ({
|
|
2606
|
+
text: header,
|
|
2607
|
+
style: 'tableHeader',
|
|
2608
|
+
bold: true,
|
|
2609
|
+
})),
|
|
2610
|
+
// Data rows
|
|
2611
|
+
...bodyRows.map((row) => row.map((cell, cellIdx) => {
|
|
2612
|
+
const col = columns[cellIdx];
|
|
2613
|
+
const type = columnTypeMap[col?.field] || col?.columnType;
|
|
2614
|
+
return {
|
|
2615
|
+
text: cell || '',
|
|
2616
|
+
style: 'tableCell',
|
|
2617
|
+
// Enable text wrapping for all cells
|
|
2618
|
+
noWrap: false,
|
|
2619
|
+
};
|
|
2620
|
+
})),
|
|
2621
|
+
];
|
|
2622
|
+
// PDF document definition
|
|
2623
|
+
const docDefinition = {
|
|
2624
|
+
pageOrientation: 'landscape',
|
|
2625
|
+
pageSize: 'A4',
|
|
2626
|
+
content: [
|
|
2627
|
+
{
|
|
2628
|
+
table: {
|
|
2629
|
+
headerRows: 1,
|
|
2630
|
+
widths: columnWidths,
|
|
2631
|
+
body: tableBody,
|
|
2632
|
+
},
|
|
2633
|
+
layout: {
|
|
2634
|
+
hLineWidth: () => 0, // Remove horizontal lines between rows
|
|
2635
|
+
vLineWidth: () => 0, // Remove vertical lines between columns
|
|
2636
|
+
paddingLeft: () => 3,
|
|
2637
|
+
paddingRight: () => 3,
|
|
2638
|
+
paddingTop: () => 3,
|
|
2639
|
+
paddingBottom: () => 3,
|
|
2640
|
+
// Alternating row colors: grey, white, grey, white...
|
|
2641
|
+
fillColor: (rowIndex, node, columnIndex) => {
|
|
2642
|
+
// Header row stays blue RGB(41, 128, 186)
|
|
2643
|
+
if (rowIndex === 0) {
|
|
2644
|
+
return [41, 128, 186];
|
|
2645
|
+
}
|
|
2646
|
+
// Data rows alternate: grey for odd rows (1, 3, 5...), white for even rows (2, 4, 6...)
|
|
2647
|
+
return (rowIndex - 1) % 2 === 0 ? '#f5f5f5' : null; // grey for odd rows, white (null) for even rows
|
|
2648
|
+
},
|
|
2649
|
+
},
|
|
2650
|
+
},
|
|
2651
|
+
],
|
|
2536
2652
|
styles: {
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2653
|
+
tableHeader: {
|
|
2654
|
+
fontSize: 11,
|
|
2655
|
+
bold: true,
|
|
2656
|
+
color: '#ffffff',
|
|
2657
|
+
fillColor: [41, 128, 186], // RGB(41, 128, 186)
|
|
2658
|
+
alignment: 'left',
|
|
2659
|
+
margin: [0, 5, 0, 5],
|
|
2660
|
+
},
|
|
2661
|
+
tableCell: {
|
|
2662
|
+
fontSize: 9,
|
|
2663
|
+
alignment: 'left',
|
|
2664
|
+
margin: [0, 5, 0, 5],
|
|
2665
|
+
// Enable text wrapping
|
|
2666
|
+
noWrap: false,
|
|
2667
|
+
},
|
|
2541
2668
|
},
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2669
|
+
defaultStyle: {
|
|
2670
|
+
// Use NotoSans if loaded, otherwise fallback to Roboto
|
|
2671
|
+
font: pdfMake.fonts?.NotoSans ? 'NotoSans' : 'Roboto',
|
|
2672
|
+
// NotoSans has better Unicode and emoji support than Roboto
|
|
2673
|
+
},
|
|
2674
|
+
pageMargins: [15, 30, 15, 30], // Reduced margins to give more space
|
|
2675
|
+
};
|
|
2676
|
+
// Generate and download PDF
|
|
2677
|
+
pdfMake.createPdf(docDefinition).download(fileName);
|
|
2546
2678
|
}
|
|
2547
2679
|
/* -------------------------- Export: Excel -------------------------- */
|
|
2548
2680
|
/**
|
|
@@ -2750,10 +2882,10 @@ class TableComponent {
|
|
|
2750
2882
|
initialSortFieldApplied = null;
|
|
2751
2883
|
/** True while initial sort is running to avoid "flash" of unsorted data */
|
|
2752
2884
|
initialSortLoading = false;
|
|
2753
|
-
/** How many skeleton rows to render while initial sort/data is loading */
|
|
2754
|
-
skeletonRowCount = 8;
|
|
2755
|
-
/** Array used by Angular @for (must be iterable) */
|
|
2756
|
-
skeletonRows = Array.from({ length: this.skeletonRowCount });
|
|
2885
|
+
// /** How many skeleton rows to render while initial sort/data is loading */
|
|
2886
|
+
// skeletonRowCount = 8;
|
|
2887
|
+
// /** Array used by Angular @for (must be iterable) */
|
|
2888
|
+
// skeletonRows = Array.from({ length: this.skeletonRowCount });
|
|
2757
2889
|
createSortWorkerInline() {
|
|
2758
2890
|
const code = `
|
|
2759
2891
|
const compareStringsNatural = (a,b) => a.localeCompare(b, undefined, { numeric:true, sensitivity:'base' });
|
|
@@ -3269,7 +3401,9 @@ class TableComponent {
|
|
|
3269
3401
|
const file = this.tableConfiguration?.key
|
|
3270
3402
|
? buildFileName(this.tableConfiguration.key, 'pdf')
|
|
3271
3403
|
: buildFileName('table', 'pdf');
|
|
3272
|
-
exportRowsToPdf(this.selectedColumns, this.tableData, this.columnTypeMap, this.columnTypeEnum, (k) => this.translateService.instant(k), file)
|
|
3404
|
+
exportRowsToPdf(this.selectedColumns, this.tableData, this.columnTypeMap, this.columnTypeEnum, (k) => this.translateService.instant(k), file).catch((error) => {
|
|
3405
|
+
console.error('Failed to export PDF:', error);
|
|
3406
|
+
});
|
|
3273
3407
|
return;
|
|
3274
3408
|
}
|
|
3275
3409
|
if (event?.action?.key === 'EXPORT_EXCEL') {
|