@eztrak/shared 0.17.1 → 0.19.0

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.
@@ -28,8 +28,8 @@ import {
28
28
  TooltipText,
29
29
  dropdownStyles,
30
30
  resolveActions
31
- } from "../chunk-4ASJWHN3.mjs";
32
- import "../chunk-QOYMQFOB.mjs";
31
+ } from "../chunk-2KXV5C3X.mjs";
32
+ import "../chunk-A5Y5QGVL.mjs";
33
33
  export {
34
34
  ActionMenuItem,
35
35
  Breadcrumbs,
@@ -0,0 +1,146 @@
1
+ type ExcelAlign = "left" | "center" | "right";
2
+ /** Per-column Excel colors. Hex is RRGGBB; a leading # is accepted. */
3
+ type ExcelColumnStyle = {
4
+ headerFill?: string;
5
+ headerColor?: string;
6
+ fill?: string;
7
+ color?: string;
8
+ bold?: boolean;
9
+ align?: ExcelAlign;
10
+ /** Excel number format, for example '"$"#,##0.00'. */
11
+ numFmt?: string;
12
+ };
13
+ type ExcelTheme = {
14
+ headerFill?: string;
15
+ headerColor?: string;
16
+ fill?: string;
17
+ color?: string;
18
+ borderColor?: string;
19
+ fontName?: string;
20
+ fontSize?: number;
21
+ };
22
+ type ExcelFormatParams = {
23
+ value: unknown;
24
+ data: Record<string, unknown>;
25
+ };
26
+ type ExcelExportColumn = {
27
+ field?: string;
28
+ headerName?: string;
29
+ children?: ExcelExportColumn[];
30
+ hide?: boolean;
31
+ checkboxSelection?: boolean;
32
+ headerCheckboxSelection?: boolean;
33
+ valueFormatter?: (params: ExcelFormatParams) => unknown;
34
+ format?: (params: ExcelFormatParams) => unknown;
35
+ excel?: ExcelColumnStyle;
36
+ };
37
+ type ExportExcelErrorCode = "empty" | "invalid" | "no-columns" | "filename" | "write";
38
+ type ExportExcelFailure = {
39
+ ok: false;
40
+ code: ExportExcelErrorCode;
41
+ error: string;
42
+ };
43
+ type ExportExcelReportResult = {
44
+ ok: true;
45
+ fileName: string;
46
+ } | ExportExcelFailure;
47
+ type ExportExcelReportOptions = {
48
+ data?: unknown[] | null;
49
+ fileName?: string;
50
+ columns?: ExcelExportColumn[];
51
+ sheetName?: string;
52
+ theme?: ExcelTheme;
53
+ /** Drop columns with hide: true. Default false, matching vault grids. */
54
+ skipHidden?: boolean;
55
+ /**
56
+ * Format leaf fields whose name contains "date" when they have no formatter.
57
+ * Vault turns this on and passes its own date formatter.
58
+ */
59
+ formatDateFields?: boolean;
60
+ formatDate?: (value: unknown) => unknown;
61
+ /**
62
+ * Date suffix for the file name. Omit to use the local YYYY-MM-DD.
63
+ * Pass null when the caller could not produce a stamp.
64
+ */
65
+ dateStamp?: string | null;
66
+ };
67
+ type ResolvedTheme = {
68
+ headerFill: string;
69
+ headerColor: string;
70
+ fill: string;
71
+ color: string;
72
+ borderColor: string;
73
+ fontName: string;
74
+ fontSize: number;
75
+ };
76
+ type ExcelCellStyle = {
77
+ font: {
78
+ name: string;
79
+ sz: number;
80
+ bold?: boolean;
81
+ color: {
82
+ rgb: string;
83
+ };
84
+ };
85
+ fill: {
86
+ patternType: "solid";
87
+ fgColor: {
88
+ rgb: string;
89
+ };
90
+ };
91
+ alignment: {
92
+ vertical: "center";
93
+ horizontal: ExcelAlign;
94
+ wrapText: false;
95
+ };
96
+ border: {
97
+ top: {
98
+ style: "thin";
99
+ color: {
100
+ rgb: string;
101
+ };
102
+ };
103
+ bottom: {
104
+ style: "thin";
105
+ color: {
106
+ rgb: string;
107
+ };
108
+ };
109
+ left: {
110
+ style: "thin";
111
+ color: {
112
+ rgb: string;
113
+ };
114
+ };
115
+ right: {
116
+ style: "thin";
117
+ color: {
118
+ rgb: string;
119
+ };
120
+ };
121
+ };
122
+ numFmt?: string;
123
+ };
124
+ type WorkBook = {
125
+ SheetNames: string[];
126
+ Sheets: Record<string, WorkSheet>;
127
+ };
128
+ type WorkSheet = Record<string, unknown>;
129
+ declare const DEFAULT_EXCEL_THEME: ResolvedTheme;
130
+ declare const excelHeaderStyle: (theme?: ExcelTheme, column?: ExcelColumnStyle) => ExcelCellStyle;
131
+ declare const excelDataStyle: (theme?: ExcelTheme, column?: ExcelColumnStyle) => ExcelCellStyle;
132
+ type BuiltExcelWorkbook = {
133
+ ok: true;
134
+ workbook: WorkBook;
135
+ fileName: string;
136
+ sheetName: string;
137
+ } | ExportExcelFailure;
138
+ /**
139
+ * Build a styled workbook. Does not write a file.
140
+ * Header merges follow the column tree, so two groups with the same title stay separate.
141
+ */
142
+ declare const buildExcelWorkbook: (options?: ExportExcelReportOptions) => BuiltExcelWorkbook;
143
+ /** Write a styled .xlsx. Returns a result; it does not toast. */
144
+ declare const exportExcelReport: (options?: ExportExcelReportOptions) => ExportExcelReportResult;
145
+
146
+ export { type BuiltExcelWorkbook, DEFAULT_EXCEL_THEME, type ExcelAlign, type ExcelCellStyle, type ExcelColumnStyle, type ExcelExportColumn, type ExcelFormatParams, type ExcelTheme, type ExportExcelErrorCode, type ExportExcelFailure, type ExportExcelReportOptions, type ExportExcelReportResult, buildExcelWorkbook, excelDataStyle, excelHeaderStyle, exportExcelReport };
@@ -0,0 +1,146 @@
1
+ type ExcelAlign = "left" | "center" | "right";
2
+ /** Per-column Excel colors. Hex is RRGGBB; a leading # is accepted. */
3
+ type ExcelColumnStyle = {
4
+ headerFill?: string;
5
+ headerColor?: string;
6
+ fill?: string;
7
+ color?: string;
8
+ bold?: boolean;
9
+ align?: ExcelAlign;
10
+ /** Excel number format, for example '"$"#,##0.00'. */
11
+ numFmt?: string;
12
+ };
13
+ type ExcelTheme = {
14
+ headerFill?: string;
15
+ headerColor?: string;
16
+ fill?: string;
17
+ color?: string;
18
+ borderColor?: string;
19
+ fontName?: string;
20
+ fontSize?: number;
21
+ };
22
+ type ExcelFormatParams = {
23
+ value: unknown;
24
+ data: Record<string, unknown>;
25
+ };
26
+ type ExcelExportColumn = {
27
+ field?: string;
28
+ headerName?: string;
29
+ children?: ExcelExportColumn[];
30
+ hide?: boolean;
31
+ checkboxSelection?: boolean;
32
+ headerCheckboxSelection?: boolean;
33
+ valueFormatter?: (params: ExcelFormatParams) => unknown;
34
+ format?: (params: ExcelFormatParams) => unknown;
35
+ excel?: ExcelColumnStyle;
36
+ };
37
+ type ExportExcelErrorCode = "empty" | "invalid" | "no-columns" | "filename" | "write";
38
+ type ExportExcelFailure = {
39
+ ok: false;
40
+ code: ExportExcelErrorCode;
41
+ error: string;
42
+ };
43
+ type ExportExcelReportResult = {
44
+ ok: true;
45
+ fileName: string;
46
+ } | ExportExcelFailure;
47
+ type ExportExcelReportOptions = {
48
+ data?: unknown[] | null;
49
+ fileName?: string;
50
+ columns?: ExcelExportColumn[];
51
+ sheetName?: string;
52
+ theme?: ExcelTheme;
53
+ /** Drop columns with hide: true. Default false, matching vault grids. */
54
+ skipHidden?: boolean;
55
+ /**
56
+ * Format leaf fields whose name contains "date" when they have no formatter.
57
+ * Vault turns this on and passes its own date formatter.
58
+ */
59
+ formatDateFields?: boolean;
60
+ formatDate?: (value: unknown) => unknown;
61
+ /**
62
+ * Date suffix for the file name. Omit to use the local YYYY-MM-DD.
63
+ * Pass null when the caller could not produce a stamp.
64
+ */
65
+ dateStamp?: string | null;
66
+ };
67
+ type ResolvedTheme = {
68
+ headerFill: string;
69
+ headerColor: string;
70
+ fill: string;
71
+ color: string;
72
+ borderColor: string;
73
+ fontName: string;
74
+ fontSize: number;
75
+ };
76
+ type ExcelCellStyle = {
77
+ font: {
78
+ name: string;
79
+ sz: number;
80
+ bold?: boolean;
81
+ color: {
82
+ rgb: string;
83
+ };
84
+ };
85
+ fill: {
86
+ patternType: "solid";
87
+ fgColor: {
88
+ rgb: string;
89
+ };
90
+ };
91
+ alignment: {
92
+ vertical: "center";
93
+ horizontal: ExcelAlign;
94
+ wrapText: false;
95
+ };
96
+ border: {
97
+ top: {
98
+ style: "thin";
99
+ color: {
100
+ rgb: string;
101
+ };
102
+ };
103
+ bottom: {
104
+ style: "thin";
105
+ color: {
106
+ rgb: string;
107
+ };
108
+ };
109
+ left: {
110
+ style: "thin";
111
+ color: {
112
+ rgb: string;
113
+ };
114
+ };
115
+ right: {
116
+ style: "thin";
117
+ color: {
118
+ rgb: string;
119
+ };
120
+ };
121
+ };
122
+ numFmt?: string;
123
+ };
124
+ type WorkBook = {
125
+ SheetNames: string[];
126
+ Sheets: Record<string, WorkSheet>;
127
+ };
128
+ type WorkSheet = Record<string, unknown>;
129
+ declare const DEFAULT_EXCEL_THEME: ResolvedTheme;
130
+ declare const excelHeaderStyle: (theme?: ExcelTheme, column?: ExcelColumnStyle) => ExcelCellStyle;
131
+ declare const excelDataStyle: (theme?: ExcelTheme, column?: ExcelColumnStyle) => ExcelCellStyle;
132
+ type BuiltExcelWorkbook = {
133
+ ok: true;
134
+ workbook: WorkBook;
135
+ fileName: string;
136
+ sheetName: string;
137
+ } | ExportExcelFailure;
138
+ /**
139
+ * Build a styled workbook. Does not write a file.
140
+ * Header merges follow the column tree, so two groups with the same title stay separate.
141
+ */
142
+ declare const buildExcelWorkbook: (options?: ExportExcelReportOptions) => BuiltExcelWorkbook;
143
+ /** Write a styled .xlsx. Returns a result; it does not toast. */
144
+ declare const exportExcelReport: (options?: ExportExcelReportOptions) => ExportExcelReportResult;
145
+
146
+ export { type BuiltExcelWorkbook, DEFAULT_EXCEL_THEME, type ExcelAlign, type ExcelCellStyle, type ExcelColumnStyle, type ExcelExportColumn, type ExcelFormatParams, type ExcelTheme, type ExportExcelErrorCode, type ExportExcelFailure, type ExportExcelReportOptions, type ExportExcelReportResult, buildExcelWorkbook, excelDataStyle, excelHeaderStyle, exportExcelReport };
@@ -0,0 +1,355 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/excel/index.ts
31
+ var excel_exports = {};
32
+ __export(excel_exports, {
33
+ DEFAULT_EXCEL_THEME: () => DEFAULT_EXCEL_THEME,
34
+ buildExcelWorkbook: () => buildExcelWorkbook,
35
+ excelDataStyle: () => excelDataStyle,
36
+ excelHeaderStyle: () => excelHeaderStyle,
37
+ exportExcelReport: () => exportExcelReport
38
+ });
39
+ module.exports = __toCommonJS(excel_exports);
40
+ var XLSX = __toESM(require("xlsx-js-style"));
41
+ var ERRORS = {
42
+ empty: "No valid data to download. Please ensure data is available.",
43
+ invalid: "Invalid data structure. Please ensure data is correctly formatted.",
44
+ "no-columns": "No data to export. Please check the data source.",
45
+ filename: "Failed to generate file name. Please try again."
46
+ };
47
+ var DEFAULT_EXCEL_THEME = {
48
+ headerFill: "2F75B6",
49
+ headerColor: "FFFFFF",
50
+ fill: "FFFFFF",
51
+ color: "1F2933",
52
+ borderColor: "8FA4BF",
53
+ fontName: "Calibri",
54
+ fontSize: 11
55
+ };
56
+ var fail = (code) => ({
57
+ ok: false,
58
+ code,
59
+ error: ERRORS[code]
60
+ });
61
+ var rgb = (input, fallback) => {
62
+ if (!input) return fallback;
63
+ const hex = input.trim().replace(/^#/, "").toUpperCase();
64
+ return /^[0-9A-F]{6}$/.test(hex) ? hex : fallback;
65
+ };
66
+ var resolveTheme = (theme) => ({
67
+ headerFill: rgb(theme?.headerFill, DEFAULT_EXCEL_THEME.headerFill),
68
+ headerColor: rgb(theme?.headerColor, DEFAULT_EXCEL_THEME.headerColor),
69
+ fill: rgb(theme?.fill, DEFAULT_EXCEL_THEME.fill),
70
+ color: rgb(theme?.color, DEFAULT_EXCEL_THEME.color),
71
+ borderColor: rgb(theme?.borderColor, DEFAULT_EXCEL_THEME.borderColor),
72
+ fontName: theme?.fontName?.trim() || DEFAULT_EXCEL_THEME.fontName,
73
+ fontSize: typeof theme?.fontSize === "number" && theme.fontSize > 0 ? theme.fontSize : DEFAULT_EXCEL_THEME.fontSize
74
+ });
75
+ var gridBorder = (color) => {
76
+ const edge = () => ({ style: "thin", color: { rgb: color } });
77
+ return { top: edge(), bottom: edge(), left: edge(), right: edge() };
78
+ };
79
+ var excelHeaderStyle = (theme, column) => {
80
+ const resolved = resolveTheme(theme);
81
+ return {
82
+ font: {
83
+ name: resolved.fontName,
84
+ sz: resolved.fontSize,
85
+ bold: true,
86
+ color: { rgb: rgb(column?.headerColor, resolved.headerColor) }
87
+ },
88
+ fill: {
89
+ patternType: "solid",
90
+ fgColor: { rgb: rgb(column?.headerFill, resolved.headerFill) }
91
+ },
92
+ alignment: {
93
+ vertical: "center",
94
+ horizontal: column?.align ?? "left",
95
+ wrapText: false
96
+ },
97
+ border: gridBorder(resolved.borderColor)
98
+ };
99
+ };
100
+ var excelDataStyle = (theme, column) => {
101
+ const resolved = resolveTheme(theme);
102
+ const font = {
103
+ name: resolved.fontName,
104
+ sz: resolved.fontSize,
105
+ color: { rgb: rgb(column?.color, resolved.color) }
106
+ };
107
+ if (column?.bold) font.bold = true;
108
+ const style = {
109
+ font,
110
+ fill: {
111
+ patternType: "solid",
112
+ fgColor: { rgb: rgb(column?.fill, resolved.fill) }
113
+ },
114
+ alignment: {
115
+ vertical: "center",
116
+ horizontal: column?.align ?? "left",
117
+ wrapText: false
118
+ },
119
+ border: gridBorder(resolved.borderColor)
120
+ };
121
+ if (column?.numFmt) style.numFmt = column.numFmt;
122
+ return style;
123
+ };
124
+ var getNestedValue = (obj, path) => {
125
+ if (!obj || typeof obj !== "object") return "";
126
+ try {
127
+ const value = path.split(".").reduce((acc, key) => {
128
+ if (acc == null || typeof acc !== "object") return void 0;
129
+ return acc[key];
130
+ }, obj);
131
+ return value ?? "";
132
+ } catch {
133
+ return "";
134
+ }
135
+ };
136
+ var isGroup = (col) => Array.isArray(col.children) && col.children.length > 0;
137
+ var isSkippedLeaf = (col) => {
138
+ if (col.checkboxSelection || col.headerCheckboxSelection) return true;
139
+ const field = typeof col.field === "string" ? col.field.trim() : "";
140
+ return !field || field === "checkbox" || field === "checkboxSelection";
141
+ };
142
+ var collectLeaves = (cols, groups, skipHidden) => {
143
+ const leaves = [];
144
+ cols.forEach((col) => {
145
+ if (!col || typeof col !== "object") return;
146
+ if (skipHidden && col.hide) return;
147
+ if (isGroup(col)) {
148
+ const group = {
149
+ name: col.headerName || "",
150
+ excel: col.excel
151
+ };
152
+ leaves.push(...collectLeaves(col.children ?? [], [...groups, group], skipHidden));
153
+ return;
154
+ }
155
+ if (isSkippedLeaf(col)) return;
156
+ const field = col.field.trim();
157
+ leaves.push({
158
+ field,
159
+ headerName: (col.headerName || field).trim() || field,
160
+ column: col,
161
+ groups
162
+ });
163
+ });
164
+ return leaves;
165
+ };
166
+ var labelFromKey = (key) => key.replace(/([A-Z])/g, " $1").replace(/^\w/, (char) => char.toUpperCase()).trim();
167
+ var columnsFromRows = (rows) => {
168
+ const first = rows[0];
169
+ if (!first || typeof first !== "object" || Array.isArray(first)) {
170
+ return fail("invalid");
171
+ }
172
+ return Object.keys(first).filter((key) => key !== "checkbox" && key !== "checkboxSelection" && key.trim()).map((key) => ({ field: key, headerName: labelFromKey(key) }));
173
+ };
174
+ var formatLeafValue = (row, leaf, options) => {
175
+ let value = getNestedValue(row, leaf.field);
176
+ const formatter = leaf.column.format || leaf.column.valueFormatter;
177
+ if (typeof formatter === "function") {
178
+ try {
179
+ return formatter({ value, data: row }) ?? "";
180
+ } catch {
181
+ return value ?? "";
182
+ }
183
+ }
184
+ const fieldLooksLikeDate = leaf.field.toLowerCase().includes("date");
185
+ if (options.formatDateFields && fieldLooksLikeDate && typeof options.formatDate === "function") {
186
+ try {
187
+ return options.formatDate(value) ?? "";
188
+ } catch {
189
+ return value ?? "";
190
+ }
191
+ }
192
+ if (value instanceof Date) return value;
193
+ if (value != null && typeof value === "object") return "";
194
+ const numFmt = leaf.column.excel?.numFmt;
195
+ if (numFmt) {
196
+ if (typeof value === "number" && Number.isFinite(value)) return value;
197
+ if (typeof value === "string" && value.trim() !== "" && Number.isFinite(Number(value))) {
198
+ return Number(value);
199
+ }
200
+ }
201
+ return value ?? "";
202
+ };
203
+ var localDateStamp = () => {
204
+ const date = /* @__PURE__ */ new Date();
205
+ const year = date.getFullYear();
206
+ const month = String(date.getMonth() + 1).padStart(2, "0");
207
+ const day = String(date.getDate()).padStart(2, "0");
208
+ return `${year}-${month}-${day}`;
209
+ };
210
+ var resolveDateStamp = (dateStamp) => {
211
+ if (dateStamp === null) return null;
212
+ if (typeof dateStamp === "string" && dateStamp.trim()) return dateStamp.trim();
213
+ return localDateStamp();
214
+ };
215
+ var safeSheetName = (name) => {
216
+ const cleaned = (name || "Report").replace(/[:\\/?*[\]]/g, " ").trim() || "Report";
217
+ return cleaned.slice(0, 31);
218
+ };
219
+ var buildHeaderGrid = (leaves) => {
220
+ const totalHeaderRows = Math.max(...leaves.map((leaf) => leaf.groups.length + 1), 1);
221
+ const headerRows = Array.from(
222
+ { length: totalHeaderRows },
223
+ () => Array.from({ length: leaves.length }, () => "")
224
+ );
225
+ const merges = [];
226
+ for (let depth = 0; depth < totalHeaderRows - 1; depth += 1) {
227
+ let colIndex = 0;
228
+ while (colIndex < leaves.length) {
229
+ const group = leaves[colIndex].groups[depth];
230
+ if (!group) {
231
+ colIndex += 1;
232
+ continue;
233
+ }
234
+ let span = 1;
235
+ while (colIndex + span < leaves.length && leaves[colIndex + span].groups[depth] === group) {
236
+ span += 1;
237
+ }
238
+ headerRows[depth][colIndex] = group.name;
239
+ if (span > 1) {
240
+ merges.push({
241
+ s: { r: depth, c: colIndex },
242
+ e: { r: depth, c: colIndex + span - 1 }
243
+ });
244
+ }
245
+ colIndex += span;
246
+ }
247
+ }
248
+ leaves.forEach((leaf, colIndex) => {
249
+ const row = leaf.groups.length;
250
+ headerRows[row][colIndex] = leaf.headerName;
251
+ if (row < totalHeaderRows - 1) {
252
+ merges.push({
253
+ s: { r: row, c: colIndex },
254
+ e: { r: totalHeaderRows - 1, c: colIndex }
255
+ });
256
+ }
257
+ });
258
+ return { headerRows, merges, totalHeaderRows };
259
+ };
260
+ var headerStyleFor = (leaf, row, theme) => {
261
+ const source = row < leaf.groups.length ? leaf.groups[row].excel : leaf.column.excel;
262
+ return excelHeaderStyle(theme, source);
263
+ };
264
+ var columnWidth = (leaf, values) => {
265
+ const headerLength = Math.max(
266
+ leaf.headerName.length,
267
+ ...leaf.groups.map((group) => group.name.length),
268
+ 0
269
+ );
270
+ const dataLength = values.reduce((max, value) => {
271
+ return Math.max(max, String(value ?? "").length);
272
+ }, 0);
273
+ return { wch: Math.min(Math.max(headerLength, dataLength, 12), 50) };
274
+ };
275
+ var buildExcelWorkbook = (options = {}) => {
276
+ const data = options.data;
277
+ if (!Array.isArray(data) || data.length === 0) return fail("empty");
278
+ const provided = Array.isArray(options.columns) ? options.columns : [];
279
+ const columns = provided.length ? provided : columnsFromRows(data);
280
+ if (!Array.isArray(columns)) return columns;
281
+ const leaves = collectLeaves(columns, [], options.skipHidden === true);
282
+ if (!leaves.length) return fail("no-columns");
283
+ const dateStamp = resolveDateStamp(options.dateStamp);
284
+ if (!dateStamp) return fail("filename");
285
+ const { headerRows, merges, totalHeaderRows } = buildHeaderGrid(leaves);
286
+ const records = data.map(
287
+ (row) => row && typeof row === "object" && !Array.isArray(row) ? row : {}
288
+ );
289
+ const dataRows = records.map(
290
+ (row) => leaves.map((leaf) => formatLeafValue(row, leaf, options))
291
+ );
292
+ const sheet = XLSX.utils.aoa_to_sheet([...headerRows, ...dataRows]);
293
+ const lastCell = XLSX.utils.encode_cell({
294
+ r: headerRows.length + dataRows.length - 1,
295
+ c: leaves.length - 1
296
+ });
297
+ sheet["!ref"] = `A1:${lastCell}`;
298
+ sheet["!merges"] = merges;
299
+ sheet["!cols"] = leaves.map(
300
+ (leaf, index) => columnWidth(
301
+ leaf,
302
+ dataRows.map((row) => row[index])
303
+ )
304
+ );
305
+ sheet["!rows"] = Array.from({ length: totalHeaderRows }, () => ({ hpt: 22 }));
306
+ const range = XLSX.utils.decode_range(sheet["!ref"]);
307
+ for (let row = range.s.r; row <= range.e.r; row += 1) {
308
+ for (let col = range.s.c; col <= range.e.c; col += 1) {
309
+ const address = XLSX.utils.encode_cell({ r: row, c: col });
310
+ const cell = sheet[address] ?? {
311
+ t: "s",
312
+ v: ""
313
+ };
314
+ const leaf = leaves[col];
315
+ if (row < totalHeaderRows) {
316
+ cell.s = headerStyleFor(leaf, row, options.theme);
317
+ } else {
318
+ const style = excelDataStyle(options.theme, leaf.column.excel);
319
+ if (leaf.column.excel?.numFmt) cell.z = leaf.column.excel.numFmt;
320
+ cell.s = style;
321
+ }
322
+ sheet[address] = cell;
323
+ }
324
+ }
325
+ const sheetName = safeSheetName(options.sheetName);
326
+ const workbook = XLSX.utils.book_new();
327
+ XLSX.utils.book_append_sheet(workbook, sheet, sheetName);
328
+ const baseName = options.fileName == null ? "" : String(options.fileName);
329
+ return {
330
+ ok: true,
331
+ workbook,
332
+ sheetName,
333
+ fileName: `${baseName ? `${baseName}_` : ""}${dateStamp}.xlsx`
334
+ };
335
+ };
336
+ var exportExcelReport = (options = {}) => {
337
+ const built = buildExcelWorkbook(options);
338
+ if (!built.ok) return built;
339
+ try {
340
+ XLSX.writeFile(built.workbook, built.fileName, { cellStyles: true });
341
+ } catch (error) {
342
+ const message = error instanceof Error ? error.message : "Unknown error";
343
+ return { ok: false, code: "write", error: message };
344
+ }
345
+ return { ok: true, fileName: built.fileName };
346
+ };
347
+ // Annotate the CommonJS export names for ESM import in node:
348
+ 0 && (module.exports = {
349
+ DEFAULT_EXCEL_THEME,
350
+ buildExcelWorkbook,
351
+ excelDataStyle,
352
+ excelHeaderStyle,
353
+ exportExcelReport
354
+ });
355
+ //# sourceMappingURL=index.js.map