@harbortouch/skytab-analytics-report-utils 0.41.11 → 0.41.13

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.
@@ -2523,16 +2523,16 @@ var FIELDS11 = {
2523
2523
  groupByName: { type: "string" },
2524
2524
  rowType: { type: "string" },
2525
2525
  locationName: { type: "string", size: 220, columnKey: "locationName" },
2526
- employeeName: { type: "string", size: 220, columnKey: "employeeName" },
2527
- empId: {
2526
+ employeeName: {
2528
2527
  type: "string",
2529
- size: 160,
2530
- columnKey: "employeeId",
2528
+ size: 220,
2529
+ columnKey: "employeeName",
2531
2530
  footerCalculation: { type: "label", label: "table.total" }
2532
2531
  },
2532
+ empId: { type: "string", size: 160, columnKey: "employeeId" },
2533
2533
  payrollId: { type: "string", size: 160, columnKey: "payrollId" },
2534
2534
  jobName: { type: "string", size: 160, columnKey: "employeeJob" },
2535
- paidNormalHours: { type: "number", columnKey: "paidNormalHours", footerCalculation: { type: "sum" } },
2535
+ paidNormalHours: { type: "fixedNumber", columnKey: "paidNormalHours", footerCalculation: { type: "sum" } },
2536
2536
  normalPay: { type: "money", columnKey: "normalPay", footerCalculation: { type: "sum" } },
2537
2537
  overtimePay: { type: "money", columnKey: "overtimePay", footerCalculation: { type: "sum" } },
2538
2538
  doubleOvertimePay: { type: "money", columnKey: "doubleOvertimePay", footerCalculation: { type: "sum" } },
@@ -2569,7 +2569,7 @@ var VISIBLE_COLUMNS3 = [
2569
2569
  "minimumWageAdjustment",
2570
2570
  "totalPay"
2571
2571
  ];
2572
- var AVAILABLE_COLUMNS3 = ["empId", ...VISIBLE_COLUMNS3];
2572
+ var AVAILABLE_COLUMNS3 = [...VISIBLE_COLUMNS3];
2573
2573
  var payrollConfig = {
2574
2574
  fields: FIELDS11,
2575
2575
  availableColumns: AVAILABLE_COLUMNS3,
@@ -1,5 +1,5 @@
1
- import { a as ExportSection } from '../../types-JAEAu4KX.cjs';
2
- export { E as XlsxFilter, b as XlsxTable, c as XlsxTableColumn } from '../../types-JAEAu4KX.cjs';
1
+ import { a as ExportSection } from '../../types-D3IyO__4.cjs';
2
+ export { E as XlsxFilter, b as XlsxTable, c as XlsxTableColumn } from '../../types-D3IyO__4.cjs';
3
3
 
4
4
  declare class ExcelExporter {
5
5
  generate(content: {
@@ -1,5 +1,5 @@
1
- import { a as ExportSection } from '../../types-JAEAu4KX.js';
2
- export { E as XlsxFilter, b as XlsxTable, c as XlsxTableColumn } from '../../types-JAEAu4KX.js';
1
+ import { a as ExportSection } from '../../types-D3IyO__4.js';
2
+ export { E as XlsxFilter, b as XlsxTable, c as XlsxTableColumn } from '../../types-D3IyO__4.js';
3
3
 
4
4
  declare class ExcelExporter {
5
5
  generate(content: {
@@ -2693,16 +2693,16 @@ var FIELDS11 = {
2693
2693
  groupByName: { type: "string" },
2694
2694
  rowType: { type: "string" },
2695
2695
  locationName: { type: "string", size: 220, columnKey: "locationName" },
2696
- employeeName: { type: "string", size: 220, columnKey: "employeeName" },
2697
- empId: {
2696
+ employeeName: {
2698
2697
  type: "string",
2699
- size: 160,
2700
- columnKey: "employeeId",
2698
+ size: 220,
2699
+ columnKey: "employeeName",
2701
2700
  footerCalculation: { type: "label", label: "table.total" }
2702
2701
  },
2702
+ empId: { type: "string", size: 160, columnKey: "employeeId" },
2703
2703
  payrollId: { type: "string", size: 160, columnKey: "payrollId" },
2704
2704
  jobName: { type: "string", size: 160, columnKey: "employeeJob" },
2705
- paidNormalHours: { type: "number", columnKey: "paidNormalHours", footerCalculation: { type: "sum" } },
2705
+ paidNormalHours: { type: "fixedNumber", columnKey: "paidNormalHours", footerCalculation: { type: "sum" } },
2706
2706
  normalPay: { type: "money", columnKey: "normalPay", footerCalculation: { type: "sum" } },
2707
2707
  overtimePay: { type: "money", columnKey: "overtimePay", footerCalculation: { type: "sum" } },
2708
2708
  doubleOvertimePay: { type: "money", columnKey: "doubleOvertimePay", footerCalculation: { type: "sum" } },
@@ -2739,7 +2739,7 @@ var VISIBLE_COLUMNS3 = [
2739
2739
  "minimumWageAdjustment",
2740
2740
  "totalPay"
2741
2741
  ];
2742
- var AVAILABLE_COLUMNS3 = ["empId", ...VISIBLE_COLUMNS3];
2742
+ var AVAILABLE_COLUMNS3 = [...VISIBLE_COLUMNS3];
2743
2743
  var payrollConfig = {
2744
2744
  fields: FIELDS11,
2745
2745
  availableColumns: AVAILABLE_COLUMNS3,
@@ -4146,7 +4146,10 @@ var ExportBuilder = class {
4146
4146
  renderTableContent(config, reportData, parameters) {
4147
4147
  const data = this.getDataForConfig(reportData, config);
4148
4148
  const { columns, headers, columnTypes } = this.resolveColumnsAndHeaders(parameters, config);
4149
- const tableColumns = columns.map((col, i) => ({ header: headers[i], key: col }));
4149
+ const tableColumns = columns.map((col, i) => {
4150
+ const size = config.fields[col]?.size;
4151
+ return { header: headers[i], key: col, ...size !== void 0 ? { size } : {} };
4152
+ });
4150
4153
  const rows = data.filter((row) => typeof row === "object" && row !== null).map((row) => this.formatRow(row, columns, columnTypes, row));
4151
4154
  if (config.hasFooter) {
4152
4155
  const totalsRow = this.buildTotalsRow(data, config);
@@ -1,5 +1,5 @@
1
1
  import { R as ReportType, A as AnalyticsField } from '../report-Dj8UU5d_.cjs';
2
- import { E as ExportFilter, R as ReportMetadata, a as ExportSection } from '../types-JAEAu4KX.cjs';
2
+ import { E as ExportFilter, R as ReportMetadata, a as ExportSection } from '../types-D3IyO__4.cjs';
3
3
 
4
4
  declare function resolveRawFiltersToExportFilters(rawFilters: Record<string, (string | number)[] | undefined>, locale: string, reportType?: ReportType): ExportFilter[];
5
5
 
@@ -1,5 +1,5 @@
1
1
  import { R as ReportType, A as AnalyticsField } from '../report-Dj8UU5d_.js';
2
- import { E as ExportFilter, R as ReportMetadata, a as ExportSection } from '../types-JAEAu4KX.js';
2
+ import { E as ExportFilter, R as ReportMetadata, a as ExportSection } from '../types-D3IyO__4.js';
3
3
 
4
4
  declare function resolveRawFiltersToExportFilters(rawFilters: Record<string, (string | number)[] | undefined>, locale: string, reportType?: ReportType): ExportFilter[];
5
5
 
@@ -8,7 +8,7 @@ import {
8
8
  getReportFormattingLocaleOptions,
9
9
  getReportName,
10
10
  resolveTranslate
11
- } from "../chunk-UUKHJDV3.js";
11
+ } from "../chunk-7CBVZY3Y.js";
12
12
 
13
13
  // src/utils/filter-resolver.ts
14
14
  var ANALYTICS_FIELDS = /* @__PURE__ */ new Set([
@@ -197,7 +197,10 @@ var ExportBuilder = class {
197
197
  renderTableContent(config, reportData, parameters) {
198
198
  const data = this.getDataForConfig(reportData, config);
199
199
  const { columns, headers, columnTypes } = this.resolveColumnsAndHeaders(parameters, config);
200
- const tableColumns = columns.map((col, i) => ({ header: headers[i], key: col }));
200
+ const tableColumns = columns.map((col, i) => {
201
+ const size = config.fields[col]?.size;
202
+ return { header: headers[i], key: col, ...size !== void 0 ? { size } : {} };
203
+ });
201
204
  const rows = data.filter((row) => typeof row === "object" && row !== null).map((row) => this.formatRow(row, columns, columnTypes, row));
202
205
  if (config.hasFooter) {
203
206
  const totalsRow = this.buildTotalsRow(data, config);
@@ -207,7 +207,14 @@ var PdfExporter = class {
207
207
  const dataFontSize = columnCount > 13 ? 5 : columnCount > 10 ? 6 : columnCount > 7 ? 7 : 8;
208
208
  const headerWidthSlack = 2;
209
209
  const headerMinWidths = /* @__PURE__ */ new Map();
210
+ const cssPixelsToPoints = 0.75;
211
+ const boundedColumns = /* @__PURE__ */ new Set();
210
212
  columns.forEach((col) => {
213
+ if (col.size !== void 0 && Number.isFinite(col.size) && col.size > 0) {
214
+ col.width = col.size * cssPixelsToPoints;
215
+ boundedColumns.add(col);
216
+ return;
217
+ }
211
218
  doc.font(FONT_BOLD).fontSize(headerFontSize);
212
219
  const headerTextWidth = doc.widthOfString(col.header);
213
220
  const headerMinWidth = Math.max(...col.header.split(" ").map((w) => doc.widthOfString(w)));
@@ -226,49 +233,50 @@ var PdfExporter = class {
226
233
  headerMinWidths.set(col, headerMinWidth + TABLE_CELL_PADDING * 2 + headerWidthSlack);
227
234
  });
228
235
  const usableWidth = doc.page.width - doc.page.margins.left - doc.page.margins.right;
236
+ const minimumColumnWidth = Math.min(MIN_COLUMN_WIDTH, usableWidth / columnCount);
229
237
  const totalColumnWidth = columns.reduce((sum, c) => sum + (c.width ?? MIN_COLUMN_WIDTH), 0);
230
238
  if (totalColumnWidth > usableWidth) {
231
239
  const scale = usableWidth / totalColumnWidth;
232
240
  columns.forEach((c) => {
233
- const headerMin = headerMinWidths.get(c) ?? MIN_COLUMN_WIDTH;
234
- c.width = Math.max(Math.floor((c.width ?? MIN_COLUMN_WIDTH) * scale), headerMin, MIN_COLUMN_WIDTH);
241
+ const width = c.width ?? MIN_COLUMN_WIDTH;
242
+ const headerMin = headerMinWidths.get(c) ?? minimumColumnWidth;
243
+ const minimumWidth = Math.min(width, Math.max(headerMin, minimumColumnWidth));
244
+ c.width = Math.max(Math.floor(width * scale), minimumWidth);
235
245
  });
236
- let excess = columns.reduce((sum, c) => sum + (c.width ?? MIN_COLUMN_WIDTH), 0) - usableWidth;
237
- for (let i = columns.length - 1; i >= 0 && excess > 0; i--) {
238
- const col = columns[i];
239
- const available = (col.width ?? MIN_COLUMN_WIDTH) - MIN_COLUMN_WIDTH;
240
- const trim = Math.min(excess, available);
241
- if (trim > 0) {
242
- col.width = (col.width ?? MIN_COLUMN_WIDTH) - trim;
243
- excess -= trim;
246
+ const excess = columns.reduce((sum, c) => sum + (c.width ?? MIN_COLUMN_WIDTH), 0) - usableWidth;
247
+ if (excess > 0) {
248
+ const reducibleWidth = columns.reduce(
249
+ (sum, c) => sum + Math.max((c.width ?? MIN_COLUMN_WIDTH) - minimumColumnWidth, 0),
250
+ 0
251
+ );
252
+ if (reducibleWidth > 0) {
253
+ columns.forEach((c) => {
254
+ const width = c.width ?? MIN_COLUMN_WIDTH;
255
+ const available = Math.max(width - minimumColumnWidth, 0);
256
+ c.width = width - excess * (available / reducibleWidth);
257
+ });
244
258
  }
245
259
  }
246
260
  } else if (totalColumnWidth < usableWidth) {
247
- const scale = usableWidth / totalColumnWidth;
248
- columns.forEach((c) => {
249
- c.width = Math.floor((c.width ?? MIN_COLUMN_WIDTH) * scale);
250
- });
251
- const expanded = columns.reduce((sum, c) => sum + (c.width ?? 0), 0);
252
- columns[columns.length - 1].width = (columns[columns.length - 1].width ?? 0) + (usableWidth - expanded);
261
+ const expandableColumns = columns.filter((c) => !boundedColumns.has(c));
262
+ const expandableWidth = expandableColumns.reduce((sum, c) => sum + (c.width ?? MIN_COLUMN_WIDTH), 0);
263
+ if (expandableWidth > 0) {
264
+ const scale = (expandableWidth + usableWidth - totalColumnWidth) / expandableWidth;
265
+ expandableColumns.forEach((c) => {
266
+ c.width = Math.floor((c.width ?? MIN_COLUMN_WIDTH) * scale);
267
+ });
268
+ const expanded = columns.reduce((sum, c) => sum + (c.width ?? 0), 0);
269
+ const lastExpandableColumn = expandableColumns[expandableColumns.length - 1];
270
+ lastExpandableColumn.width = (lastExpandableColumn.width ?? 0) + (usableWidth - expanded);
271
+ }
253
272
  }
254
273
  const tableWidth = columns.reduce((sum, c) => sum + (c.width ?? MIN_COLUMN_WIDTH), 0);
255
274
  const pageBottom = doc.page.height - doc.page.margins.bottom;
256
- const calculateRowHeight = (row, isHeader = false) => {
257
- const fontSize = isHeader ? headerFontSize : dataFontSize;
258
- doc.font(isHeader ? FONT_BOLD : FONT_REGULAR).fontSize(fontSize);
259
- let maxLines = 1;
260
- columns.forEach((col) => {
261
- const cellValue = isHeader ? col.header : row?.[col.key] !== void 0 ? String(row[col.key]) : "";
262
- const textWidth = doc.widthOfString(cellValue);
263
- const availableWidth = (col.width ?? MIN_COLUMN_WIDTH) - TABLE_CELL_PADDING * 2;
264
- const lines = Math.ceil(textWidth / availableWidth);
265
- if (lines > maxLines) {
266
- maxLines = lines;
267
- }
268
- });
269
- return Math.max(maxLines * (fontSize + 2) + TABLE_CELL_PADDING * 2, DEFAULT_ROW_HEIGHT);
275
+ const calculateRowHeight = (isHeader = false) => {
276
+ doc.font(isHeader ? FONT_BOLD : FONT_REGULAR).fontSize(isHeader ? headerFontSize : dataFontSize);
277
+ return Math.max(doc.currentLineHeight(true) + TABLE_CELL_PADDING * 2, DEFAULT_ROW_HEIGHT);
270
278
  };
271
- const headerHeight = calculateRowHeight(null, true);
279
+ const headerHeight = calculateRowHeight(true);
272
280
  const drawTableHeader = (y) => this.drawHeader(doc, columns, y, tableWidth, headerHeight, TABLE_CELL_PADDING, headerFontSize, MIN_COLUMN_WIDTH);
273
281
  let tableStartY = startY;
274
282
  if (tableStartY + headerHeight > pageBottom) {
@@ -278,7 +286,7 @@ var PdfExporter = class {
278
286
  let currentY = drawTableHeader(tableStartY);
279
287
  doc.font(FONT_REGULAR).fontSize(dataFontSize);
280
288
  rows.forEach((row, rowIndex) => {
281
- const currentRowHeight = calculateRowHeight(row, false);
289
+ const currentRowHeight = calculateRowHeight();
282
290
  if (currentY + currentRowHeight > pageBottom) {
283
291
  doc.addPage();
284
292
  currentY = drawTableHeader(doc.page.margins.top);
@@ -301,6 +309,28 @@ var PdfExporter = class {
301
309
  doc.strokeColor(HEADER_RULE_COLOR).lineWidth(HEADER_RULE_WIDTH).moveTo(left, closingRuleY).lineTo(left + tableWidth, closingRuleY).stroke();
302
310
  return closingRuleY;
303
311
  }
312
+ truncateTextToWidth(doc, text, availableWidth) {
313
+ if (doc.widthOfString(text) <= availableWidth) {
314
+ return text;
315
+ }
316
+ const ellipsis = "\u2026";
317
+ if (doc.widthOfString(ellipsis) > availableWidth) {
318
+ return "";
319
+ }
320
+ const characters = Array.from(text);
321
+ let low = 0;
322
+ let high = characters.length;
323
+ while (low < high) {
324
+ const middle = Math.ceil((low + high) / 2);
325
+ const candidate = `${characters.slice(0, middle).join("").trimEnd()}${ellipsis}`;
326
+ if (doc.widthOfString(candidate) <= availableWidth) {
327
+ low = middle;
328
+ } else {
329
+ high = middle - 1;
330
+ }
331
+ }
332
+ return `${characters.slice(0, low).join("").trimEnd()}${ellipsis}`;
333
+ }
304
334
  drawHeader(doc, columns, startY, tableWidth, headerHeight, cellPadding, headerFontSize, minColumnWidth) {
305
335
  const left = doc.page.margins.left;
306
336
  doc.rect(left, startY, tableWidth, headerHeight).fill(HEADER_BACKGROUND_COLOR);
@@ -310,12 +340,15 @@ var PdfExporter = class {
310
340
  const headerLineHeight = doc.currentLineHeight(true);
311
341
  const headerTextY = startY + Math.max((headerHeight - headerLineHeight) / 2, 0);
312
342
  columns.forEach((col) => {
313
- doc.text(col.header, xPosition + cellPadding, headerTextY, {
314
- width: (col.width ?? minColumnWidth) - cellPadding * 2,
343
+ const innerWidth = (col.width ?? minColumnWidth) - cellPadding * 2;
344
+ const bounded = col.size !== void 0 && Number.isFinite(col.size) && col.size > 0;
345
+ const headerText = bounded ? this.truncateTextToWidth(doc, col.header, innerWidth) : col.header;
346
+ doc.text(headerText, xPosition + cellPadding, headerTextY, {
347
+ width: innerWidth,
315
348
  height: headerLineHeight,
316
349
  align: "left",
317
350
  lineBreak: false,
318
- ellipsis: true
351
+ ellipsis: !bounded
319
352
  });
320
353
  xPosition += col.width ?? minColumnWidth;
321
354
  });
@@ -336,12 +369,15 @@ var PdfExporter = class {
336
369
  const rawValue = row[col.key];
337
370
  const cellValue = typeof rawValue === "string" || typeof rawValue === "number" || typeof rawValue === "boolean" ? String(rawValue) : "";
338
371
  const isNumeric = typeof rawValue === "number" || typeof rawValue === "string" && rawValue !== "" && !isNaN(Number(rawValue));
339
- doc.text(cellValue, xPosition + cellPadding, dataTextY, {
340
- width: (col.width ?? minColumnWidth) - cellPadding * 2,
372
+ const innerWidth = (col.width ?? minColumnWidth) - cellPadding * 2;
373
+ const bounded = col.size !== void 0 && Number.isFinite(col.size) && col.size > 0;
374
+ const rowText = bounded ? this.truncateTextToWidth(doc, cellValue, innerWidth) : cellValue;
375
+ doc.text(rowText, xPosition + cellPadding, dataTextY, {
376
+ width: innerWidth,
341
377
  height: dataLineHeight,
342
378
  align: isNumeric ? "right" : "left",
343
379
  lineBreak: false,
344
- ellipsis: true
380
+ ellipsis: !bounded
345
381
  });
346
382
  xPosition += col.width ?? minColumnWidth;
347
383
  if (i < columns.length - 1) {
@@ -1,4 +1,4 @@
1
- import { a as ExportSection, E as ExportFilter, b as ExportTable, c as ExportTableColumn } from '../../types-JAEAu4KX.cjs';
1
+ import { a as ExportSection, E as ExportFilter, b as ExportTable, c as ExportTableColumn } from '../../types-D3IyO__4.cjs';
2
2
 
3
3
  type MetaDataValue = ExportFilter[] | string;
4
4
  declare class PdfExporter {
@@ -10,6 +10,7 @@ declare class PdfExporter {
10
10
  drawSectionTitle(doc: PDFKit.PDFDocument, title: string, startY: number): number;
11
11
  drawMetaData(doc: PDFKit.PDFDocument, metaData: Record<string, MetaDataValue>, startY: number): number;
12
12
  drawTable(doc: PDFKit.PDFDocument, table: ExportTable, startY: number): number;
13
+ private truncateTextToWidth;
13
14
  drawHeader(doc: PDFKit.PDFDocument, columns: ExportTableColumn[], startY: number, tableWidth: number, headerHeight: number, cellPadding: number, headerFontSize: number, minColumnWidth: number): number;
14
15
  drawRow(doc: PDFKit.PDFDocument, row: Record<string, unknown>, columns: ExportTableColumn[], currentY: number, rowHeight: number, cellPadding: number, dataFontSize: number, minColumnWidth: number, rowIndex?: number): number;
15
16
  }
@@ -1,4 +1,4 @@
1
- import { a as ExportSection, E as ExportFilter, b as ExportTable, c as ExportTableColumn } from '../../types-JAEAu4KX.js';
1
+ import { a as ExportSection, E as ExportFilter, b as ExportTable, c as ExportTableColumn } from '../../types-D3IyO__4.js';
2
2
 
3
3
  type MetaDataValue = ExportFilter[] | string;
4
4
  declare class PdfExporter {
@@ -10,6 +10,7 @@ declare class PdfExporter {
10
10
  drawSectionTitle(doc: PDFKit.PDFDocument, title: string, startY: number): number;
11
11
  drawMetaData(doc: PDFKit.PDFDocument, metaData: Record<string, MetaDataValue>, startY: number): number;
12
12
  drawTable(doc: PDFKit.PDFDocument, table: ExportTable, startY: number): number;
13
+ private truncateTextToWidth;
13
14
  drawHeader(doc: PDFKit.PDFDocument, columns: ExportTableColumn[], startY: number, tableWidth: number, headerHeight: number, cellPadding: number, headerFontSize: number, minColumnWidth: number): number;
14
15
  drawRow(doc: PDFKit.PDFDocument, row: Record<string, unknown>, columns: ExportTableColumn[], currentY: number, rowHeight: number, cellPadding: number, dataFontSize: number, minColumnWidth: number, rowIndex?: number): number;
15
16
  }
@@ -167,7 +167,14 @@ var PdfExporter = class {
167
167
  const dataFontSize = columnCount > 13 ? 5 : columnCount > 10 ? 6 : columnCount > 7 ? 7 : 8;
168
168
  const headerWidthSlack = 2;
169
169
  const headerMinWidths = /* @__PURE__ */ new Map();
170
+ const cssPixelsToPoints = 0.75;
171
+ const boundedColumns = /* @__PURE__ */ new Set();
170
172
  columns.forEach((col) => {
173
+ if (col.size !== void 0 && Number.isFinite(col.size) && col.size > 0) {
174
+ col.width = col.size * cssPixelsToPoints;
175
+ boundedColumns.add(col);
176
+ return;
177
+ }
171
178
  doc.font(FONT_BOLD).fontSize(headerFontSize);
172
179
  const headerTextWidth = doc.widthOfString(col.header);
173
180
  const headerMinWidth = Math.max(...col.header.split(" ").map((w) => doc.widthOfString(w)));
@@ -186,49 +193,50 @@ var PdfExporter = class {
186
193
  headerMinWidths.set(col, headerMinWidth + TABLE_CELL_PADDING * 2 + headerWidthSlack);
187
194
  });
188
195
  const usableWidth = doc.page.width - doc.page.margins.left - doc.page.margins.right;
196
+ const minimumColumnWidth = Math.min(MIN_COLUMN_WIDTH, usableWidth / columnCount);
189
197
  const totalColumnWidth = columns.reduce((sum, c) => sum + (c.width ?? MIN_COLUMN_WIDTH), 0);
190
198
  if (totalColumnWidth > usableWidth) {
191
199
  const scale = usableWidth / totalColumnWidth;
192
200
  columns.forEach((c) => {
193
- const headerMin = headerMinWidths.get(c) ?? MIN_COLUMN_WIDTH;
194
- c.width = Math.max(Math.floor((c.width ?? MIN_COLUMN_WIDTH) * scale), headerMin, MIN_COLUMN_WIDTH);
201
+ const width = c.width ?? MIN_COLUMN_WIDTH;
202
+ const headerMin = headerMinWidths.get(c) ?? minimumColumnWidth;
203
+ const minimumWidth = Math.min(width, Math.max(headerMin, minimumColumnWidth));
204
+ c.width = Math.max(Math.floor(width * scale), minimumWidth);
195
205
  });
196
- let excess = columns.reduce((sum, c) => sum + (c.width ?? MIN_COLUMN_WIDTH), 0) - usableWidth;
197
- for (let i = columns.length - 1; i >= 0 && excess > 0; i--) {
198
- const col = columns[i];
199
- const available = (col.width ?? MIN_COLUMN_WIDTH) - MIN_COLUMN_WIDTH;
200
- const trim = Math.min(excess, available);
201
- if (trim > 0) {
202
- col.width = (col.width ?? MIN_COLUMN_WIDTH) - trim;
203
- excess -= trim;
206
+ const excess = columns.reduce((sum, c) => sum + (c.width ?? MIN_COLUMN_WIDTH), 0) - usableWidth;
207
+ if (excess > 0) {
208
+ const reducibleWidth = columns.reduce(
209
+ (sum, c) => sum + Math.max((c.width ?? MIN_COLUMN_WIDTH) - minimumColumnWidth, 0),
210
+ 0
211
+ );
212
+ if (reducibleWidth > 0) {
213
+ columns.forEach((c) => {
214
+ const width = c.width ?? MIN_COLUMN_WIDTH;
215
+ const available = Math.max(width - minimumColumnWidth, 0);
216
+ c.width = width - excess * (available / reducibleWidth);
217
+ });
204
218
  }
205
219
  }
206
220
  } else if (totalColumnWidth < usableWidth) {
207
- const scale = usableWidth / totalColumnWidth;
208
- columns.forEach((c) => {
209
- c.width = Math.floor((c.width ?? MIN_COLUMN_WIDTH) * scale);
210
- });
211
- const expanded = columns.reduce((sum, c) => sum + (c.width ?? 0), 0);
212
- columns[columns.length - 1].width = (columns[columns.length - 1].width ?? 0) + (usableWidth - expanded);
221
+ const expandableColumns = columns.filter((c) => !boundedColumns.has(c));
222
+ const expandableWidth = expandableColumns.reduce((sum, c) => sum + (c.width ?? MIN_COLUMN_WIDTH), 0);
223
+ if (expandableWidth > 0) {
224
+ const scale = (expandableWidth + usableWidth - totalColumnWidth) / expandableWidth;
225
+ expandableColumns.forEach((c) => {
226
+ c.width = Math.floor((c.width ?? MIN_COLUMN_WIDTH) * scale);
227
+ });
228
+ const expanded = columns.reduce((sum, c) => sum + (c.width ?? 0), 0);
229
+ const lastExpandableColumn = expandableColumns[expandableColumns.length - 1];
230
+ lastExpandableColumn.width = (lastExpandableColumn.width ?? 0) + (usableWidth - expanded);
231
+ }
213
232
  }
214
233
  const tableWidth = columns.reduce((sum, c) => sum + (c.width ?? MIN_COLUMN_WIDTH), 0);
215
234
  const pageBottom = doc.page.height - doc.page.margins.bottom;
216
- const calculateRowHeight = (row, isHeader = false) => {
217
- const fontSize = isHeader ? headerFontSize : dataFontSize;
218
- doc.font(isHeader ? FONT_BOLD : FONT_REGULAR).fontSize(fontSize);
219
- let maxLines = 1;
220
- columns.forEach((col) => {
221
- const cellValue = isHeader ? col.header : row?.[col.key] !== void 0 ? String(row[col.key]) : "";
222
- const textWidth = doc.widthOfString(cellValue);
223
- const availableWidth = (col.width ?? MIN_COLUMN_WIDTH) - TABLE_CELL_PADDING * 2;
224
- const lines = Math.ceil(textWidth / availableWidth);
225
- if (lines > maxLines) {
226
- maxLines = lines;
227
- }
228
- });
229
- return Math.max(maxLines * (fontSize + 2) + TABLE_CELL_PADDING * 2, DEFAULT_ROW_HEIGHT);
235
+ const calculateRowHeight = (isHeader = false) => {
236
+ doc.font(isHeader ? FONT_BOLD : FONT_REGULAR).fontSize(isHeader ? headerFontSize : dataFontSize);
237
+ return Math.max(doc.currentLineHeight(true) + TABLE_CELL_PADDING * 2, DEFAULT_ROW_HEIGHT);
230
238
  };
231
- const headerHeight = calculateRowHeight(null, true);
239
+ const headerHeight = calculateRowHeight(true);
232
240
  const drawTableHeader = (y) => this.drawHeader(doc, columns, y, tableWidth, headerHeight, TABLE_CELL_PADDING, headerFontSize, MIN_COLUMN_WIDTH);
233
241
  let tableStartY = startY;
234
242
  if (tableStartY + headerHeight > pageBottom) {
@@ -238,7 +246,7 @@ var PdfExporter = class {
238
246
  let currentY = drawTableHeader(tableStartY);
239
247
  doc.font(FONT_REGULAR).fontSize(dataFontSize);
240
248
  rows.forEach((row, rowIndex) => {
241
- const currentRowHeight = calculateRowHeight(row, false);
249
+ const currentRowHeight = calculateRowHeight();
242
250
  if (currentY + currentRowHeight > pageBottom) {
243
251
  doc.addPage();
244
252
  currentY = drawTableHeader(doc.page.margins.top);
@@ -261,6 +269,28 @@ var PdfExporter = class {
261
269
  doc.strokeColor(HEADER_RULE_COLOR).lineWidth(HEADER_RULE_WIDTH).moveTo(left, closingRuleY).lineTo(left + tableWidth, closingRuleY).stroke();
262
270
  return closingRuleY;
263
271
  }
272
+ truncateTextToWidth(doc, text, availableWidth) {
273
+ if (doc.widthOfString(text) <= availableWidth) {
274
+ return text;
275
+ }
276
+ const ellipsis = "\u2026";
277
+ if (doc.widthOfString(ellipsis) > availableWidth) {
278
+ return "";
279
+ }
280
+ const characters = Array.from(text);
281
+ let low = 0;
282
+ let high = characters.length;
283
+ while (low < high) {
284
+ const middle = Math.ceil((low + high) / 2);
285
+ const candidate = `${characters.slice(0, middle).join("").trimEnd()}${ellipsis}`;
286
+ if (doc.widthOfString(candidate) <= availableWidth) {
287
+ low = middle;
288
+ } else {
289
+ high = middle - 1;
290
+ }
291
+ }
292
+ return `${characters.slice(0, low).join("").trimEnd()}${ellipsis}`;
293
+ }
264
294
  drawHeader(doc, columns, startY, tableWidth, headerHeight, cellPadding, headerFontSize, minColumnWidth) {
265
295
  const left = doc.page.margins.left;
266
296
  doc.rect(left, startY, tableWidth, headerHeight).fill(HEADER_BACKGROUND_COLOR);
@@ -270,12 +300,15 @@ var PdfExporter = class {
270
300
  const headerLineHeight = doc.currentLineHeight(true);
271
301
  const headerTextY = startY + Math.max((headerHeight - headerLineHeight) / 2, 0);
272
302
  columns.forEach((col) => {
273
- doc.text(col.header, xPosition + cellPadding, headerTextY, {
274
- width: (col.width ?? minColumnWidth) - cellPadding * 2,
303
+ const innerWidth = (col.width ?? minColumnWidth) - cellPadding * 2;
304
+ const bounded = col.size !== void 0 && Number.isFinite(col.size) && col.size > 0;
305
+ const headerText = bounded ? this.truncateTextToWidth(doc, col.header, innerWidth) : col.header;
306
+ doc.text(headerText, xPosition + cellPadding, headerTextY, {
307
+ width: innerWidth,
275
308
  height: headerLineHeight,
276
309
  align: "left",
277
310
  lineBreak: false,
278
- ellipsis: true
311
+ ellipsis: !bounded
279
312
  });
280
313
  xPosition += col.width ?? minColumnWidth;
281
314
  });
@@ -296,12 +329,15 @@ var PdfExporter = class {
296
329
  const rawValue = row[col.key];
297
330
  const cellValue = typeof rawValue === "string" || typeof rawValue === "number" || typeof rawValue === "boolean" ? String(rawValue) : "";
298
331
  const isNumeric = typeof rawValue === "number" || typeof rawValue === "string" && rawValue !== "" && !isNaN(Number(rawValue));
299
- doc.text(cellValue, xPosition + cellPadding, dataTextY, {
300
- width: (col.width ?? minColumnWidth) - cellPadding * 2,
332
+ const innerWidth = (col.width ?? minColumnWidth) - cellPadding * 2;
333
+ const bounded = col.size !== void 0 && Number.isFinite(col.size) && col.size > 0;
334
+ const rowText = bounded ? this.truncateTextToWidth(doc, cellValue, innerWidth) : cellValue;
335
+ doc.text(rowText, xPosition + cellPadding, dataTextY, {
336
+ width: innerWidth,
301
337
  height: dataLineHeight,
302
338
  align: isNumeric ? "right" : "left",
303
339
  lineBreak: false,
304
- ellipsis: true
340
+ ellipsis: !bounded
305
341
  });
306
342
  xPosition += col.width ?? minColumnWidth;
307
343
  if (i < columns.length - 1) {
package/dist/index.cjs CHANGED
@@ -2601,16 +2601,16 @@ var FIELDS11 = {
2601
2601
  groupByName: { type: "string" },
2602
2602
  rowType: { type: "string" },
2603
2603
  locationName: { type: "string", size: 220, columnKey: "locationName" },
2604
- employeeName: { type: "string", size: 220, columnKey: "employeeName" },
2605
- empId: {
2604
+ employeeName: {
2606
2605
  type: "string",
2607
- size: 160,
2608
- columnKey: "employeeId",
2606
+ size: 220,
2607
+ columnKey: "employeeName",
2609
2608
  footerCalculation: { type: "label", label: "table.total" }
2610
2609
  },
2610
+ empId: { type: "string", size: 160, columnKey: "employeeId" },
2611
2611
  payrollId: { type: "string", size: 160, columnKey: "payrollId" },
2612
2612
  jobName: { type: "string", size: 160, columnKey: "employeeJob" },
2613
- paidNormalHours: { type: "number", columnKey: "paidNormalHours", footerCalculation: { type: "sum" } },
2613
+ paidNormalHours: { type: "fixedNumber", columnKey: "paidNormalHours", footerCalculation: { type: "sum" } },
2614
2614
  normalPay: { type: "money", columnKey: "normalPay", footerCalculation: { type: "sum" } },
2615
2615
  overtimePay: { type: "money", columnKey: "overtimePay", footerCalculation: { type: "sum" } },
2616
2616
  doubleOvertimePay: { type: "money", columnKey: "doubleOvertimePay", footerCalculation: { type: "sum" } },
@@ -2647,7 +2647,7 @@ var VISIBLE_COLUMNS3 = [
2647
2647
  "minimumWageAdjustment",
2648
2648
  "totalPay"
2649
2649
  ];
2650
- var AVAILABLE_COLUMNS3 = ["empId", ...VISIBLE_COLUMNS3];
2650
+ var AVAILABLE_COLUMNS3 = [...VISIBLE_COLUMNS3];
2651
2651
  var payrollConfig = {
2652
2652
  fields: FIELDS11,
2653
2653
  availableColumns: AVAILABLE_COLUMNS3,
package/dist/index.js CHANGED
@@ -40,7 +40,7 @@ import {
40
40
  ticketLiveConfig,
41
41
  ticketSummaryConfig,
42
42
  tipCashoutReconciliationConfig
43
- } from "./chunk-UUKHJDV3.js";
43
+ } from "./chunk-7CBVZY3Y.js";
44
44
 
45
45
  // src/utils/alignment.ts
46
46
  function getColumnAlignment(type) {
@@ -2,6 +2,7 @@ interface ExportTableColumn {
2
2
  header: string;
3
3
  key: string;
4
4
  width?: number;
5
+ size?: number;
5
6
  }
6
7
  interface ExportTable {
7
8
  columns: ExportTableColumn[];
@@ -2,6 +2,7 @@ interface ExportTableColumn {
2
2
  header: string;
3
3
  key: string;
4
4
  width?: number;
5
+ size?: number;
5
6
  }
6
7
  interface ExportTable {
7
8
  columns: ExportTableColumn[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@harbortouch/skytab-analytics-report-utils",
3
- "version": "0.41.11",
3
+ "version": "0.41.13",
4
4
  "description": "Centralized report column presentation configuration for SkyTab Analytics",
5
5
  "engines": {
6
6
  "node": ">=22.6.0",