@ifto/mantine-kit 0.0.0-stage → 0.2.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.
- package/LICENSE +21 -0
- package/README.md +475 -2
- package/dist/component/atom/AppMain/App.module.js +7 -0
- package/dist/component/atom/AppMain/App.module.js.map +1 -0
- package/dist/component/atom/AppMain/AppMain.d.ts +7 -0
- package/dist/component/atom/AppMain/AppMain.js +14 -0
- package/dist/component/atom/AppMain/AppMain.js.map +1 -0
- package/dist/component/atom/CancelEditButton/CancelEditButton.d.ts +6 -0
- package/dist/component/atom/CancelEditButton/CancelEditButton.js +24 -0
- package/dist/component/atom/CancelEditButton/CancelEditButton.js.map +1 -0
- package/dist/component/atom/ConfirmEditButton/ConfirmEditButton.d.ts +13 -0
- package/dist/component/atom/ConfirmEditButton/ConfirmEditButton.js +30 -0
- package/dist/component/atom/ConfirmEditButton/ConfirmEditButton.js.map +1 -0
- package/dist/component/atom/DateField/DateField.d.ts +7 -0
- package/dist/component/atom/DateField/DateField.js +21 -0
- package/dist/component/atom/DateField/DateField.js.map +1 -0
- package/dist/component/atom/EditValueButton/EditValueButton.d.ts +6 -0
- package/dist/component/atom/EditValueButton/EditValueButton.js +24 -0
- package/dist/component/atom/EditValueButton/EditValueButton.js.map +1 -0
- package/dist/component/atom/ErrorAlert/ErrorAlert.d.ts +8 -0
- package/dist/component/atom/ErrorAlert/ErrorAlert.js +21 -0
- package/dist/component/atom/ErrorAlert/ErrorAlert.js.map +1 -0
- package/dist/component/atom/Surface/Surface.d.ts +20 -0
- package/dist/component/atom/Surface/Surface.js +15 -0
- package/dist/component/atom/Surface/Surface.js.map +1 -0
- package/dist/component/molecule/Breadcrumb/Breadcrumb.d.ts +12 -0
- package/dist/component/molecule/Breadcrumb/Breadcrumb.js +38 -0
- package/dist/component/molecule/Breadcrumb/Breadcrumb.js.map +1 -0
- package/dist/component/molecule/ExportMenuButton/ExportMenuButton.d.ts +25 -0
- package/dist/component/molecule/ExportMenuButton/ExportMenuButton.js +49 -0
- package/dist/component/molecule/ExportMenuButton/ExportMenuButton.js.map +1 -0
- package/dist/component/molecule/PaperCard/PaperCard.d.ts +7 -0
- package/dist/component/molecule/PaperCard/PaperCard.js +17 -0
- package/dist/component/molecule/PaperCard/PaperCard.js.map +1 -0
- package/dist/component/molecule/PrintSection/PrintSection.d.ts +14 -0
- package/dist/component/molecule/PrintSection/PrintSection.js +29 -0
- package/dist/component/molecule/PrintSection/PrintSection.js.map +1 -0
- package/dist/component/molecule/SelectField/SelectField.d.ts +32 -0
- package/dist/component/molecule/SelectField/SelectField.js +38 -0
- package/dist/component/molecule/SelectField/SelectField.js.map +1 -0
- package/dist/component/molecule/StatsCard/Stats.module.js +15 -0
- package/dist/component/molecule/StatsCard/Stats.module.js.map +1 -0
- package/dist/component/molecule/StatsCard/StatsCard.d.ts +18 -0
- package/dist/component/molecule/StatsCard/StatsCard.js +60 -0
- package/dist/component/molecule/StatsCard/StatsCard.js.map +1 -0
- package/dist/component/organism/DataForm/DataForm.d.ts +26 -0
- package/dist/component/organism/DataForm/DataForm.js +83 -0
- package/dist/component/organism/DataForm/DataForm.js.map +1 -0
- package/dist/component/organism/DataTabList/DataTabList.d.ts +24 -0
- package/dist/component/organism/DataTabList/DataTabList.js +37 -0
- package/dist/component/organism/DataTabList/DataTabList.js.map +1 -0
- package/dist/component/organism/DataTabList/DataTabList.module.js +13 -0
- package/dist/component/organism/DataTabList/DataTabList.module.js.map +1 -0
- package/dist/component/organism/EChart/EChart.d.ts +47 -0
- package/dist/component/organism/EChart/EChart.js +37 -0
- package/dist/component/organism/EChart/EChart.js.map +1 -0
- package/dist/component/organism/EChart/buildEChartOption.d.ts +40 -0
- package/dist/component/organism/EChart/buildEChartOption.js +57 -0
- package/dist/component/organism/EChart/buildEChartOption.js.map +1 -0
- package/dist/component/organism/EChart/chart/BarChart.d.ts +22 -0
- package/dist/component/organism/EChart/chart/BarChart.js +34 -0
- package/dist/component/organism/EChart/chart/BarChart.js.map +1 -0
- package/dist/component/organism/EChart/chart/CartesianChart.d.ts +48 -0
- package/dist/component/organism/EChart/chart/CartesianChart.js +63 -0
- package/dist/component/organism/EChart/chart/CartesianChart.js.map +1 -0
- package/dist/component/organism/EChart/chart/ChartHeader.d.ts +36 -0
- package/dist/component/organism/EChart/chart/ChartHeader.js +105 -0
- package/dist/component/organism/EChart/chart/ChartHeader.js.map +1 -0
- package/dist/component/organism/EChart/chart/ChartSeries.d.ts +50 -0
- package/dist/component/organism/EChart/chart/ChartSeries.js +23 -0
- package/dist/component/organism/EChart/chart/ChartSeries.js.map +1 -0
- package/dist/component/organism/EChart/chart/ChartTexts.d.ts +12 -0
- package/dist/component/organism/EChart/chart/ChartTexts.js +21 -0
- package/dist/component/organism/EChart/chart/ChartTexts.js.map +1 -0
- package/dist/component/organism/EChart/chart/ChartType.d.ts +50 -0
- package/dist/component/organism/EChart/chart/ChartType.js +1 -0
- package/dist/component/organism/EChart/chart/ChartTypeId.d.ts +2 -0
- package/dist/component/organism/EChart/chart/ChartTypeId.js +1 -0
- package/dist/component/organism/EChart/chart/ChartTypes.d.ts +15 -0
- package/dist/component/organism/EChart/chart/ChartTypes.js +24 -0
- package/dist/component/organism/EChart/chart/ChartTypes.js.map +1 -0
- package/dist/component/organism/EChart/chart/DonutChart.d.ts +32 -0
- package/dist/component/organism/EChart/chart/DonutChart.js +111 -0
- package/dist/component/organism/EChart/chart/DonutChart.js.map +1 -0
- package/dist/component/organism/EChart/chart/LineChart.d.ts +11 -0
- package/dist/component/organism/EChart/chart/LineChart.js +20 -0
- package/dist/component/organism/EChart/chart/LineChart.js.map +1 -0
- package/dist/component/organism/EChart/chart/StackedBarChart.d.ts +15 -0
- package/dist/component/organism/EChart/chart/StackedBarChart.js +30 -0
- package/dist/component/organism/EChart/chart/StackedBarChart.js.map +1 -0
- package/dist/component/organism/EChart/chart/UnitPanels.d.ts +63 -0
- package/dist/component/organism/EChart/chart/UnitPanels.js +127 -0
- package/dist/component/organism/EChart/chart/UnitPanels.js.map +1 -0
- package/dist/component/organism/EChart/echartDefaults.d.ts +32 -0
- package/dist/component/organism/EChart/echartDefaults.js +47 -0
- package/dist/component/organism/EChart/echartDefaults.js.map +1 -0
- package/dist/component/organism/EChart/useEChart.d.ts +35 -0
- package/dist/component/organism/EChart/useEChart.js +112 -0
- package/dist/component/organism/EChart/useEChart.js.map +1 -0
- package/dist/component/organism/Navbar/NavItem.d.ts +16 -0
- package/dist/component/organism/Navbar/NavItem.js +1 -0
- package/dist/component/organism/Navbar/Navbar.d.ts +20 -0
- package/dist/component/organism/Navbar/Navbar.js +64 -0
- package/dist/component/organism/Navbar/Navbar.js.map +1 -0
- package/dist/component/organism/Navbar/Navbar.module.js +19 -0
- package/dist/component/organism/Navbar/Navbar.module.js.map +1 -0
- package/dist/component/organism/PageHeader/PageHeader.d.ts +14 -0
- package/dist/component/organism/PageHeader/PageHeader.js +55 -0
- package/dist/component/organism/PageHeader/PageHeader.js.map +1 -0
- package/dist/component/organism/StatsGrid/StatsGrid.d.ts +12 -0
- package/dist/component/organism/StatsGrid/StatsGrid.js +46 -0
- package/dist/component/organism/StatsGrid/StatsGrid.js.map +1 -0
- package/dist/component/organism/StatsGrid/StatsGrid.module.js +17 -0
- package/dist/component/organism/StatsGrid/StatsGrid.module.js.map +1 -0
- package/dist/component/organism/Table/RowActions.d.ts +23 -0
- package/dist/component/organism/Table/RowActions.js +121 -0
- package/dist/component/organism/Table/RowActions.js.map +1 -0
- package/dist/component/organism/Table/Table.d.ts +51 -0
- package/dist/component/organism/Table/Table.js +110 -0
- package/dist/component/organism/Table/Table.js.map +1 -0
- package/dist/component/organism/ViewTable/ColumnComparator.d.ts +11 -0
- package/dist/component/organism/ViewTable/ColumnComparator.js +25 -0
- package/dist/component/organism/ViewTable/ColumnComparator.js.map +1 -0
- package/dist/component/organism/ViewTable/ViewTable.d.ts +53 -0
- package/dist/component/organism/ViewTable/ViewTable.js +115 -0
- package/dist/component/organism/ViewTable/ViewTable.js.map +1 -0
- package/dist/component/organism/ViewTable/useRowKey.d.ts +8 -0
- package/dist/component/organism/ViewTable/useRowKey.js +24 -0
- package/dist/component/organism/ViewTable/useRowKey.js.map +1 -0
- package/dist/component/template/CreateFormPage/CreateFormPage.d.ts +19 -0
- package/dist/component/template/CreateFormPage/CreateFormPage.js +41 -0
- package/dist/component/template/CreateFormPage/CreateFormPage.js.map +1 -0
- package/dist/component/template/EditFormPage/EditFormPage.d.ts +19 -0
- package/dist/component/template/EditFormPage/EditFormPage.js +42 -0
- package/dist/component/template/EditFormPage/EditFormPage.js.map +1 -0
- package/dist/component/template/FormPage/FormPage.d.ts +25 -0
- package/dist/component/template/FormPage/FormPage.js +130 -0
- package/dist/component/template/FormPage/FormPage.js.map +1 -0
- package/dist/component/template/FormPage/FormType.d.ts +6 -0
- package/dist/component/template/FormPage/FormType.js +12 -0
- package/dist/component/template/FormPage/FormType.js.map +1 -0
- package/dist/component/template/Layout/Layout.d.ts +21 -0
- package/dist/component/template/Layout/Layout.js +121 -0
- package/dist/component/template/Layout/Layout.js.map +1 -0
- package/dist/component/template/Layout/Layout.module.js +19 -0
- package/dist/component/template/Layout/Layout.module.js.map +1 -0
- package/dist/component/template/ListPage/ListPage.d.ts +32 -0
- package/dist/component/template/ListPage/ListPage.js +47 -0
- package/dist/component/template/ListPage/ListPage.js.map +1 -0
- package/dist/component/template/PrintPage/PrintPage.d.ts +25 -0
- package/dist/component/template/PrintPage/PrintPage.js +115 -0
- package/dist/component/template/PrintPage/PrintPage.js.map +1 -0
- package/dist/component/template/ViewPage/ViewPage.d.ts +11 -0
- package/dist/component/template/ViewPage/ViewPage.js +49 -0
- package/dist/component/template/ViewPage/ViewPage.js.map +1 -0
- package/dist/data/ListDataSource.d.ts +12 -0
- package/dist/data/ListDataSource.js +1 -0
- package/dist/data/SaveDataSource.d.ts +16 -0
- package/dist/data/SaveDataSource.js +1 -0
- package/dist/export/ExportCellText.d.ts +18 -0
- package/dist/export/ExportCellText.js +60 -0
- package/dist/export/ExportCellText.js.map +1 -0
- package/dist/export/ExportDocument.d.ts +127 -0
- package/dist/export/ExportDocument.js +59 -0
- package/dist/export/ExportDocument.js.map +1 -0
- package/dist/export/ExportDownload.d.ts +9 -0
- package/dist/export/ExportDownload.js +19 -0
- package/dist/export/ExportDownload.js.map +1 -0
- package/dist/export/ExportFileName.d.ts +11 -0
- package/dist/export/ExportFileName.js +24 -0
- package/dist/export/ExportFileName.js.map +1 -0
- package/dist/export/ExportFormat.d.ts +30 -0
- package/dist/export/ExportFormat.js +1 -0
- package/dist/export/ExportFormats.d.ts +12 -0
- package/dist/export/ExportFormats.js +16 -0
- package/dist/export/ExportFormats.js.map +1 -0
- package/dist/export/ExportTexts.d.ts +14 -0
- package/dist/export/ExportTexts.js +23 -0
- package/dist/export/ExportTexts.js.map +1 -0
- package/dist/export/csv/CsvFormat.d.ts +41 -0
- package/dist/export/csv/CsvFormat.js +91 -0
- package/dist/export/csv/CsvFormat.js.map +1 -0
- package/dist/export/xlsx/XlsxFormat.d.ts +35 -0
- package/dist/export/xlsx/XlsxFormat.js +66 -0
- package/dist/export/xlsx/XlsxFormat.js.map +1 -0
- package/dist/export/xlsx/XlsxNumberFormat.d.ts +8 -0
- package/dist/export/xlsx/XlsxNumberFormat.js +15 -0
- package/dist/export/xlsx/XlsxNumberFormat.js.map +1 -0
- package/dist/export/xlsx/XlsxSheetName.d.ts +12 -0
- package/dist/export/xlsx/XlsxSheetName.js +62 -0
- package/dist/export/xlsx/XlsxSheetName.js.map +1 -0
- package/dist/export/xlsx/XlsxSheetWriter.d.ts +67 -0
- package/dist/export/xlsx/XlsxSheetWriter.js +215 -0
- package/dist/export/xlsx/XlsxSheetWriter.js.map +1 -0
- package/dist/export/xlsx/XlsxStyle.d.ts +51 -0
- package/dist/export/xlsx/XlsxStyle.js +87 -0
- package/dist/export/xlsx/XlsxStyle.js.map +1 -0
- package/dist/hook/useIsMobile.d.ts +5 -0
- package/dist/hook/useIsMobile.js +16 -0
- package/dist/hook/useIsMobile.js.map +1 -0
- package/dist/hook/useKeyedService.d.ts +22 -0
- package/dist/hook/useKeyedService.js +38 -0
- package/dist/hook/useKeyedService.js.map +1 -0
- package/dist/hook/useLightColorSchemeOnPrint.d.ts +9 -0
- package/dist/hook/useLightColorSchemeOnPrint.js +36 -0
- package/dist/hook/useLightColorSchemeOnPrint.js.map +1 -0
- package/dist/hook/useService.d.ts +27 -0
- package/dist/hook/useService.js +23 -0
- package/dist/hook/useService.js.map +1 -0
- package/dist/http/ApiError.d.ts +13 -0
- package/dist/http/ApiError.js +22 -0
- package/dist/http/ApiError.js.map +1 -0
- package/dist/http/AxiosHttpClient.d.ts +21 -0
- package/dist/http/AxiosHttpClient.js +67 -0
- package/dist/http/AxiosHttpClient.js.map +1 -0
- package/dist/http/AxiosHttpClientConfig.d.ts +37 -0
- package/dist/http/AxiosHttpClientConfig.js +19 -0
- package/dist/http/AxiosHttpClientConfig.js.map +1 -0
- package/dist/i18n/KitLocale.d.ts +4 -0
- package/dist/i18n/KitLocale.js +7 -0
- package/dist/i18n/KitLocale.js.map +1 -0
- package/dist/i18n/KitMessages.d.ts +146 -0
- package/dist/i18n/KitMessages.js +1 -0
- package/dist/i18n/messages/enUS.d.ts +3 -0
- package/dist/i18n/messages/enUS.js +112 -0
- package/dist/i18n/messages/enUS.js.map +1 -0
- package/dist/i18n/messages/ptBR.d.ts +3 -0
- package/dist/i18n/messages/ptBR.js +97 -0
- package/dist/i18n/messages/ptBR.js.map +1 -0
- package/dist/i18n/resolveMessages.d.ts +13 -0
- package/dist/i18n/resolveMessages.js +29 -0
- package/dist/i18n/resolveMessages.js.map +1 -0
- package/dist/model/Identifiable.d.ts +7 -0
- package/dist/model/Identifiable.js +1 -0
- package/dist/provider/KitConfig.d.ts +26 -0
- package/dist/provider/KitConfig.js +1 -0
- package/dist/provider/KitContext.d.ts +9 -0
- package/dist/provider/KitContext.js +27 -0
- package/dist/provider/KitContext.js.map +1 -0
- package/dist/provider/KitProvider.d.ts +7 -0
- package/dist/provider/KitProvider.js +31 -0
- package/dist/provider/KitProvider.js.map +1 -0
- package/dist/provider/useKit.d.ts +15 -0
- package/dist/provider/useKit.js +28 -0
- package/dist/provider/useKit.js.map +1 -0
- package/dist/router/FormRouteSegments.d.ts +16 -0
- package/dist/router/FormRouteSegments.js +19 -0
- package/dist/router/FormRouteSegments.js.map +1 -0
- package/dist/router/RouterAdapter.d.ts +24 -0
- package/dist/router/RouterAdapter.js +1 -0
- package/dist/router/anchorRouter.d.ts +7 -0
- package/dist/router/anchorRouter.js +23 -0
- package/dist/router/anchorRouter.js.map +1 -0
- package/dist/styles/print.css +93 -0
- package/dist/styles.css +188 -0
- package/dist/util/ArrayUtil.d.ts +39 -0
- package/dist/util/ArrayUtil.js +48 -0
- package/dist/util/ArrayUtil.js.map +1 -0
- package/dist/util/ColorUtil.d.ts +7 -0
- package/dist/util/ColorUtil.js +16 -0
- package/dist/util/ColorUtil.js.map +1 -0
- package/dist/util/CompareUtil.d.ts +19 -0
- package/dist/util/CompareUtil.js +51 -0
- package/dist/util/CompareUtil.js.map +1 -0
- package/dist/util/DateUtil.d.ts +38 -0
- package/dist/util/DateUtil.js +55 -0
- package/dist/util/DateUtil.js.map +1 -0
- package/dist/util/DownloadUtil.d.ts +6 -0
- package/dist/util/DownloadUtil.js +25 -0
- package/dist/util/DownloadUtil.js.map +1 -0
- package/dist/util/EnumUtil.d.ts +19 -0
- package/dist/util/EnumUtil.js +32 -0
- package/dist/util/EnumUtil.js.map +1 -0
- package/dist/util/FormUtil.d.ts +8 -0
- package/dist/util/FormUtil.js +14 -0
- package/dist/util/FormUtil.js.map +1 -0
- package/dist/util/HtmlUtil.d.ts +8 -0
- package/dist/util/HtmlUtil.js +23 -0
- package/dist/util/HtmlUtil.js.map +1 -0
- package/dist/util/Notifications.d.ts +30 -0
- package/dist/util/Notifications.js +59 -0
- package/dist/util/Notifications.js.map +1 -0
- package/dist/util/NumberUtil.d.ts +19 -0
- package/dist/util/NumberUtil.js +33 -0
- package/dist/util/NumberUtil.js.map +1 -0
- package/dist/util/ObjectUtil.d.ts +22 -0
- package/dist/util/ObjectUtil.js +34 -0
- package/dist/util/ObjectUtil.js.map +1 -0
- package/dist/util/SearchParamsUtil.d.ts +23 -0
- package/dist/util/SearchParamsUtil.js +29 -0
- package/dist/util/SearchParamsUtil.js.map +1 -0
- package/dist/util/TransformData.d.ts +14 -0
- package/dist/util/TransformData.js +31 -0
- package/dist/util/TransformData.js.map +1 -0
- package/dist/util/ValidationUtil.d.ts +9 -0
- package/dist/util/ValidationUtil.js +16 -0
- package/dist/util/ValidationUtil.js.map +1 -0
- package/dist/util/parseActionsPageParams.d.ts +14 -0
- package/dist/util/parseActionsPageParams.js +29 -0
- package/dist/util/parseActionsPageParams.js.map +1 -0
- package/package.json +158 -5
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { exportMessages } from "../ExportTexts.js";
|
|
3
|
+
import { XlsxSheetWriter } from "./XlsxSheetWriter.js";
|
|
4
|
+
import { xlsxSheetNames } from "./XlsxSheetName.js";
|
|
5
|
+
import { xlsxStyles } from "./XlsxStyle.js";
|
|
6
|
+
// src/export/xlsx/XlsxFormat.ts
|
|
7
|
+
/**
|
|
8
|
+
* Exports to Excel (`.xlsx`) with [ExcelJS](https://github.com/exceljs/exceljs): a sheet in the file for each sheet
|
|
9
|
+
* of the document, with styles, the logo and the numbers in a numeric format (not text).
|
|
10
|
+
*
|
|
11
|
+
* ExcelJS is loaded on demand (dynamic `import()`), like ECharts: imported statically, it would be in the bundle of
|
|
12
|
+
* every page that can export, even if the user exports nothing.
|
|
13
|
+
* @author Manoel Campos
|
|
14
|
+
*/
|
|
15
|
+
var XlsxFormat = class {
|
|
16
|
+
id = "xlsx";
|
|
17
|
+
label = "Excel (.xlsx)";
|
|
18
|
+
extension = "xlsx";
|
|
19
|
+
mimeType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
|
20
|
+
multipleSheets = true;
|
|
21
|
+
styles;
|
|
22
|
+
/** @param options options of the format, such as the colors of the file */
|
|
23
|
+
constructor(options = {}) {
|
|
24
|
+
this.styles = xlsxStyles(options.colors);
|
|
25
|
+
}
|
|
26
|
+
async generate(document) {
|
|
27
|
+
const buffer = await (await this.buildWorkbook(document)).xlsx.writeBuffer();
|
|
28
|
+
return new Blob([buffer], { type: this.mimeType });
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Builds the workbook with a sheet for each sheet of the document.
|
|
32
|
+
* @param document data to export
|
|
33
|
+
* @return the workbook ready to be written
|
|
34
|
+
* @throws Error if the document has no sheets
|
|
35
|
+
*/
|
|
36
|
+
async buildWorkbook(document) {
|
|
37
|
+
if (document.sheets.length === 0) throw new Error("There is no data to export.");
|
|
38
|
+
const workbook = new (await (loadExcelJs())).Workbook();
|
|
39
|
+
workbook.creator = document.branding.systemName;
|
|
40
|
+
workbook.title = document.title;
|
|
41
|
+
workbook.created = document.generatedAt;
|
|
42
|
+
const logo = document.branding.logo;
|
|
43
|
+
const logoImageId = logo ? workbook.addImage({
|
|
44
|
+
base64: logo.pngDataUrl,
|
|
45
|
+
extension: "png"
|
|
46
|
+
}) : void 0;
|
|
47
|
+
const defaultName = exportMessages(document).defaultSheetName;
|
|
48
|
+
const names = xlsxSheetNames(document.sheets.map((sheet) => sheet.name), defaultName);
|
|
49
|
+
document.sheets.forEach((sheet, i) => {
|
|
50
|
+
new XlsxSheetWriter(workbook.addWorksheet(names[i]), document, this.styles).write(sheet, logoImageId);
|
|
51
|
+
});
|
|
52
|
+
return workbook;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Loads ExcelJS. Being a CommonJS module, depending on the bundler the classes come in the module itself or in
|
|
57
|
+
* `default`.
|
|
58
|
+
* @return the ExcelJS module
|
|
59
|
+
*/
|
|
60
|
+
async function loadExcelJs() {
|
|
61
|
+
const excelJs = await import("exceljs");
|
|
62
|
+
return excelJs.default ?? excelJs;
|
|
63
|
+
}
|
|
64
|
+
export { XlsxFormat };
|
|
65
|
+
|
|
66
|
+
//# sourceMappingURL=XlsxFormat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"XlsxFormat.js","names":[],"sources":["../../../src/export/xlsx/XlsxFormat.ts"],"sourcesContent":["import type { Workbook } from 'exceljs';\n\nimport { ExportDocument } from '../ExportDocument';\nimport { ExportFormat } from '../ExportFormat';\nimport { exportMessages } from '../ExportTexts';\nimport { XlsxSheetWriter } from './XlsxSheetWriter';\nimport { xlsxSheetNames } from './XlsxSheetName';\nimport { XlsxColors, xlsxStyles, XlsxStyles } from './XlsxStyle';\n\ntype ExcelJsModule = typeof import('exceljs');\n\n/** Options of an {@link XlsxFormat}. */\nexport type XlsxFormatOptions = {\n /** Colors of the file (e.g. the brand colors of the app); the ones not given use the defaults. */\n colors?: Partial<XlsxColors>;\n};\n\n/**\n * Exports to Excel (`.xlsx`) with [ExcelJS](https://github.com/exceljs/exceljs): a sheet in the file for each sheet\n * of the document, with styles, the logo and the numbers in a numeric format (not text).\n *\n * ExcelJS is loaded on demand (dynamic `import()`), like ECharts: imported statically, it would be in the bundle of\n * every page that can export, even if the user exports nothing.\n * @author Manoel Campos\n */\nexport class XlsxFormat implements ExportFormat {\n readonly id = 'xlsx';\n readonly label = 'Excel (.xlsx)';\n readonly extension = 'xlsx';\n readonly mimeType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';\n readonly multipleSheets = true;\n\n private readonly styles: XlsxStyles;\n\n /** @param options options of the format, such as the colors of the file */\n constructor(options: XlsxFormatOptions = {}) {\n this.styles = xlsxStyles(options.colors);\n }\n\n async generate(document: ExportDocument): Promise<Blob> {\n const workbook = await this.buildWorkbook(document);\n const buffer = await workbook.xlsx.writeBuffer();\n\n return new Blob([buffer], { type: this.mimeType });\n }\n\n /**\n * Builds the workbook with a sheet for each sheet of the document.\n * @param document data to export\n * @return the workbook ready to be written\n * @throws Error if the document has no sheets\n */\n async buildWorkbook(document: ExportDocument): Promise<Workbook> {\n // Excel does not open a file without any sheet.\n if (document.sheets.length === 0) throw new Error('There is no data to export.');\n\n const excelJs = await loadExcelJs();\n const workbook = new excelJs.Workbook();\n workbook.creator = document.branding.systemName;\n workbook.title = document.title;\n workbook.created = document.generatedAt;\n\n const logo = document.branding.logo;\n const logoImageId = logo ? workbook.addImage({ base64: logo.pngDataUrl, extension: 'png' }) : undefined;\n const defaultName = exportMessages(document).defaultSheetName;\n const names = xlsxSheetNames(\n document.sheets.map(sheet => sheet.name),\n defaultName\n );\n document.sheets.forEach((sheet, i) => {\n new XlsxSheetWriter(workbook.addWorksheet(names[i]), document, this.styles).write(sheet, logoImageId);\n });\n\n return workbook;\n }\n}\n\n/**\n * Loads ExcelJS. Being a CommonJS module, depending on the bundler the classes come in the module itself or in\n * `default`.\n * @return the ExcelJS module\n */\nasync function loadExcelJs(): Promise<ExcelJsModule> {\n const excelJs: ExcelJsModule & { default?: ExcelJsModule } = await import('exceljs');\n\n return excelJs.default ?? excelJs;\n}\n"],"mappings":";;;;;;;;;;;;;;AAyBA,IAAa,aAAb,MAAgD;CAC5C,KAAc;CACd,QAAiB;CACjB,YAAqB;CACrB,WAAoB;CACpB,iBAA0B;CAE1B;;CAGA,YAAY,UAA6B,CAAC,GAAG;EACzC,KAAK,SAAS,WAAW,QAAQ,MAAM;CAC3C;CAEA,MAAM,SAAS,UAAyC;EAEpD,MAAM,SAAS,OAAM,MADE,KAAK,cAAc,QAAQ,EAAA,CACpB,KAAK,YAAY;EAE/C,OAAO,IAAI,KAAK,CAAC,MAAM,GAAG,EAAE,MAAM,KAAK,SAAS,CAAC;CACrD;;;;;;;CAQA,MAAM,cAAc,UAA6C;EAE7D,IAAI,SAAS,OAAO,WAAW,GAAG,MAAM,IAAI,MAAM,6BAA6B;EAG/E,MAAM,WAAW,KAAI,OADC,YAAY,GAAA,CACL,SAAS;EACtC,SAAS,UAAU,SAAS,SAAS;EACrC,SAAS,QAAQ,SAAS;EAC1B,SAAS,UAAU,SAAS;EAE5B,MAAM,OAAO,SAAS,SAAS;EAC/B,MAAM,cAAc,OAAO,SAAS,SAAS;GAAE,QAAQ,KAAK;GAAY,WAAW;EAAM,CAAC,IAAI,KAAA;EAC9F,MAAM,cAAc,eAAe,QAAQ,CAAC,CAAC;EAC7C,MAAM,QAAQ,eACV,SAAS,OAAO,KAAI,UAAS,MAAM,IAAI,GACvC,WACJ;EACA,SAAS,OAAO,SAAS,OAAO,MAAM;GAClC,IAAI,gBAAgB,SAAS,aAAa,MAAM,EAAE,GAAG,UAAU,KAAK,MAAM,CAAC,CAAC,MAAM,OAAO,WAAW;EACxG,CAAC;EAED,OAAO;CACX;AACJ;;;;;;AAOA,eAAe,cAAsC;CACjD,MAAM,UAAuD,MAAM,OAAO;CAE1E,OAAO,QAAQ,WAAW;AAC9B"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { NumberFormat } from '../ExportDocument';
|
|
2
|
+
/**
|
|
3
|
+
* Converts a {@link NumberFormat} to the Excel number format code. The code uses `.` and `,` as in the American
|
|
4
|
+
* format, but Excel shows the separators of the language of whoever opens the file (e.g. "1.234,56" in Portuguese).
|
|
5
|
+
* @param format decimal places and whether the value is a percentage (in the 0..1 scale)
|
|
6
|
+
* @return the format code (e.g. `#,##0.00` or `0.0%`)
|
|
7
|
+
*/
|
|
8
|
+
export declare function xlsxNumberFormat(format: NumberFormat): string;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
// src/export/xlsx/XlsxNumberFormat.ts
|
|
3
|
+
/**
|
|
4
|
+
* Converts a {@link NumberFormat} to the Excel number format code. The code uses `.` and `,` as in the American
|
|
5
|
+
* format, but Excel shows the separators of the language of whoever opens the file (e.g. "1.234,56" in Portuguese).
|
|
6
|
+
* @param format decimal places and whether the value is a percentage (in the 0..1 scale)
|
|
7
|
+
* @return the format code (e.g. `#,##0.00` or `0.0%`)
|
|
8
|
+
*/
|
|
9
|
+
function xlsxNumberFormat(format) {
|
|
10
|
+
const decimalPart = format.decimals > 0 ? `.${"0".repeat(format.decimals)}` : "";
|
|
11
|
+
return format.percent ? `0${decimalPart}%` : `#,##0${decimalPart}`;
|
|
12
|
+
}
|
|
13
|
+
export { xlsxNumberFormat };
|
|
14
|
+
|
|
15
|
+
//# sourceMappingURL=XlsxNumberFormat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"XlsxNumberFormat.js","names":[],"sources":["../../../src/export/xlsx/XlsxNumberFormat.ts"],"sourcesContent":["import { NumberFormat } from '../ExportDocument';\n\n/**\n * Converts a {@link NumberFormat} to the Excel number format code. The code uses `.` and `,` as in the American\n * format, but Excel shows the separators of the language of whoever opens the file (e.g. \"1.234,56\" in Portuguese).\n * @param format decimal places and whether the value is a percentage (in the 0..1 scale)\n * @return the format code (e.g. `#,##0.00` or `0.0%`)\n */\nexport function xlsxNumberFormat(format: NumberFormat): string {\n const decimalPart = format.decimals > 0 ? `.${'0'.repeat(format.decimals)}` : '';\n\n return format.percent ? `0${decimalPart}%` : `#,##0${decimalPart}`;\n}\n"],"mappings":";;;;;;;;AAQA,SAAgB,iBAAiB,QAA8B;CAC3D,MAAM,cAAc,OAAO,WAAW,IAAI,IAAI,IAAI,OAAO,OAAO,QAAQ,MAAM;CAE9E,OAAO,OAAO,UAAU,IAAI,YAAY,KAAK,QAAQ;AACzD"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Maximum length of a sheet name in Excel. */
|
|
2
|
+
export declare const MAX_SHEET_NAME_LENGTH = 31;
|
|
3
|
+
/**
|
|
4
|
+
* Adapts the sheet names to the Excel rules: at most {@link MAX_SHEET_NAME_LENGTH} characters, without `[ ] : * ? /
|
|
5
|
+
* \`, without an apostrophe at the beginning or at the end, without the reserved name "History" and without repeating
|
|
6
|
+
* a name (Excel is case insensitive). A repeated or reserved name gets a number at the end (e.g. "Sales (2)").
|
|
7
|
+
* @param names desired names, in the order of the sheets
|
|
8
|
+
* @param defaultName builds the name of a sheet without any valid character, from its position (starting at 1);
|
|
9
|
+
* defaults to the one of the default locale
|
|
10
|
+
* @return the names accepted by Excel, in the same order
|
|
11
|
+
*/
|
|
12
|
+
export declare function xlsxSheetNames(names: string[], defaultName?: (position: number) => string): string[];
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { DEFAULT_MESSAGES } from "../../i18n/resolveMessages.js";
|
|
3
|
+
// src/export/xlsx/XlsxSheetName.ts
|
|
4
|
+
/** Maximum length of a sheet name in Excel. */
|
|
5
|
+
var MAX_SHEET_NAME_LENGTH = 31;
|
|
6
|
+
/** Characters Excel does not accept in a sheet name. */
|
|
7
|
+
var INVALID_CHARS = /[[\]:*?/\\]/g;
|
|
8
|
+
/** Spaces and apostrophes at the ends of the name: Excel accepts no apostrophe at the beginning or at the end. */
|
|
9
|
+
var EDGES = /^[\s']+|[\s']+$/g;
|
|
10
|
+
/** Name reserved by Excel, which cannot be used by a sheet (case insensitive). */
|
|
11
|
+
var RESERVED_NAME = "history";
|
|
12
|
+
/**
|
|
13
|
+
* Adapts the sheet names to the Excel rules: at most {@link MAX_SHEET_NAME_LENGTH} characters, without `[ ] : * ? /
|
|
14
|
+
* \`, without an apostrophe at the beginning or at the end, without the reserved name "History" and without repeating
|
|
15
|
+
* a name (Excel is case insensitive). A repeated or reserved name gets a number at the end (e.g. "Sales (2)").
|
|
16
|
+
* @param names desired names, in the order of the sheets
|
|
17
|
+
* @param defaultName builds the name of a sheet without any valid character, from its position (starting at 1);
|
|
18
|
+
* defaults to the one of the default locale
|
|
19
|
+
* @return the names accepted by Excel, in the same order
|
|
20
|
+
*/
|
|
21
|
+
function xlsxSheetNames(names, defaultName = DEFAULT_MESSAGES.export.defaultSheetName) {
|
|
22
|
+
const usedNames = /* @__PURE__ */ new Set([RESERVED_NAME]);
|
|
23
|
+
return names.map((name, i) => {
|
|
24
|
+
const sheetName = uniqueName(sanitize(name) || defaultName(i + 1), usedNames);
|
|
25
|
+
usedNames.add(sheetName.toLowerCase());
|
|
26
|
+
return sheetName;
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Removes from the name the characters Excel does not accept.
|
|
31
|
+
* @param name desired name of the sheet
|
|
32
|
+
* @return the name without the invalid characters and without spaces or apostrophes at the ends
|
|
33
|
+
*/
|
|
34
|
+
function sanitize(name) {
|
|
35
|
+
return name.replace(INVALID_CHARS, "-").replace(EDGES, "");
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Cuts the name to the maximum length and adds a number if it is already used.
|
|
39
|
+
* @param name name of the sheet, already without invalid characters
|
|
40
|
+
* @param usedNames names already used, in lower case
|
|
41
|
+
* @return a name not used yet
|
|
42
|
+
*/
|
|
43
|
+
function uniqueName(name, usedNames) {
|
|
44
|
+
let candidate = cut(name, 31);
|
|
45
|
+
for (let number = 2; usedNames.has(candidate.toLowerCase()); number++) {
|
|
46
|
+
const suffix = ` (${number})`;
|
|
47
|
+
candidate = cut(name, 31 - suffix.length) + suffix;
|
|
48
|
+
}
|
|
49
|
+
return candidate;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Cuts the name to a length and removes again the spaces and apostrophes at the ends, which the cut may have left.
|
|
53
|
+
* @param name name of the sheet
|
|
54
|
+
* @param maxLength maximum length
|
|
55
|
+
* @return the cut name
|
|
56
|
+
*/
|
|
57
|
+
function cut(name, maxLength) {
|
|
58
|
+
return name.slice(0, maxLength).replace(EDGES, "");
|
|
59
|
+
}
|
|
60
|
+
export { MAX_SHEET_NAME_LENGTH, xlsxSheetNames };
|
|
61
|
+
|
|
62
|
+
//# sourceMappingURL=XlsxSheetName.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"XlsxSheetName.js","names":[],"sources":["../../../src/export/xlsx/XlsxSheetName.ts"],"sourcesContent":["import { DEFAULT_MESSAGES } from '../../i18n/resolveMessages';\n\n/** Maximum length of a sheet name in Excel. */\nexport const MAX_SHEET_NAME_LENGTH = 31;\n\n/** Characters Excel does not accept in a sheet name. */\nconst INVALID_CHARS = /[[\\]:*?/\\\\]/g;\n\n/** Spaces and apostrophes at the ends of the name: Excel accepts no apostrophe at the beginning or at the end. */\nconst EDGES = /^[\\s']+|[\\s']+$/g;\n\n/** Name reserved by Excel, which cannot be used by a sheet (case insensitive). */\nconst RESERVED_NAME = 'history';\n\n/**\n * Adapts the sheet names to the Excel rules: at most {@link MAX_SHEET_NAME_LENGTH} characters, without `[ ] : * ? /\n * \\`, without an apostrophe at the beginning or at the end, without the reserved name \"History\" and without repeating\n * a name (Excel is case insensitive). A repeated or reserved name gets a number at the end (e.g. \"Sales (2)\").\n * @param names desired names, in the order of the sheets\n * @param defaultName builds the name of a sheet without any valid character, from its position (starting at 1);\n * defaults to the one of the default locale\n * @return the names accepted by Excel, in the same order\n */\nexport function xlsxSheetNames(\n names: string[],\n defaultName: (position: number) => string = DEFAULT_MESSAGES.export.defaultSheetName\n): string[] {\n const usedNames = new Set<string>([RESERVED_NAME]);\n\n return names.map((name, i) => {\n const sheetName = uniqueName(sanitize(name) || defaultName(i + 1), usedNames);\n usedNames.add(sheetName.toLowerCase());\n return sheetName;\n });\n}\n\n/**\n * Removes from the name the characters Excel does not accept.\n * @param name desired name of the sheet\n * @return the name without the invalid characters and without spaces or apostrophes at the ends\n */\nfunction sanitize(name: string): string {\n return name.replace(INVALID_CHARS, '-').replace(EDGES, '');\n}\n\n/**\n * Cuts the name to the maximum length and adds a number if it is already used.\n * @param name name of the sheet, already without invalid characters\n * @param usedNames names already used, in lower case\n * @return a name not used yet\n */\nfunction uniqueName(name: string, usedNames: Set<string>): string {\n let candidate = cut(name, MAX_SHEET_NAME_LENGTH);\n for (let number = 2; usedNames.has(candidate.toLowerCase()); number++) {\n const suffix = ` (${number})`;\n candidate = cut(name, MAX_SHEET_NAME_LENGTH - suffix.length) + suffix;\n }\n\n return candidate;\n}\n\n/**\n * Cuts the name to a length and removes again the spaces and apostrophes at the ends, which the cut may have left.\n * @param name name of the sheet\n * @param maxLength maximum length\n * @return the cut name\n */\nfunction cut(name: string, maxLength: number): string {\n return name.slice(0, maxLength).replace(EDGES, '');\n}\n"],"mappings":";;;;AAGA,IAAa,wBAAwB;;AAGrC,IAAM,gBAAgB;;AAGtB,IAAM,QAAQ;;AAGd,IAAM,gBAAgB;;;;;;;;;;AAWtB,SAAgB,eACZ,OACA,cAA4C,iBAAiB,OAAO,kBAC5D;CACR,MAAM,4BAAY,IAAI,IAAY,CAAC,aAAa,CAAC;CAEjD,OAAO,MAAM,KAAK,MAAM,MAAM;EAC1B,MAAM,YAAY,WAAW,SAAS,IAAI,KAAK,YAAY,IAAI,CAAC,GAAG,SAAS;EAC5E,UAAU,IAAI,UAAU,YAAY,CAAC;EACrC,OAAO;CACX,CAAC;AACL;;;;;;AAOA,SAAS,SAAS,MAAsB;CACpC,OAAO,KAAK,QAAQ,eAAe,GAAG,CAAC,CAAC,QAAQ,OAAO,EAAE;AAC7D;;;;;;;AAQA,SAAS,WAAW,MAAc,WAAgC;CAC9D,IAAI,YAAY,IAAI,MAAA,EAA2B;CAC/C,KAAK,IAAI,SAAS,GAAG,UAAU,IAAI,UAAU,YAAY,CAAC,GAAG,UAAU;EACnE,MAAM,SAAS,KAAK,OAAO;EAC3B,YAAY,IAAI,MAAA,KAA8B,OAAO,MAAM,IAAI;CACnE;CAEA,OAAO;AACX;;;;;;;AAQA,SAAS,IAAI,MAAc,WAA2B;CAClD,OAAO,KAAK,MAAM,GAAG,SAAS,CAAC,CAAC,QAAQ,OAAO,EAAE;AACrD"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { Worksheet } from 'exceljs';
|
|
2
|
+
import { ExportDocument, ExportSheet } from '../ExportDocument';
|
|
3
|
+
import { XlsxStyles } from './XlsxStyle';
|
|
4
|
+
/**
|
|
5
|
+
* Writes a sheet of the `.xlsx`, from top to bottom: the logo, the title, the generation date, the context info, the
|
|
6
|
+
* table and the footer with the link of the system. Numbers are numeric (not text), with the format of each cell.
|
|
7
|
+
* @author Manoel Campos
|
|
8
|
+
*/
|
|
9
|
+
export declare class XlsxSheetWriter {
|
|
10
|
+
private readonly worksheet;
|
|
11
|
+
private readonly document;
|
|
12
|
+
private readonly messages;
|
|
13
|
+
private readonly styles;
|
|
14
|
+
/** Next free row of the sheet (starts at 1, as in Excel). */
|
|
15
|
+
private nextRow;
|
|
16
|
+
/**
|
|
17
|
+
* @param worksheet sheet to write to
|
|
18
|
+
* @param document exported document, where the title, the context, the texts and the visual identity come from
|
|
19
|
+
* @param styles fonts, fills and borders of the sheet
|
|
20
|
+
*/
|
|
21
|
+
constructor(worksheet: Worksheet, document: ExportDocument, styles?: XlsxStyles);
|
|
22
|
+
/**
|
|
23
|
+
* Writes the whole sheet.
|
|
24
|
+
* @param sheet columns and rows of the table
|
|
25
|
+
* @param logoImageId id of the logo registered in the workbook; absent to show no logo
|
|
26
|
+
*/
|
|
27
|
+
write(sheet: ExportSheet, logoImageId?: number): void;
|
|
28
|
+
/**
|
|
29
|
+
* Writes the logo, the title, the generation date and the context info.
|
|
30
|
+
* @param logoImageId id of the logo registered in the workbook
|
|
31
|
+
*/
|
|
32
|
+
private writeHeader;
|
|
33
|
+
/**
|
|
34
|
+
* Writes the table: the header and the rows, with borders, zebra stripes and the Excel filter in the header.
|
|
35
|
+
* @param sheet columns of the table
|
|
36
|
+
* @param rows cells of each row, already classified
|
|
37
|
+
* @return the number of the header row
|
|
38
|
+
*/
|
|
39
|
+
private writeTable;
|
|
40
|
+
/**
|
|
41
|
+
* Writes a row of the table.
|
|
42
|
+
* @param row cells of the row, already classified
|
|
43
|
+
* @param index position of the row in the table (0 for the first one), used in the zebra stripes
|
|
44
|
+
*/
|
|
45
|
+
private writeTableRow;
|
|
46
|
+
/** Writes the footer, with the name of the system and the link to it. */
|
|
47
|
+
private writeFooter;
|
|
48
|
+
/**
|
|
49
|
+
* Fits the width of each column to the longest text of the table. The rows outside the table (title, info and
|
|
50
|
+
* footer) do not count, since their text can flow to the empty cells beside them.
|
|
51
|
+
* @param sheet columns of the table
|
|
52
|
+
* @param rows cells of each row, already classified
|
|
53
|
+
*/
|
|
54
|
+
private adjustColumnWidths;
|
|
55
|
+
/**
|
|
56
|
+
* Sets up printing: landscape, the table fitting the page width, the header repeated on every page and a page
|
|
57
|
+
* footer with the system and the page number.
|
|
58
|
+
* @param headerRow number of the header row
|
|
59
|
+
*/
|
|
60
|
+
private setupPrinting;
|
|
61
|
+
/**
|
|
62
|
+
* Adds a row at the next free position.
|
|
63
|
+
* @param values values of the cells, from the first column on
|
|
64
|
+
* @return the created row
|
|
65
|
+
*/
|
|
66
|
+
private addRow;
|
|
67
|
+
}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cellText } from "../ExportCellText.js";
|
|
3
|
+
import { classifyCell } from "../ExportDocument.js";
|
|
4
|
+
import { exportLocale, exportMessages } from "../ExportTexts.js";
|
|
5
|
+
import { xlsxNumberFormat } from "./XlsxNumberFormat.js";
|
|
6
|
+
import { xlsxStyles } from "./XlsxStyle.js";
|
|
7
|
+
// src/export/xlsx/XlsxSheetWriter.ts
|
|
8
|
+
/**
|
|
9
|
+
* Writes a sheet of the `.xlsx`, from top to bottom: the logo, the title, the generation date, the context info, the
|
|
10
|
+
* table and the footer with the link of the system. Numbers are numeric (not text), with the format of each cell.
|
|
11
|
+
* @author Manoel Campos
|
|
12
|
+
*/
|
|
13
|
+
var XlsxSheetWriter = class {
|
|
14
|
+
worksheet;
|
|
15
|
+
document;
|
|
16
|
+
messages;
|
|
17
|
+
styles;
|
|
18
|
+
/** Next free row of the sheet (starts at 1, as in Excel). */
|
|
19
|
+
nextRow = 1;
|
|
20
|
+
/**
|
|
21
|
+
* @param worksheet sheet to write to
|
|
22
|
+
* @param document exported document, where the title, the context, the texts and the visual identity come from
|
|
23
|
+
* @param styles fonts, fills and borders of the sheet
|
|
24
|
+
*/
|
|
25
|
+
constructor(worksheet, document, styles = xlsxStyles()) {
|
|
26
|
+
this.worksheet = worksheet;
|
|
27
|
+
this.document = document;
|
|
28
|
+
this.messages = exportMessages(document);
|
|
29
|
+
this.styles = styles;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Writes the whole sheet.
|
|
33
|
+
* @param sheet columns and rows of the table
|
|
34
|
+
* @param logoImageId id of the logo registered in the workbook; absent to show no logo
|
|
35
|
+
*/
|
|
36
|
+
write(sheet, logoImageId) {
|
|
37
|
+
this.writeHeader(logoImageId);
|
|
38
|
+
const rows = classifyRows(sheet, this.messages.invalidCell);
|
|
39
|
+
const headerRow = this.writeTable(sheet, rows);
|
|
40
|
+
this.writeFooter();
|
|
41
|
+
this.adjustColumnWidths(sheet, rows);
|
|
42
|
+
this.setupPrinting(headerRow);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Writes the logo, the title, the generation date and the context info.
|
|
46
|
+
* @param logoImageId id of the logo registered in the workbook
|
|
47
|
+
*/
|
|
48
|
+
writeHeader(logoImageId) {
|
|
49
|
+
const { logo } = this.document.branding;
|
|
50
|
+
if (logoImageId !== void 0 && logo) {
|
|
51
|
+
const width = Math.round(48 * logo.width / logo.height);
|
|
52
|
+
this.worksheet.addImage(logoImageId, {
|
|
53
|
+
tl: {
|
|
54
|
+
col: 0,
|
|
55
|
+
row: 0
|
|
56
|
+
},
|
|
57
|
+
ext: {
|
|
58
|
+
width,
|
|
59
|
+
height: 48
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
this.nextRow += 3;
|
|
63
|
+
}
|
|
64
|
+
this.addRow([this.document.title]).getCell(1).font = this.styles.titleFont;
|
|
65
|
+
this.addRow([this.messages.generatedAt(this.document.generatedAt)]).getCell(1).font = this.styles.subtitleFont;
|
|
66
|
+
this.document.info.forEach((info) => {
|
|
67
|
+
this.addRow([]).getCell(1).value = { richText: [{
|
|
68
|
+
font: this.styles.infoLabelFont,
|
|
69
|
+
text: `${info.label}: `
|
|
70
|
+
}, { text: info.value }] };
|
|
71
|
+
});
|
|
72
|
+
this.nextRow++;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Writes the table: the header and the rows, with borders, zebra stripes and the Excel filter in the header.
|
|
76
|
+
* @param sheet columns of the table
|
|
77
|
+
* @param rows cells of each row, already classified
|
|
78
|
+
* @return the number of the header row
|
|
79
|
+
*/
|
|
80
|
+
writeTable(sheet, rows) {
|
|
81
|
+
const headerRow = this.nextRow;
|
|
82
|
+
this.addRow(sheet.columns.map((column) => column.header)).eachCell((cell) => {
|
|
83
|
+
cell.font = this.styles.headerFont;
|
|
84
|
+
cell.fill = this.styles.headerFill;
|
|
85
|
+
cell.border = this.styles.cellBorder;
|
|
86
|
+
cell.alignment = {
|
|
87
|
+
vertical: "middle",
|
|
88
|
+
wrapText: true
|
|
89
|
+
};
|
|
90
|
+
});
|
|
91
|
+
rows.forEach((row, i) => this.writeTableRow(row, i));
|
|
92
|
+
if (rows.length > 0 && sheet.columns.length > 0) this.worksheet.autoFilter = {
|
|
93
|
+
from: {
|
|
94
|
+
row: headerRow,
|
|
95
|
+
column: 1
|
|
96
|
+
},
|
|
97
|
+
to: {
|
|
98
|
+
row: headerRow + rows.length,
|
|
99
|
+
column: sheet.columns.length
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
return headerRow;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Writes a row of the table.
|
|
106
|
+
* @param row cells of the row, already classified
|
|
107
|
+
* @param index position of the row in the table (0 for the first one), used in the zebra stripes
|
|
108
|
+
*/
|
|
109
|
+
writeTableRow(row, index) {
|
|
110
|
+
const excelRow = this.worksheet.getRow(this.nextRow++);
|
|
111
|
+
row.forEach((classified, i) => {
|
|
112
|
+
const cell = excelRow.getCell(i + 1);
|
|
113
|
+
writeCell(cell, classified, this.styles);
|
|
114
|
+
cell.border = this.styles.cellBorder;
|
|
115
|
+
if (index % 2 === 1) cell.fill = this.styles.zebraFill;
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
/** Writes the footer, with the name of the system and the link to it. */
|
|
119
|
+
writeFooter() {
|
|
120
|
+
const { branding } = this.document;
|
|
121
|
+
this.nextRow++;
|
|
122
|
+
this.addRow([this.messages.footer(branding.systemName)]).getCell(1).font = this.styles.footerFont;
|
|
123
|
+
const link = this.addRow([]).getCell(1);
|
|
124
|
+
link.value = {
|
|
125
|
+
text: branding.siteUrl,
|
|
126
|
+
hyperlink: branding.siteUrl
|
|
127
|
+
};
|
|
128
|
+
link.font = this.styles.linkFont;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Fits the width of each column to the longest text of the table. The rows outside the table (title, info and
|
|
132
|
+
* footer) do not count, since their text can flow to the empty cells beside them.
|
|
133
|
+
* @param sheet columns of the table
|
|
134
|
+
* @param rows cells of each row, already classified
|
|
135
|
+
*/
|
|
136
|
+
adjustColumnWidths(sheet, rows) {
|
|
137
|
+
const locale = exportLocale(this.document);
|
|
138
|
+
sheet.columns.forEach((column, i) => {
|
|
139
|
+
const maxLength = rows.reduce((max, row) => Math.max(max, cellText(row[i], true, locale).length), column.header.length);
|
|
140
|
+
this.worksheet.getColumn(i + 1).width = Math.min(60, Math.max(8, maxLength + 2));
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Sets up printing: landscape, the table fitting the page width, the header repeated on every page and a page
|
|
145
|
+
* footer with the system and the page number.
|
|
146
|
+
* @param headerRow number of the header row
|
|
147
|
+
*/
|
|
148
|
+
setupPrinting(headerRow) {
|
|
149
|
+
this.worksheet.pageSetup = {
|
|
150
|
+
...this.worksheet.pageSetup,
|
|
151
|
+
orientation: "landscape",
|
|
152
|
+
fitToPage: true,
|
|
153
|
+
fitToWidth: 1,
|
|
154
|
+
fitToHeight: 0,
|
|
155
|
+
printTitlesRow: `${headerRow}:${headerRow}`
|
|
156
|
+
};
|
|
157
|
+
const { branding } = this.document;
|
|
158
|
+
const footer = `${this.messages.footer(branding.systemName)} - ${branding.siteUrl}`.replaceAll("&", "&&");
|
|
159
|
+
this.worksheet.headerFooter.oddFooter = `&L${footer}&R${this.messages.excelPageNumber}`;
|
|
160
|
+
this.worksheet.views = [{ showGridLines: false }];
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Adds a row at the next free position.
|
|
164
|
+
* @param values values of the cells, from the first column on
|
|
165
|
+
* @return the created row
|
|
166
|
+
*/
|
|
167
|
+
addRow(values) {
|
|
168
|
+
const row = this.worksheet.getRow(this.nextRow++);
|
|
169
|
+
values.forEach((value, i) => {
|
|
170
|
+
row.getCell(i + 1).value = value;
|
|
171
|
+
});
|
|
172
|
+
return row;
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
/**
|
|
176
|
+
* Classifies the cells of all rows of the table, completing with empty cells the rows shorter than the number of
|
|
177
|
+
* columns.
|
|
178
|
+
* @param sheet columns and rows of the table
|
|
179
|
+
* @param invalidText text of an infinite number
|
|
180
|
+
* @return a classified cell per column, in each row
|
|
181
|
+
* @throws Error if a row has more cells than columns, since the extra data would be lost without warning
|
|
182
|
+
*/
|
|
183
|
+
function classifyRows(sheet, invalidText) {
|
|
184
|
+
return sheet.rows.map((row, rowIndex) => {
|
|
185
|
+
if (row.length > sheet.columns.length) throw new Error(`Row ${rowIndex + 1} of the sheet "${sheet.name}" has ${row.length} cells, but the sheet has ${sheet.columns.length} columns.`);
|
|
186
|
+
return sheet.columns.map((column, i) => classifyCell(row[i], column.format, invalidText));
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Writes the value of a table cell, with the number format and the highlight of the invalid results.
|
|
191
|
+
* @param cell Excel cell
|
|
192
|
+
* @param classified value already classified (see {@link classifyCell})
|
|
193
|
+
* @param styles styles of the sheet, for the highlight of the invalid results
|
|
194
|
+
*/
|
|
195
|
+
function writeCell(cell, classified, styles) {
|
|
196
|
+
switch (classified.kind) {
|
|
197
|
+
case "empty":
|
|
198
|
+
cell.value = null;
|
|
199
|
+
break;
|
|
200
|
+
case "text":
|
|
201
|
+
cell.value = classified.text;
|
|
202
|
+
break;
|
|
203
|
+
case "invalid":
|
|
204
|
+
cell.value = classified.text;
|
|
205
|
+
cell.font = styles.invalidFont;
|
|
206
|
+
cell.alignment = { horizontal: "right" };
|
|
207
|
+
break;
|
|
208
|
+
case "number":
|
|
209
|
+
cell.value = classified.value;
|
|
210
|
+
cell.numFmt = xlsxNumberFormat(classified.format);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
export { XlsxSheetWriter };
|
|
214
|
+
|
|
215
|
+
//# sourceMappingURL=XlsxSheetWriter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"XlsxSheetWriter.js","names":[],"sources":["../../../src/export/xlsx/XlsxSheetWriter.ts"],"sourcesContent":["import type { Cell, Row, Worksheet } from 'exceljs';\n\nimport { ExportMessages } from '../../i18n/KitMessages';\nimport { cellText } from '../ExportCellText';\nimport { ClassifiedCell, classifyCell, ExportDocument, ExportSheet } from '../ExportDocument';\nimport { exportLocale, exportMessages } from '../ExportTexts';\nimport { xlsxNumberFormat } from './XlsxNumberFormat';\nimport {\n COLUMN_PADDING,\n LOGO_HEIGHT,\n LOGO_ROWS,\n MAX_COLUMN_WIDTH,\n MIN_COLUMN_WIDTH,\n xlsxStyles,\n XlsxStyles\n} from './XlsxStyle';\n\n/**\n * Writes a sheet of the `.xlsx`, from top to bottom: the logo, the title, the generation date, the context info, the\n * table and the footer with the link of the system. Numbers are numeric (not text), with the format of each cell.\n * @author Manoel Campos\n */\nexport class XlsxSheetWriter {\n private readonly worksheet: Worksheet;\n private readonly document: ExportDocument;\n private readonly messages: ExportMessages;\n private readonly styles: XlsxStyles;\n\n /** Next free row of the sheet (starts at 1, as in Excel). */\n private nextRow = 1;\n\n /**\n * @param worksheet sheet to write to\n * @param document exported document, where the title, the context, the texts and the visual identity come from\n * @param styles fonts, fills and borders of the sheet\n */\n constructor(worksheet: Worksheet, document: ExportDocument, styles: XlsxStyles = xlsxStyles()) {\n this.worksheet = worksheet;\n this.document = document;\n this.messages = exportMessages(document);\n this.styles = styles;\n }\n\n /**\n * Writes the whole sheet.\n * @param sheet columns and rows of the table\n * @param logoImageId id of the logo registered in the workbook; absent to show no logo\n */\n write(sheet: ExportSheet, logoImageId?: number): void {\n this.writeHeader(logoImageId);\n const rows = classifyRows(sheet, this.messages.invalidCell);\n const headerRow = this.writeTable(sheet, rows);\n this.writeFooter();\n this.adjustColumnWidths(sheet, rows);\n this.setupPrinting(headerRow);\n }\n\n /**\n * Writes the logo, the title, the generation date and the context info.\n * @param logoImageId id of the logo registered in the workbook\n */\n private writeHeader(logoImageId?: number): void {\n const { logo } = this.document.branding;\n if (logoImageId !== undefined && logo) {\n const width = Math.round((LOGO_HEIGHT * logo.width) / logo.height);\n this.worksheet.addImage(logoImageId, { tl: { col: 0, row: 0 }, ext: { width, height: LOGO_HEIGHT } });\n this.nextRow += LOGO_ROWS;\n }\n\n this.addRow([this.document.title]).getCell(1).font = this.styles.titleFont;\n this.addRow([this.messages.generatedAt(this.document.generatedAt)]).getCell(1).font = this.styles.subtitleFont;\n /* The label and the value stay in a single cell (as rich text, with the label in bold): the text flows to the\n empty cells beside it, instead of being cut by the width of the first column, which fits the table. */\n this.document.info.forEach(info => {\n this.addRow([]).getCell(1).value = {\n richText: [{ font: this.styles.infoLabelFont, text: `${info.label}: ` }, { text: info.value }]\n };\n });\n this.nextRow++;\n }\n\n /**\n * Writes the table: the header and the rows, with borders, zebra stripes and the Excel filter in the header.\n * @param sheet columns of the table\n * @param rows cells of each row, already classified\n * @return the number of the header row\n */\n private writeTable(sheet: ExportSheet, rows: ClassifiedCell[][]): number {\n const headerRow = this.nextRow;\n this.addRow(sheet.columns.map(column => column.header)).eachCell(cell => {\n cell.font = this.styles.headerFont;\n cell.fill = this.styles.headerFill;\n cell.border = this.styles.cellBorder;\n cell.alignment = { vertical: 'middle', wrapText: true };\n });\n\n rows.forEach((row, i) => this.writeTableRow(row, i));\n if (rows.length > 0 && sheet.columns.length > 0) {\n this.worksheet.autoFilter = {\n from: { row: headerRow, column: 1 },\n to: { row: headerRow + rows.length, column: sheet.columns.length }\n };\n }\n\n return headerRow;\n }\n\n /**\n * Writes a row of the table.\n * @param row cells of the row, already classified\n * @param index position of the row in the table (0 for the first one), used in the zebra stripes\n */\n private writeTableRow(row: ClassifiedCell[], index: number): void {\n const excelRow = this.worksheet.getRow(this.nextRow++);\n row.forEach((classified, i) => {\n const cell = excelRow.getCell(i + 1);\n writeCell(cell, classified, this.styles);\n cell.border = this.styles.cellBorder;\n if (index % 2 === 1) cell.fill = this.styles.zebraFill;\n });\n }\n\n /** Writes the footer, with the name of the system and the link to it. */\n private writeFooter(): void {\n const { branding } = this.document;\n this.nextRow++;\n this.addRow([this.messages.footer(branding.systemName)]).getCell(1).font = this.styles.footerFont;\n\n const link = this.addRow([]).getCell(1);\n link.value = { text: branding.siteUrl, hyperlink: branding.siteUrl };\n link.font = this.styles.linkFont;\n }\n\n /**\n * Fits the width of each column to the longest text of the table. The rows outside the table (title, info and\n * footer) do not count, since their text can flow to the empty cells beside them.\n * @param sheet columns of the table\n * @param rows cells of each row, already classified\n */\n private adjustColumnWidths(sheet: ExportSheet, rows: ClassifiedCell[][]): void {\n const locale = exportLocale(this.document);\n sheet.columns.forEach((column, i) => {\n // reduce, not Math.max(...): the spread passes a row per argument and overflows the stack in a big sheet.\n const maxLength = rows.reduce(\n (max, row) => Math.max(max, cellText(row[i], true, locale).length),\n column.header.length\n );\n this.worksheet.getColumn(i + 1).width = Math.min(\n MAX_COLUMN_WIDTH,\n Math.max(MIN_COLUMN_WIDTH, maxLength + COLUMN_PADDING)\n );\n });\n }\n\n /**\n * Sets up printing: landscape, the table fitting the page width, the header repeated on every page and a page\n * footer with the system and the page number.\n * @param headerRow number of the header row\n */\n private setupPrinting(headerRow: number): void {\n this.worksheet.pageSetup = {\n ...this.worksheet.pageSetup,\n orientation: 'landscape',\n fitToPage: true,\n fitToWidth: 1,\n fitToHeight: 0,\n printTitlesRow: `${headerRow}:${headerRow}`\n };\n\n // In the Excel page footer, `&` starts a code (e.g. &P is the page number), so it is escaped.\n const { branding } = this.document;\n const footer = `${this.messages.footer(branding.systemName)} - ${branding.siteUrl}`.replaceAll('&', '&&');\n this.worksheet.headerFooter.oddFooter = `&L${footer}&R${this.messages.excelPageNumber}`;\n this.worksheet.views = [{ showGridLines: false }];\n }\n\n /**\n * Adds a row at the next free position.\n * @param values values of the cells, from the first column on\n * @return the created row\n */\n private addRow(values: string[]): Row {\n const row = this.worksheet.getRow(this.nextRow++);\n values.forEach((value, i) => {\n row.getCell(i + 1).value = value;\n });\n\n return row;\n }\n}\n\n/**\n * Classifies the cells of all rows of the table, completing with empty cells the rows shorter than the number of\n * columns.\n * @param sheet columns and rows of the table\n * @param invalidText text of an infinite number\n * @return a classified cell per column, in each row\n * @throws Error if a row has more cells than columns, since the extra data would be lost without warning\n */\nfunction classifyRows(sheet: ExportSheet, invalidText: string): ClassifiedCell[][] {\n return sheet.rows.map((row, rowIndex) => {\n if (row.length > sheet.columns.length) {\n throw new Error(\n `Row ${rowIndex + 1} of the sheet \"${sheet.name}\" has ${row.length} cells, but the sheet has ` +\n `${sheet.columns.length} columns.`\n );\n }\n\n return sheet.columns.map((column, i) => classifyCell(row[i], column.format, invalidText));\n });\n}\n\n/**\n * Writes the value of a table cell, with the number format and the highlight of the invalid results.\n * @param cell Excel cell\n * @param classified value already classified (see {@link classifyCell})\n * @param styles styles of the sheet, for the highlight of the invalid results\n */\nfunction writeCell(cell: Cell, classified: ClassifiedCell, styles: XlsxStyles): void {\n switch (classified.kind) {\n case 'empty':\n cell.value = null;\n break;\n case 'text':\n cell.value = classified.text;\n break;\n case 'invalid':\n cell.value = classified.text;\n cell.font = styles.invalidFont;\n cell.alignment = { horizontal: 'right' };\n break;\n case 'number':\n cell.value = classified.value;\n cell.numFmt = xlsxNumberFormat(classified.format);\n break;\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { Border, Fill, Font } from 'exceljs';
|
|
2
|
+
/**
|
|
3
|
+
* Styles of the `.xlsx` file, built from a set of colors so that all sheets look the same and an app can use its own
|
|
4
|
+
* brand colors.
|
|
5
|
+
* @author Manoel Campos
|
|
6
|
+
*/
|
|
7
|
+
/** Colors of the `.xlsx` file, in the Excel ARGB format (e.g. `FF055087`). */
|
|
8
|
+
export type XlsxColors = {
|
|
9
|
+
/** Title, table header background and links. */
|
|
10
|
+
primary: string;
|
|
11
|
+
/** Background of the even rows (zebra stripes). */
|
|
12
|
+
primaryLight: string;
|
|
13
|
+
/** Text of the table header. */
|
|
14
|
+
headerText: string;
|
|
15
|
+
/** Table borders. */
|
|
16
|
+
border: string;
|
|
17
|
+
/** Secondary texts: generation date, info labels and footer. */
|
|
18
|
+
secondaryText: string;
|
|
19
|
+
/** Cells with an invalid result. */
|
|
20
|
+
invalid: string;
|
|
21
|
+
};
|
|
22
|
+
/** Default colors: a dark blue primary color with a light blue zebra. */
|
|
23
|
+
export declare const DEFAULT_XLSX_COLORS: XlsxColors;
|
|
24
|
+
/** Fonts, fills and borders of the `.xlsx` file. */
|
|
25
|
+
export type XlsxStyles = {
|
|
26
|
+
titleFont: Partial<Font>;
|
|
27
|
+
subtitleFont: Partial<Font>;
|
|
28
|
+
infoLabelFont: Partial<Font>;
|
|
29
|
+
headerFont: Partial<Font>;
|
|
30
|
+
invalidFont: Partial<Font>;
|
|
31
|
+
footerFont: Partial<Font>;
|
|
32
|
+
linkFont: Partial<Font>;
|
|
33
|
+
headerFill: Fill;
|
|
34
|
+
zebraFill: Fill;
|
|
35
|
+
cellBorder: Partial<Record<'top' | 'left' | 'bottom' | 'right', Partial<Border>>>;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Builds the styles of the `.xlsx` file from a set of colors.
|
|
39
|
+
* @param colors colors of the file; the ones not given use {@link DEFAULT_XLSX_COLORS}
|
|
40
|
+
* @return the fonts, fills and borders of the file
|
|
41
|
+
*/
|
|
42
|
+
export declare function xlsxStyles(colors?: Partial<XlsxColors>): XlsxStyles;
|
|
43
|
+
/** Height of the logo in the header (px). The width follows the aspect ratio of the image. */
|
|
44
|
+
export declare const LOGO_HEIGHT = 48;
|
|
45
|
+
/** Header rows taken by the logo, so the text is not placed under it. */
|
|
46
|
+
export declare const LOGO_ROWS = 3;
|
|
47
|
+
/** Minimum and maximum width of a column, in characters. */
|
|
48
|
+
export declare const MIN_COLUMN_WIDTH = 8;
|
|
49
|
+
export declare const MAX_COLUMN_WIDTH = 60;
|
|
50
|
+
/** Room added to the longest text of the column, in characters, so the text does not touch the border. */
|
|
51
|
+
export declare const COLUMN_PADDING = 2;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
// src/export/xlsx/XlsxStyle.ts
|
|
3
|
+
/** Default colors: a dark blue primary color with a light blue zebra. */
|
|
4
|
+
var DEFAULT_XLSX_COLORS = {
|
|
5
|
+
primary: "FF055087",
|
|
6
|
+
primaryLight: "FFF0F8FF",
|
|
7
|
+
headerText: "FFFFFFFF",
|
|
8
|
+
border: "FFD0D7DE",
|
|
9
|
+
secondaryText: "FF5F6B7A",
|
|
10
|
+
invalid: "FFC92A2A"
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Builds the styles of the `.xlsx` file from a set of colors.
|
|
14
|
+
* @param colors colors of the file; the ones not given use {@link DEFAULT_XLSX_COLORS}
|
|
15
|
+
* @return the fonts, fills and borders of the file
|
|
16
|
+
*/
|
|
17
|
+
function xlsxStyles(colors = {}) {
|
|
18
|
+
const color = {
|
|
19
|
+
...DEFAULT_XLSX_COLORS,
|
|
20
|
+
...colors
|
|
21
|
+
};
|
|
22
|
+
const thinBorder = {
|
|
23
|
+
style: "thin",
|
|
24
|
+
color: { argb: color.border }
|
|
25
|
+
};
|
|
26
|
+
return {
|
|
27
|
+
titleFont: {
|
|
28
|
+
size: 16,
|
|
29
|
+
bold: true,
|
|
30
|
+
color: { argb: color.primary }
|
|
31
|
+
},
|
|
32
|
+
subtitleFont: {
|
|
33
|
+
size: 10,
|
|
34
|
+
italic: true,
|
|
35
|
+
color: { argb: color.secondaryText }
|
|
36
|
+
},
|
|
37
|
+
infoLabelFont: {
|
|
38
|
+
bold: true,
|
|
39
|
+
color: { argb: color.secondaryText }
|
|
40
|
+
},
|
|
41
|
+
headerFont: {
|
|
42
|
+
bold: true,
|
|
43
|
+
color: { argb: color.headerText }
|
|
44
|
+
},
|
|
45
|
+
invalidFont: {
|
|
46
|
+
bold: true,
|
|
47
|
+
color: { argb: color.invalid }
|
|
48
|
+
},
|
|
49
|
+
footerFont: {
|
|
50
|
+
size: 9,
|
|
51
|
+
color: { argb: color.secondaryText }
|
|
52
|
+
},
|
|
53
|
+
linkFont: {
|
|
54
|
+
size: 9,
|
|
55
|
+
underline: true,
|
|
56
|
+
color: { argb: color.primary }
|
|
57
|
+
},
|
|
58
|
+
headerFill: {
|
|
59
|
+
type: "pattern",
|
|
60
|
+
pattern: "solid",
|
|
61
|
+
fgColor: { argb: color.primary }
|
|
62
|
+
},
|
|
63
|
+
zebraFill: {
|
|
64
|
+
type: "pattern",
|
|
65
|
+
pattern: "solid",
|
|
66
|
+
fgColor: { argb: color.primaryLight }
|
|
67
|
+
},
|
|
68
|
+
cellBorder: {
|
|
69
|
+
top: thinBorder,
|
|
70
|
+
left: thinBorder,
|
|
71
|
+
bottom: thinBorder,
|
|
72
|
+
right: thinBorder
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/** Height of the logo in the header (px). The width follows the aspect ratio of the image. */
|
|
77
|
+
var LOGO_HEIGHT = 48;
|
|
78
|
+
/** Header rows taken by the logo, so the text is not placed under it. */
|
|
79
|
+
var LOGO_ROWS = 3;
|
|
80
|
+
/** Minimum and maximum width of a column, in characters. */
|
|
81
|
+
var MIN_COLUMN_WIDTH = 8;
|
|
82
|
+
var MAX_COLUMN_WIDTH = 60;
|
|
83
|
+
/** Room added to the longest text of the column, in characters, so the text does not touch the border. */
|
|
84
|
+
var COLUMN_PADDING = 2;
|
|
85
|
+
export { COLUMN_PADDING, DEFAULT_XLSX_COLORS, LOGO_HEIGHT, LOGO_ROWS, MAX_COLUMN_WIDTH, MIN_COLUMN_WIDTH, xlsxStyles };
|
|
86
|
+
|
|
87
|
+
//# sourceMappingURL=XlsxStyle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"XlsxStyle.js","names":[],"sources":["../../../src/export/xlsx/XlsxStyle.ts"],"sourcesContent":["import type { Border, Fill, Font } from 'exceljs';\n\n/**\n * Styles of the `.xlsx` file, built from a set of colors so that all sheets look the same and an app can use its own\n * brand colors.\n * @author Manoel Campos\n */\n\n/** Colors of the `.xlsx` file, in the Excel ARGB format (e.g. `FF055087`). */\nexport type XlsxColors = {\n /** Title, table header background and links. */\n primary: string;\n\n /** Background of the even rows (zebra stripes). */\n primaryLight: string;\n\n /** Text of the table header. */\n headerText: string;\n\n /** Table borders. */\n border: string;\n\n /** Secondary texts: generation date, info labels and footer. */\n secondaryText: string;\n\n /** Cells with an invalid result. */\n invalid: string;\n};\n\n/** Default colors: a dark blue primary color with a light blue zebra. */\nexport const DEFAULT_XLSX_COLORS: XlsxColors = {\n primary: 'FF055087',\n primaryLight: 'FFF0F8FF',\n headerText: 'FFFFFFFF',\n border: 'FFD0D7DE',\n secondaryText: 'FF5F6B7A',\n invalid: 'FFC92A2A'\n};\n\n/** Fonts, fills and borders of the `.xlsx` file. */\nexport type XlsxStyles = {\n titleFont: Partial<Font>;\n subtitleFont: Partial<Font>;\n infoLabelFont: Partial<Font>;\n headerFont: Partial<Font>;\n invalidFont: Partial<Font>;\n footerFont: Partial<Font>;\n linkFont: Partial<Font>;\n headerFill: Fill;\n zebraFill: Fill;\n cellBorder: Partial<Record<'top' | 'left' | 'bottom' | 'right', Partial<Border>>>;\n};\n\n/**\n * Builds the styles of the `.xlsx` file from a set of colors.\n * @param colors colors of the file; the ones not given use {@link DEFAULT_XLSX_COLORS}\n * @return the fonts, fills and borders of the file\n */\nexport function xlsxStyles(colors: Partial<XlsxColors> = {}): XlsxStyles {\n const color = { ...DEFAULT_XLSX_COLORS, ...colors };\n const thinBorder: Partial<Border> = { style: 'thin', color: { argb: color.border } };\n\n return {\n titleFont: { size: 16, bold: true, color: { argb: color.primary } },\n subtitleFont: { size: 10, italic: true, color: { argb: color.secondaryText } },\n infoLabelFont: { bold: true, color: { argb: color.secondaryText } },\n headerFont: { bold: true, color: { argb: color.headerText } },\n invalidFont: { bold: true, color: { argb: color.invalid } },\n footerFont: { size: 9, color: { argb: color.secondaryText } },\n linkFont: { size: 9, underline: true, color: { argb: color.primary } },\n headerFill: { type: 'pattern', pattern: 'solid', fgColor: { argb: color.primary } },\n zebraFill: { type: 'pattern', pattern: 'solid', fgColor: { argb: color.primaryLight } },\n cellBorder: { top: thinBorder, left: thinBorder, bottom: thinBorder, right: thinBorder }\n };\n}\n\n/** Height of the logo in the header (px). The width follows the aspect ratio of the image. */\nexport const LOGO_HEIGHT = 48;\n\n/** Header rows taken by the logo, so the text is not placed under it. */\nexport const LOGO_ROWS = 3;\n\n/** Minimum and maximum width of a column, in characters. */\nexport const MIN_COLUMN_WIDTH = 8;\nexport const MAX_COLUMN_WIDTH = 60;\n\n/** Room added to the longest text of the column, in characters, so the text does not touch the border. */\nexport const COLUMN_PADDING = 2;\n"],"mappings":";;;AA8BA,IAAa,sBAAkC;CAC3C,SAAS;CACT,cAAc;CACd,YAAY;CACZ,QAAQ;CACR,eAAe;CACf,SAAS;AACb;;;;;;AAqBA,SAAgB,WAAW,SAA8B,CAAC,GAAe;CACrE,MAAM,QAAQ;EAAE,GAAG;EAAqB,GAAG;CAAO;CAClD,MAAM,aAA8B;EAAE,OAAO;EAAQ,OAAO,EAAE,MAAM,MAAM,OAAO;CAAE;CAEnF,OAAO;EACH,WAAW;GAAE,MAAM;GAAI,MAAM;GAAM,OAAO,EAAE,MAAM,MAAM,QAAQ;EAAE;EAClE,cAAc;GAAE,MAAM;GAAI,QAAQ;GAAM,OAAO,EAAE,MAAM,MAAM,cAAc;EAAE;EAC7E,eAAe;GAAE,MAAM;GAAM,OAAO,EAAE,MAAM,MAAM,cAAc;EAAE;EAClE,YAAY;GAAE,MAAM;GAAM,OAAO,EAAE,MAAM,MAAM,WAAW;EAAE;EAC5D,aAAa;GAAE,MAAM;GAAM,OAAO,EAAE,MAAM,MAAM,QAAQ;EAAE;EAC1D,YAAY;GAAE,MAAM;GAAG,OAAO,EAAE,MAAM,MAAM,cAAc;EAAE;EAC5D,UAAU;GAAE,MAAM;GAAG,WAAW;GAAM,OAAO,EAAE,MAAM,MAAM,QAAQ;EAAE;EACrE,YAAY;GAAE,MAAM;GAAW,SAAS;GAAS,SAAS,EAAE,MAAM,MAAM,QAAQ;EAAE;EAClF,WAAW;GAAE,MAAM;GAAW,SAAS;GAAS,SAAS,EAAE,MAAM,MAAM,aAAa;EAAE;EACtF,YAAY;GAAE,KAAK;GAAY,MAAM;GAAY,QAAQ;GAAY,OAAO;EAAW;CAC3F;AACJ;;AAGA,IAAa,cAAc;;AAG3B,IAAa,YAAY;;AAGzB,IAAa,mBAAmB;AAChC,IAAa,mBAAmB;;AAGhC,IAAa,iBAAiB"}
|