@fuentis/phoenix-ui 0.0.9-alpha.367 → 0.0.9-alpha.369

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.
@@ -2567,8 +2567,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImpo
2567
2567
  }] });
2568
2568
 
2569
2569
  /**
2570
- * Splits table actions into context-specific arrays (global, row, bulk, more).
2571
- * This controls where buttons will appear (toolbar, row menu, etc.).
2570
+ * Split actions by context (controls placement in toolbar/rows).
2572
2571
  */
2573
2572
  function resolveActions(value) {
2574
2573
  const transformed = {
@@ -2602,7 +2601,7 @@ function resolveActions(value) {
2602
2601
  }
2603
2602
  /* ----------------------------- Helpers ----------------------------- */
2604
2603
  /**
2605
- * Safely retrieves nested object property using dot notation.
2604
+ * Safe nested property access via dot notation.
2606
2605
  * Example: "user.address.city" → row.user.address.city
2607
2606
  */
2608
2607
  function getNestedValue(obj, path) {
@@ -2627,10 +2626,10 @@ function getNestedValue(obj, path) {
2627
2626
  }
2628
2627
  }
2629
2628
  /**
2630
- * Sanitizes text:
2631
- * - Removes HTML tags
2632
- * - Replaces   and non-breaking spaces
2633
- * - Normalizes Unicode (keeps German umlauts and Serbian letters)
2629
+ * Normalize text for export:
2630
+ * - Strip HTML
2631
+ * - Replace NBSPs
2632
+ * - Normalize Unicode (keeps diacritics/umlauts)
2634
2633
  */
2635
2634
  function sanitizeText(v) {
2636
2635
  const s = (v ?? '').toString();
@@ -2642,14 +2641,14 @@ function sanitizeText(v) {
2642
2641
  .trim();
2643
2642
  }
2644
2643
  /**
2645
- * Checks if a CSV value must be quoted (contains delimiter, quotes or newlines).
2644
+ * Quote CSV values when needed (delimiter, quotes, newlines).
2646
2645
  */
2647
2646
  function needsQuotesCSV(value, delimiter) {
2648
2647
  const pattern = new RegExp(`[\"\\n${delimiter === ',' ? ',' : ';'}]`);
2649
2648
  return pattern.test(value);
2650
2649
  }
2651
2650
  /**
2652
- * Formats a date value using Angular DatePipe and the provided locale.
2651
+ * Locale-aware date formatting using Angular DatePipe.
2653
2652
  */
2654
2653
  function formatDateValue(val, pattern, locale) {
2655
2654
  try {
@@ -2664,10 +2663,10 @@ function formatDateValue(val, pattern, locale) {
2664
2663
  }
2665
2664
  /* ------------------------- Display resolver ------------------------ */
2666
2665
  /**
2667
- * Converts raw row values into human-readable strings for export.
2668
- * Handles various column types: DATE, LIST, BOOLEAN, etc.
2666
+ * Convert raw row values into exportable strings.
2667
+ * Supports DATE/LIST/BOOLEAN/etc. and CSV/PDF specific rendering.
2669
2668
  */
2670
- function getDisplayValue(row, col, columnTypeMap, columnTypeEnum, t, locale = 'en-US') {
2669
+ function getDisplayValue(row, col, columnTypeMap, columnTypeEnum, t, locale = 'en-US', forCsv = false, forPdf = false) {
2671
2670
  const field = col.field;
2672
2671
  const type = columnTypeMap[field] || col.columnType;
2673
2672
  const val = getNestedValue(row, field);
@@ -2680,15 +2679,20 @@ function getDisplayValue(row, col, columnTypeMap, columnTypeEnum, t, locale = 'e
2680
2679
  return formatDateValue(val, 'dd.MM.yyyy', locale);
2681
2680
  case columnTypeEnum.TAG:
2682
2681
  return (val?.name ?? val)?.toString();
2683
- case columnTypeEnum.LIST_TAG:
2684
2682
  case columnTypeEnum.LIST:
2685
- return Array.isArray(val)
2686
- ? val.map((x) => (x?.name ?? x)).join(', ')
2687
- : String(val);
2683
+ case columnTypeEnum.LIST_TAG: {
2684
+ if (!Array.isArray(val))
2685
+ return String(val);
2686
+ const items = val.map((x) => (x?.name ?? x));
2687
+ if (forCsv)
2688
+ return items.join('\n'); // multi-line cell in CSV
2689
+ if (forPdf)
2690
+ return '• ' + items.join('\n• '); // bullet list in PDF
2691
+ return items.join(', '); // UI default
2692
+ }
2688
2693
  case columnTypeEnum.OBJ_TAG:
2689
2694
  return (val?.value ?? val)?.toString();
2690
2695
  case columnTypeEnum.BOOLEAN: {
2691
- // Translate YES/NO if translation function is provided
2692
2696
  const yes = t ? t('ACTION.YES') : 'Yes';
2693
2697
  const no = t ? t('ACTION.NO') : 'No';
2694
2698
  return (val === true || val === 'true') ? yes : no;
@@ -2704,40 +2708,64 @@ function getDisplayValue(row, col, columnTypeMap, columnTypeEnum, t, locale = 'e
2704
2708
  return String(val);
2705
2709
  }
2706
2710
  }
2707
- function trimExcelLineBreaks(s) {
2711
+ /**
2712
+ * Clean multi-line content for CSV while preserving line breaks:
2713
+ * - Normalize all separators to '\n'
2714
+ * - Remove leading/trailing blank lines and indentation
2715
+ * - Collapse multiple blank lines
2716
+ */
2717
+ function cleanMultilineForCsv(s) {
2718
+ if (!s)
2719
+ return '';
2708
2720
  return s
2709
- .replace(/^[\r\n]+/, '') // remove leading line breaks
2710
- .replace(/[\r\n]+$/, '') // remove trailing line breaks
2711
- .replace(/(\r?\n){2,}/g, '\n'); // collapse multiple to a single
2721
+ .replace(/\u2028|\u2029|\r\n|\r/g, '\n')
2722
+ .replace(/^[\s\u00A0]+/g, '')
2723
+ .replace(/[\s\u00A0]+$/g, '')
2724
+ .replace(/^(?:\s*\n)+/g, '')
2725
+ .replace(/(?:\n\s*)+$/g, '')
2726
+ .split('\n')
2727
+ .map(line => line.replace(/^[\s\u00A0]+/, ''))
2728
+ .join('\n')
2729
+ .replace(/(\n\s*){2,}/g, '\n');
2712
2730
  }
2713
2731
  /**
2714
- * Exports table rows to a PDF file.
2715
- * - Uses jsPDF + autoTable
2716
- * - Respects only visible columns
2717
- * - Translates headers with provided translation function
2732
+ * Export rows to PDF (jsPDF + autoTable).
2733
+ * - Uses visible columns only
2734
+ * - Translates headers via provided translator
2735
+ * - Wraps the “Scope” column content for long lists
2718
2736
  */
2719
2737
  function exportRowsToPdf(columns, rows, columnTypeMap, columnTypeEnum, t, fileName = 'table.pdf', options = {}) {
2720
2738
  if (!columns?.length)
2721
2739
  return;
2722
2740
  const locale = options.locale || 'en-US';
2741
+ const scopeIdx = columns.findIndex(c => (c.header || '').toLowerCase().includes('scope'));
2723
2742
  const head = [columns.map(c => sanitizeText(t(c.header)))];
2724
- const body = (rows ?? []).map(row => columns.map(col => sanitizeText(getDisplayValue(row, col, columnTypeMap, columnTypeEnum, t, locale))));
2725
- // jsPDF default font supports Latin-1 (English, German, Serbian Latin characters).
2743
+ const body = (rows ?? []).map(row => columns.map(col => {
2744
+ const forPdf = true;
2745
+ const raw = getDisplayValue(row, col, columnTypeMap, columnTypeEnum, t, locale, false, forPdf);
2746
+ return sanitizeText(raw);
2747
+ }));
2726
2748
  const doc = new jsPDF({ orientation: 'landscape', unit: 'pt', format: 'A4' });
2727
2749
  autoTable(doc, {
2728
2750
  head,
2729
2751
  body,
2730
- styles: { fontSize: 9, cellPadding: 5, overflow: 'linebreak' },
2731
- margin: { top: 36, right: 24, bottom: 36, left: 24 },
2752
+ styles: {
2753
+ fontSize: 9,
2754
+ cellPadding: 5,
2755
+ overflow: 'linebreak', // this breaks long/multi-line text
2756
+ valign: 'top' // align multi-line cells nicely
2757
+ },
2758
+ margin: { top: 36, right: 24, bottom: 36, left: 24 }
2732
2759
  });
2733
2760
  doc.save(fileName);
2734
2761
  }
2735
2762
  /* -------------------------- Export: CSV ---------------------------- */
2736
2763
  /**
2737
- * Exports table rows to a CSV file.
2738
- * - Includes only visible columns
2739
- * - Translates headers via provided translation function
2740
- * - Escapes quotes and adds UTF-8 BOM (so Excel reads special chars correctly)
2764
+ * Export rows to CSV.
2765
+ * - Uses visible columns only
2766
+ * - Translates headers
2767
+ * - Adds UTF-8 BOM so Excel renders diacritics/umlauts correctly
2768
+ * - Preserves multi-line cells (LIST → each item on a new line)
2741
2769
  */
2742
2770
  function exportRowsToCsv(columns, rows, columnTypeMap, columnTypeEnum, t, fileName = 'table.csv', options = {}) {
2743
2771
  if (!columns?.length)
@@ -2746,14 +2774,13 @@ function exportRowsToCsv(columns, rows, columnTypeMap, columnTypeEnum, t, fileNa
2746
2774
  const delimiter = options.delimiter || ',';
2747
2775
  const headers = columns.map(c => sanitizeText(t(c.header)));
2748
2776
  const lines = (rows ?? []).map(row => columns.map(col => {
2749
- const raw = getDisplayValue(row, col, columnTypeMap, columnTypeEnum, t, locale);
2750
- // keep multiline, but remove useless blank line at start/end
2751
- const v = trimExcelLineBreaks(sanitizeText(raw));
2777
+ const raw = getDisplayValue(row, col, columnTypeMap, columnTypeEnum, t, locale, true /* forCsv */);
2778
+ const v = cleanMultilineForCsv(sanitizeText(raw));
2752
2779
  const safe = v.replace(/"/g, '""'); // escape double quotes
2753
2780
  return needsQuotesCSV(v, delimiter) ? `"${safe}"` : safe;
2754
2781
  }).join(delimiter));
2755
2782
  const csv = [headers.join(delimiter), ...lines].join('\n');
2756
- // Add UTF-8 BOM Excel correctly recognizes UTF-8 (handles č, ć, š, đ, ž, ä, ö, ü, ß, etc.)
2783
+ // Prepend BOM so Excel opens as UTF-8 (č, ć, š, đ, ž, ä, ö, ü, ß, )
2757
2784
  const BOM = '\uFEFF';
2758
2785
  const blob = new Blob([BOM + csv], { type: 'text/csv;charset=utf-8;' });
2759
2786
  const a = document.createElement('a');
@@ -2767,7 +2794,7 @@ function exportRowsToCsv(columns, rows, columnTypeMap, columnTypeEnum, t, fileNa
2767
2794
  }
2768
2795
  /* --------------------------- File name ----------------------------- */
2769
2796
  /**
2770
- * Builds a file name with pattern: tableKey_YYYY-MM-DD_HH-mm.ext
2797
+ * Build file name as: tableKey_YYYY-MM-DD_HH-mm.ext
2771
2798
  * Example: risks_2025-09-10_14-32.csv
2772
2799
  */
2773
2800
  function buildFileName(baseKey, ext) {