@fuentis/phoenix-ui 0.0.9-alpha.573 → 0.0.9-alpha.576
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.
|
@@ -2536,13 +2536,16 @@ async function exportRowsToPdf(columns, rows, columnTypeMap, columnTypeEnum, t,
|
|
|
2536
2536
|
if (!columns?.length)
|
|
2537
2537
|
return;
|
|
2538
2538
|
const locale = options.locale || 'en-US';
|
|
2539
|
-
|
|
2539
|
+
/* =========================
|
|
2540
|
+
HEADERS
|
|
2541
|
+
========================= */
|
|
2540
2542
|
const headers = columns.map((c) => sanitizeText(t(c.header)));
|
|
2541
|
-
|
|
2543
|
+
/* =========================
|
|
2544
|
+
BODY ROWS
|
|
2545
|
+
========================= */
|
|
2542
2546
|
const bodyRows = (rows ?? []).map((row) => columns.map((col) => {
|
|
2543
2547
|
const type = columnTypeMap[col.field] || col.columnType;
|
|
2544
2548
|
if (type === columnTypeEnum.LIST || type === columnTypeEnum.LIST_TAG) {
|
|
2545
|
-
// make each item its own line; keep items intact (no bullets)
|
|
2546
2549
|
const rawVal = getNestedValue(row, col.field);
|
|
2547
2550
|
const items = Array.isArray(rawVal)
|
|
2548
2551
|
? rawVal.map((x) => x?.name ?? x)
|
|
@@ -2550,13 +2553,14 @@ async function exportRowsToPdf(columns, rows, columnTypeMap, columnTypeEnum, t,
|
|
|
2550
2553
|
const cleaned = items
|
|
2551
2554
|
.map((it) => collapseInlineSpaces(String(it)))
|
|
2552
2555
|
.filter(Boolean);
|
|
2553
|
-
return sanitizeText(cleaned.join(',\n'));
|
|
2556
|
+
return sanitizeText(cleaned.join(',\n'));
|
|
2554
2557
|
}
|
|
2555
2558
|
const raw = String(getDisplayValue(row, col, columnTypeMap, columnTypeEnum, t, locale));
|
|
2556
2559
|
return sanitizeText(collapseInlineSpaces(raw));
|
|
2557
2560
|
}));
|
|
2558
|
-
|
|
2559
|
-
|
|
2561
|
+
/* =========================
|
|
2562
|
+
FONTS
|
|
2563
|
+
========================= */
|
|
2560
2564
|
if (pdfFonts && pdfFonts.pdfMake) {
|
|
2561
2565
|
pdfMake.vfs = pdfFonts.pdfMake.vfs;
|
|
2562
2566
|
}
|
|
@@ -2564,89 +2568,114 @@ async function exportRowsToPdf(columns, rows, columnTypeMap, columnTypeEnum, t,
|
|
|
2564
2568
|
pdfMake.vfs = pdfFonts.vfs;
|
|
2565
2569
|
}
|
|
2566
2570
|
else {
|
|
2567
|
-
// Fallback: try to access vfs directly
|
|
2568
2571
|
pdfMake.vfs = pdfFonts || {};
|
|
2569
2572
|
}
|
|
2570
|
-
// Try to load Noto Sans font which has better emoji support
|
|
2571
|
-
// This is optional - if it fails, we'll use Roboto
|
|
2572
2573
|
try {
|
|
2573
2574
|
const notoSansFont = await loadNotoSansFont();
|
|
2574
2575
|
if (notoSansFont) {
|
|
2575
|
-
|
|
2576
|
-
if (!pdfMake.fonts) {
|
|
2577
|
-
pdfMake.fonts = {};
|
|
2578
|
-
}
|
|
2576
|
+
pdfMake.fonts ??= {};
|
|
2579
2577
|
pdfMake.fonts.NotoSans = {
|
|
2580
2578
|
normal: 'NotoSans-Regular.ttf',
|
|
2581
2579
|
bold: 'NotoSans-Bold.ttf',
|
|
2582
2580
|
italics: 'NotoSans-Italic.ttf',
|
|
2583
2581
|
bolditalics: 'NotoSans-BoldItalic.ttf',
|
|
2584
2582
|
};
|
|
2585
|
-
// Add font file to vfs
|
|
2586
2583
|
pdfMake.vfs['NotoSans-Regular.ttf'] = notoSansFont;
|
|
2587
|
-
pdfMake.vfs['NotoSans-Bold.ttf'] = notoSansFont;
|
|
2584
|
+
pdfMake.vfs['NotoSans-Bold.ttf'] = notoSansFont;
|
|
2588
2585
|
}
|
|
2589
2586
|
}
|
|
2590
|
-
catch
|
|
2591
|
-
console.warn('
|
|
2592
|
-
}
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2587
|
+
catch {
|
|
2588
|
+
console.warn('NotoSans not loaded, fallback to Roboto');
|
|
2589
|
+
}
|
|
2590
|
+
/* =========================
|
|
2591
|
+
FIXED TABLE WIDTH LOGIC
|
|
2592
|
+
========================= */
|
|
2593
|
+
const fixedTableWidth = 750;
|
|
2594
|
+
const listColumnWidth = 80;
|
|
2595
|
+
const minColumnWidth = 40;
|
|
2596
|
+
const listIndexes = [];
|
|
2597
|
+
const regularIndexes = [];
|
|
2598
|
+
columns.forEach((col, i) => {
|
|
2596
2599
|
const type = columnTypeMap[col.field] || col.columnType;
|
|
2597
2600
|
if (type === columnTypeEnum.LIST || type === columnTypeEnum.LIST_TAG) {
|
|
2598
|
-
|
|
2601
|
+
listIndexes.push(i);
|
|
2602
|
+
}
|
|
2603
|
+
else {
|
|
2604
|
+
regularIndexes.push(i);
|
|
2599
2605
|
}
|
|
2600
|
-
return 'auto'; // Auto width for other columns - pdfmake will fit them
|
|
2601
2606
|
});
|
|
2602
|
-
|
|
2607
|
+
const reservedWidth = listIndexes.length * listColumnWidth;
|
|
2608
|
+
const availableWidth = fixedTableWidth - reservedWidth;
|
|
2609
|
+
const baseRegularWidth = regularIndexes.length > 0
|
|
2610
|
+
? Math.max(minColumnWidth, availableWidth / regularIndexes.length)
|
|
2611
|
+
: minColumnWidth;
|
|
2612
|
+
let columnWidths = columns.map((_, i) => listIndexes.includes(i) ? listColumnWidth : baseRegularWidth);
|
|
2613
|
+
/* === NORMALIZACIJA (TAČNO 750px) === */
|
|
2614
|
+
const regularSum = regularIndexes.reduce((sum, i) => sum + columnWidths[i], 0);
|
|
2615
|
+
if (regularSum > 0) {
|
|
2616
|
+
const scaleFactor = availableWidth / regularSum;
|
|
2617
|
+
console.log(scaleFactor);
|
|
2618
|
+
// 1. skaliranje + floor
|
|
2619
|
+
regularIndexes.forEach((i) => {
|
|
2620
|
+
columnWidths[i] = Math.floor(columnWidths[i] * scaleFactor);
|
|
2621
|
+
});
|
|
2622
|
+
// 2. korekcija razlike (1px po koloni)
|
|
2623
|
+
let diff = fixedTableWidth - columnWidths.reduce((sum, w) => sum + w, 0);
|
|
2624
|
+
let idx = 0;
|
|
2625
|
+
while (diff !== 0 && regularIndexes.length) {
|
|
2626
|
+
const i = regularIndexes[idx % regularIndexes.length];
|
|
2627
|
+
columnWidths[i] += diff > 0 ? 1 : -1;
|
|
2628
|
+
diff += diff > 0 ? -1 : 1;
|
|
2629
|
+
idx++;
|
|
2630
|
+
}
|
|
2631
|
+
}
|
|
2632
|
+
/* =========================
|
|
2633
|
+
TABLE BODY
|
|
2634
|
+
========================= */
|
|
2603
2635
|
const tableBody = [
|
|
2604
|
-
// Header row
|
|
2605
2636
|
headers.map((header) => ({
|
|
2606
2637
|
text: header,
|
|
2607
2638
|
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
2639
|
})),
|
|
2640
|
+
...bodyRows.map((row) => row.map((cell) => ({
|
|
2641
|
+
text: cell || '',
|
|
2642
|
+
style: 'tableCell',
|
|
2643
|
+
noWrap: false,
|
|
2644
|
+
}))),
|
|
2621
2645
|
];
|
|
2622
|
-
|
|
2646
|
+
console.log(columnWidths);
|
|
2647
|
+
/* =========================
|
|
2648
|
+
PDF DEFINITION
|
|
2649
|
+
========================= */
|
|
2623
2650
|
const docDefinition = {
|
|
2624
2651
|
pageOrientation: 'landscape',
|
|
2625
2652
|
pageSize: 'A4',
|
|
2653
|
+
pageMargins: [25, 30, 15, 30],
|
|
2626
2654
|
content: [
|
|
2627
2655
|
{
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2656
|
+
columns: [
|
|
2657
|
+
{
|
|
2658
|
+
width: fixedTableWidth,
|
|
2659
|
+
table: {
|
|
2660
|
+
headerRows: 1,
|
|
2661
|
+
widths: columnWidths,
|
|
2662
|
+
body: tableBody,
|
|
2663
|
+
},
|
|
2664
|
+
layout: {
|
|
2665
|
+
hLineWidth: () => 0,
|
|
2666
|
+
vLineWidth: () => 0,
|
|
2667
|
+
paddingLeft: () => 3,
|
|
2668
|
+
paddingRight: () => 3,
|
|
2669
|
+
paddingTop: () => 3,
|
|
2670
|
+
paddingBottom: () => 3,
|
|
2671
|
+
fillColor: (rowIndex) => rowIndex === 0
|
|
2672
|
+
? [41, 128, 186]
|
|
2673
|
+
: (rowIndex - 1) % 2 === 0
|
|
2674
|
+
? '#f5f5f5'
|
|
2675
|
+
: null,
|
|
2676
|
+
},
|
|
2648
2677
|
},
|
|
2649
|
-
|
|
2678
|
+
],
|
|
2650
2679
|
},
|
|
2651
2680
|
],
|
|
2652
2681
|
styles: {
|
|
@@ -2654,26 +2683,17 @@ async function exportRowsToPdf(columns, rows, columnTypeMap, columnTypeEnum, t,
|
|
|
2654
2683
|
fontSize: 11,
|
|
2655
2684
|
bold: true,
|
|
2656
2685
|
color: '#ffffff',
|
|
2657
|
-
fillColor: [41, 128, 186], // RGB(41, 128, 186)
|
|
2658
|
-
alignment: 'left',
|
|
2659
2686
|
margin: [0, 5, 0, 5],
|
|
2660
2687
|
},
|
|
2661
2688
|
tableCell: {
|
|
2662
2689
|
fontSize: 9,
|
|
2663
|
-
alignment: 'left',
|
|
2664
2690
|
margin: [0, 5, 0, 5],
|
|
2665
|
-
// Enable text wrapping
|
|
2666
|
-
noWrap: false,
|
|
2667
2691
|
},
|
|
2668
2692
|
},
|
|
2669
2693
|
defaultStyle: {
|
|
2670
|
-
// Use NotoSans if loaded, otherwise fallback to Roboto
|
|
2671
2694
|
font: pdfMake.fonts?.NotoSans ? 'NotoSans' : 'Roboto',
|
|
2672
|
-
// NotoSans has better Unicode and emoji support than Roboto
|
|
2673
2695
|
},
|
|
2674
|
-
pageMargins: [15, 30, 15, 30], // Reduced margins to give more space
|
|
2675
2696
|
};
|
|
2676
|
-
// Generate and download PDF
|
|
2677
2697
|
pdfMake.createPdf(docDefinition).download(fileName);
|
|
2678
2698
|
}
|
|
2679
2699
|
/* -------------------------- Export: Excel -------------------------- */
|