@ifto/mantine-kit 0.0.0-stage → 0.1.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 +471 -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 +108 -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 +123 -0
- package/dist/component/organism/ViewTable/ViewTable.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 +12 -0
- package/dist/hook/useService.js +29 -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 +37 -0
- package/dist/util/DateUtil.js +53 -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 +149 -5
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { DEFAULT_MESSAGES } from "../i18n/resolveMessages.js";
|
|
3
|
+
// src/export/ExportDocument.ts
|
|
4
|
+
/** Format of the numbers of a column that defines none. */
|
|
5
|
+
var DEFAULT_NUMBER_FORMAT = { decimals: 2 };
|
|
6
|
+
/**
|
|
7
|
+
* Creates a cell with an invalid result.
|
|
8
|
+
* @param text text shown instead of the value; defaults to the text of the default locale
|
|
9
|
+
* @return the invalid cell
|
|
10
|
+
*/
|
|
11
|
+
function invalidCell(text = DEFAULT_MESSAGES.export.invalidCell) {
|
|
12
|
+
return {
|
|
13
|
+
invalid: true,
|
|
14
|
+
text
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Tells whether the cell is an invalid result.
|
|
19
|
+
* @param cell cell to check
|
|
20
|
+
*/
|
|
21
|
+
function isInvalidCell(cell) {
|
|
22
|
+
return typeof cell === "object" && "invalid" in cell;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Classifies a cell, so that every format handles each type of value the same way. A `NaN` number is treated as
|
|
26
|
+
* absent (empty cell), and `Infinity` as invalid (e.g. a division by zero).
|
|
27
|
+
* @param cell cell to classify
|
|
28
|
+
* @param columnFormat format of the column of the cell, used when the cell is a number without its own format
|
|
29
|
+
* @param invalidText text of an infinite number; defaults to the text of the default locale
|
|
30
|
+
* @return the type and the value of the cell
|
|
31
|
+
*/
|
|
32
|
+
function classifyCell(cell, columnFormat = DEFAULT_NUMBER_FORMAT, invalidText = DEFAULT_MESSAGES.export.invalidCell) {
|
|
33
|
+
if (cell === void 0) return { kind: "empty" };
|
|
34
|
+
if (typeof cell === "string") return {
|
|
35
|
+
kind: "text",
|
|
36
|
+
text: cell
|
|
37
|
+
};
|
|
38
|
+
if (isInvalidCell(cell)) return {
|
|
39
|
+
kind: "invalid",
|
|
40
|
+
text: cell.text
|
|
41
|
+
};
|
|
42
|
+
const { value, format } = typeof cell === "number" ? {
|
|
43
|
+
value: cell,
|
|
44
|
+
format: columnFormat
|
|
45
|
+
} : cell;
|
|
46
|
+
if (Number.isNaN(value)) return { kind: "empty" };
|
|
47
|
+
if (!Number.isFinite(value)) return {
|
|
48
|
+
kind: "invalid",
|
|
49
|
+
text: invalidText
|
|
50
|
+
};
|
|
51
|
+
return {
|
|
52
|
+
kind: "number",
|
|
53
|
+
value,
|
|
54
|
+
format
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
export { DEFAULT_NUMBER_FORMAT, classifyCell, invalidCell, isInvalidCell };
|
|
58
|
+
|
|
59
|
+
//# sourceMappingURL=ExportDocument.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExportDocument.js","names":[],"sources":["../../src/export/ExportDocument.ts"],"sourcesContent":["/**\n * Model of the exported data, independent of the file format (see `ExportFormat`). An export is a document with one\n * or more sheets, and each sheet is a matrix (an array of arrays) of cells, with the title of each column.\n * It depends on no domain: whoever exports converts their data to this model.\n * @author Manoel Campos\n */\n\nimport { KitLocale } from '../i18n/KitLocale';\nimport { ExportMessages } from '../i18n/KitMessages';\nimport { DEFAULT_MESSAGES } from '../i18n/resolveMessages';\n\n/** Format of a numeric value. Percentages are in the 0..1 scale and converted only for display. */\nexport type NumberFormat = {\n /** Decimal places shown. */\n decimals: number;\n\n /** Whether the value is a percentage in the 0..1 scale (e.g. 0.85 is shown as 85%). */\n percent?: boolean;\n};\n\n/** Number with its own format, for when the format changes from one row to another (e.g. the unit of each row). */\nexport type NumberCell = {\n value: number;\n format: NumberFormat;\n};\n\n/** Cell whose value could not be computed (e.g. a calculation error), unlike an empty (absent) cell. */\nexport type InvalidCell = {\n invalid: true;\n\n /** Text shown instead of the value. */\n text: string;\n};\n\n/**\n * Value of a cell:\n * - `string`: text;\n * - `number`: number, in the format of the column (`NaN` is treated as an absent value);\n * - {@link NumberCell}: number with its own format;\n * - {@link InvalidCell}: invalid result;\n * - `undefined`: absent value (empty cell), which is different from zero.\n */\nexport type ExportCell = string | number | NumberCell | InvalidCell | undefined;\n\n/** Column of a sheet. */\nexport type ExportColumn = {\n /** Title (header) of the column. */\n header: string;\n\n /** Format of the numbers of the column, used when the cell has none; absent for {@link DEFAULT_NUMBER_FORMAT}. */\n format?: NumberFormat;\n};\n\n/** Sheet of the file: a table with the columns and the rows. */\nexport type ExportSheet = {\n /** Name of the sheet. Each format adapts it to its rules (e.g. the maximum length in Excel). */\n name: string;\n columns: ExportColumn[];\n\n /**\n * One array per row, with one cell per column, in the order of {@link columns}. A shorter row is completed with\n * empty cells; a row with more cells than columns is an error, since the extra data would be lost.\n */\n rows: ExportCell[][];\n};\n\n/** Information about the context of the data, shown at the beginning of the file (e.g. the period and the filters). */\nexport type ExportInfo = {\n label: string;\n value: string;\n};\n\n/** Visual identity of the system that generated the file, shown in the header and in the footer. */\nexport type ExportBranding = {\n /** Name of the system, shown in the footer (e.g. \"Data generated by My System\"). */\n systemName: string;\n\n /** Address of the system, shown as a link in the footer. */\n siteUrl: string;\n\n /** Logo shown in the header; absent to show no logo (e.g. if it could not be loaded). */\n logo?: ExportImage;\n};\n\n/** PNG image embedded in the file. */\nexport type ExportImage = {\n /** Content of the image, as a base64 data URL (`data:image/png;base64,...`). */\n pngDataUrl: string;\n\n /** Original width and height (px), to keep the aspect ratio when resizing. */\n width: number;\n height: number;\n};\n\n/** Document to export: the data and its context. */\nexport type ExportDocument = {\n /** Title shown at the top of the file. */\n title: string;\n\n /** Name of the file, without the date and the extension, which are added on export. */\n fileName: string;\n info: ExportInfo[];\n\n /** Date and time the data was generated. */\n generatedAt: Date;\n branding: ExportBranding;\n sheets: ExportSheet[];\n\n /** Locale of the texts and of the number format of the file. Default: `en-US`. */\n locale?: KitLocale;\n\n /** Texts that replace the ones of the locale (e.g. the ones the app overrides in the `KitProvider`). */\n messages?: Partial<ExportMessages>;\n};\n\n/** Format of the numbers of a column that defines none. */\nexport const DEFAULT_NUMBER_FORMAT: NumberFormat = { decimals: 2 };\n\n/** Types of cell, after being normalized by {@link classifyCell}. */\nexport type ClassifiedCell =\n | { kind: 'empty' }\n | { kind: 'text'; text: string }\n | { kind: 'number'; value: number; format: NumberFormat }\n | { kind: 'invalid'; text: string };\n\n/**\n * Creates a cell with an invalid result.\n * @param text text shown instead of the value; defaults to the text of the default locale\n * @return the invalid cell\n */\nexport function invalidCell(text: string = DEFAULT_MESSAGES.export.invalidCell): InvalidCell {\n return { invalid: true, text };\n}\n\n/**\n * Tells whether the cell is an invalid result.\n * @param cell cell to check\n */\nexport function isInvalidCell(cell: ExportCell): cell is InvalidCell {\n return typeof cell === 'object' && 'invalid' in cell;\n}\n\n/**\n * Classifies a cell, so that every format handles each type of value the same way. A `NaN` number is treated as\n * absent (empty cell), and `Infinity` as invalid (e.g. a division by zero).\n * @param cell cell to classify\n * @param columnFormat format of the column of the cell, used when the cell is a number without its own format\n * @param invalidText text of an infinite number; defaults to the text of the default locale\n * @return the type and the value of the cell\n */\nexport function classifyCell(\n cell: ExportCell,\n columnFormat: NumberFormat = DEFAULT_NUMBER_FORMAT,\n invalidText: string = DEFAULT_MESSAGES.export.invalidCell\n): ClassifiedCell {\n if (cell === undefined) return { kind: 'empty' };\n if (typeof cell === 'string') return { kind: 'text', text: cell };\n if (isInvalidCell(cell)) return { kind: 'invalid', text: cell.text };\n\n const { value, format } = typeof cell === 'number' ? { value: cell, format: columnFormat } : cell;\n if (Number.isNaN(value)) return { kind: 'empty' };\n if (!Number.isFinite(value)) return { kind: 'invalid', text: invalidText };\n\n return { kind: 'number', value, format };\n}\n"],"mappings":";;;;AAoHA,IAAa,wBAAsC,EAAE,UAAU,EAAE;;;;;;AAcjE,SAAgB,YAAY,OAAe,iBAAiB,OAAO,aAA0B;CACzF,OAAO;EAAE,SAAS;EAAM;CAAK;AACjC;;;;;AAMA,SAAgB,cAAc,MAAuC;CACjE,OAAO,OAAO,SAAS,YAAY,aAAa;AACpD;;;;;;;;;AAUA,SAAgB,aACZ,MACA,eAA6B,uBAC7B,cAAsB,iBAAiB,OAAO,aAChC;CACd,IAAI,SAAS,KAAA,GAAW,OAAO,EAAE,MAAM,QAAQ;CAC/C,IAAI,OAAO,SAAS,UAAU,OAAO;EAAE,MAAM;EAAQ,MAAM;CAAK;CAChE,IAAI,cAAc,IAAI,GAAG,OAAO;EAAE,MAAM;EAAW,MAAM,KAAK;CAAK;CAEnE,MAAM,EAAE,OAAO,WAAW,OAAO,SAAS,WAAW;EAAE,OAAO;EAAM,QAAQ;CAAa,IAAI;CAC7F,IAAI,OAAO,MAAM,KAAK,GAAG,OAAO,EAAE,MAAM,QAAQ;CAChD,IAAI,CAAC,OAAO,SAAS,KAAK,GAAG,OAAO;EAAE,MAAM;EAAW,MAAM;CAAY;CAEzE,OAAO;EAAE,MAAM;EAAU;EAAO;CAAO;AAC3C"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ExportDocument } from './ExportDocument';
|
|
2
|
+
import { ExportFormat } from './ExportFormat';
|
|
3
|
+
/**
|
|
4
|
+
* Generates the file of a document in the chosen format and makes the browser download it, named after the document,
|
|
5
|
+
* with the generation date and the extension of the format.
|
|
6
|
+
* @param document data to export
|
|
7
|
+
* @param format format of the file
|
|
8
|
+
*/
|
|
9
|
+
export declare function downloadExport(document: ExportDocument, format: ExportFormat): Promise<void>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { exportFileName } from "./ExportFileName.js";
|
|
3
|
+
import { exportMessages } from "./ExportTexts.js";
|
|
4
|
+
import { downloadBlob } from "../util/DownloadUtil.js";
|
|
5
|
+
// src/export/ExportDownload.ts
|
|
6
|
+
/**
|
|
7
|
+
* Generates the file of a document in the chosen format and makes the browser download it, named after the document,
|
|
8
|
+
* with the generation date and the extension of the format.
|
|
9
|
+
* @param document data to export
|
|
10
|
+
* @param format format of the file
|
|
11
|
+
*/
|
|
12
|
+
async function downloadExport(document, format) {
|
|
13
|
+
const blob = await format.generate(document);
|
|
14
|
+
const defaultName = exportMessages(document).defaultFileName;
|
|
15
|
+
downloadBlob(blob, exportFileName(document.fileName, document.generatedAt, format.extension, defaultName));
|
|
16
|
+
}
|
|
17
|
+
export { downloadExport };
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=ExportDownload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExportDownload.js","names":[],"sources":["../../src/export/ExportDownload.ts"],"sourcesContent":["import { ExportDocument } from './ExportDocument';\nimport { exportFileName } from './ExportFileName';\nimport { ExportFormat } from './ExportFormat';\nimport { exportMessages } from './ExportTexts';\nimport { downloadBlob } from '../util/DownloadUtil';\n\n/**\n * Generates the file of a document in the chosen format and makes the browser download it, named after the document,\n * with the generation date and the extension of the format.\n * @param document data to export\n * @param format format of the file\n */\nexport async function downloadExport(document: ExportDocument, format: ExportFormat): Promise<void> {\n const blob = await format.generate(document);\n const defaultName = exportMessages(document).defaultFileName;\n downloadBlob(blob, exportFileName(document.fileName, document.generatedAt, format.extension, defaultName));\n}\n"],"mappings":";;;;;;;;;;;AAYA,eAAsB,eAAe,UAA0B,QAAqC;CAChG,MAAM,OAAO,MAAM,OAAO,SAAS,QAAQ;CAC3C,MAAM,cAAc,eAAe,QAAQ,CAAC,CAAC;CAC7C,aAAa,MAAM,eAAe,SAAS,UAAU,SAAS,aAAa,OAAO,WAAW,WAAW,CAAC;AAC7G"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds the name of the exported file: the base name without accents or invalid characters, the generation date and
|
|
3
|
+
* the extension (e.g. "sales-north-2026-10-20.xlsx"). Without accents, the name works in any system and e-mail
|
|
4
|
+
* attachment.
|
|
5
|
+
* @param baseName desired name, without date or extension
|
|
6
|
+
* @param generatedAt date the data was generated
|
|
7
|
+
* @param extension extension of the format, without the dot
|
|
8
|
+
* @param defaultName name used when the base name has no valid character; defaults to the one of the default locale
|
|
9
|
+
* @return the name of the file
|
|
10
|
+
*/
|
|
11
|
+
export declare function exportFileName(baseName: string, generatedAt: Date, extension: string, defaultName?: string): string;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { DEFAULT_MESSAGES } from "../i18n/resolveMessages.js";
|
|
3
|
+
import { formatDateToISO } from "../util/DateUtil.js";
|
|
4
|
+
// src/export/ExportFileName.ts
|
|
5
|
+
/** Characters not accepted in file names by some operating system, plus the spaces. */
|
|
6
|
+
var INVALID_FILE_NAME_CHARS = /[\s/\\:*?"<>|]+/g;
|
|
7
|
+
/** Accent marks, separated from the letters by the NFD normalization. */
|
|
8
|
+
var DIACRITICS = /\p{Diacritic}/gu;
|
|
9
|
+
/**
|
|
10
|
+
* Builds the name of the exported file: the base name without accents or invalid characters, the generation date and
|
|
11
|
+
* the extension (e.g. "sales-north-2026-10-20.xlsx"). Without accents, the name works in any system and e-mail
|
|
12
|
+
* attachment.
|
|
13
|
+
* @param baseName desired name, without date or extension
|
|
14
|
+
* @param generatedAt date the data was generated
|
|
15
|
+
* @param extension extension of the format, without the dot
|
|
16
|
+
* @param defaultName name used when the base name has no valid character; defaults to the one of the default locale
|
|
17
|
+
* @return the name of the file
|
|
18
|
+
*/
|
|
19
|
+
function exportFileName(baseName, generatedAt, extension, defaultName = DEFAULT_MESSAGES.export.defaultFileName) {
|
|
20
|
+
return `${baseName.normalize("NFD").replace(DIACRITICS, "").replace(INVALID_FILE_NAME_CHARS, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").toLowerCase() || defaultName}-${formatDateToISO(generatedAt)}.${extension}`;
|
|
21
|
+
}
|
|
22
|
+
export { exportFileName };
|
|
23
|
+
|
|
24
|
+
//# sourceMappingURL=ExportFileName.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExportFileName.js","names":[],"sources":["../../src/export/ExportFileName.ts"],"sourcesContent":["import { DEFAULT_MESSAGES } from '../i18n/resolveMessages';\nimport { formatDateToISO } from '../util/DateUtil';\n\n/** Characters not accepted in file names by some operating system, plus the spaces. */\nconst INVALID_FILE_NAME_CHARS = /[\\s/\\\\:*?\"<>|]+/g;\n\n/** Accent marks, separated from the letters by the NFD normalization. */\nconst DIACRITICS = /\\p{Diacritic}/gu;\n\n/**\n * Builds the name of the exported file: the base name without accents or invalid characters, the generation date and\n * the extension (e.g. \"sales-north-2026-10-20.xlsx\"). Without accents, the name works in any system and e-mail\n * attachment.\n * @param baseName desired name, without date or extension\n * @param generatedAt date the data was generated\n * @param extension extension of the format, without the dot\n * @param defaultName name used when the base name has no valid character; defaults to the one of the default locale\n * @return the name of the file\n */\nexport function exportFileName(\n baseName: string,\n generatedAt: Date,\n extension: string,\n defaultName: string = DEFAULT_MESSAGES.export.defaultFileName\n): string {\n const name = baseName\n .normalize('NFD')\n .replace(DIACRITICS, '')\n .replace(INVALID_FILE_NAME_CHARS, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '')\n .toLowerCase();\n\n return `${name || defaultName}-${formatDateToISO(generatedAt)}.${extension}`;\n}\n"],"mappings":";;;;;AAIA,IAAM,0BAA0B;;AAGhC,IAAM,aAAa;;;;;;;;;;;AAYnB,SAAgB,eACZ,UACA,aACA,WACA,cAAsB,iBAAiB,OAAO,iBACxC;CASN,OAAO,GARM,SACR,UAAU,KAAK,CAAC,CAChB,QAAQ,YAAY,EAAE,CAAC,CACvB,QAAQ,yBAAyB,GAAG,CAAC,CACrC,QAAQ,OAAO,GAAG,CAAC,CACnB,QAAQ,UAAU,EAAE,CAAC,CACrB,YAEK,KAAQ,YAAY,GAAG,gBAAgB,WAAW,EAAE,GAAG;AACrE"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { ExportDocument } from './ExportDocument';
|
|
2
|
+
/**
|
|
3
|
+
* Contract every export format must follow (Strategy pattern). Each format generates the file from the same
|
|
4
|
+
* {@link ExportDocument}, so whoever exports chooses the format without knowing the details of each one. To add a
|
|
5
|
+
* format, create the implementation and register it in `ExportFormats.ts`.
|
|
6
|
+
* @author Manoel Campos
|
|
7
|
+
*/
|
|
8
|
+
export interface ExportFormat {
|
|
9
|
+
/** Unique id of the format (e.g. `xlsx`), used as the key of the format in menus. */
|
|
10
|
+
readonly id: string;
|
|
11
|
+
/** Name of the format shown to the user (e.g. "Excel (.xlsx)"), the same in every language. */
|
|
12
|
+
readonly label: string;
|
|
13
|
+
/** Extension of the file, without the dot. */
|
|
14
|
+
readonly extension: string;
|
|
15
|
+
/** MIME type of the file. */
|
|
16
|
+
readonly mimeType: string;
|
|
17
|
+
/**
|
|
18
|
+
* Whether the format stores many sheets in a single file. A format without sheets (e.g. CSV) accepts only
|
|
19
|
+
* documents with one sheet, so whoever exports must build the document according to this value.
|
|
20
|
+
*/
|
|
21
|
+
readonly multipleSheets: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Generates the file.
|
|
24
|
+
* @param document data to export
|
|
25
|
+
* @return the content of the file
|
|
26
|
+
* @throws Error if the document cannot be exported in the format: without any sheet, with many sheets in a
|
|
27
|
+
* format without sheets, or with a row with more cells than columns
|
|
28
|
+
*/
|
|
29
|
+
generate(document: ExportDocument): Promise<Blob>;
|
|
30
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { CsvFormat } from './csv/CsvFormat';
|
|
2
|
+
import { ExportFormat } from './ExportFormat';
|
|
3
|
+
import { XlsxFormat } from './xlsx/XlsxFormat';
|
|
4
|
+
/**
|
|
5
|
+
* Single instances of the export formats. The formats have no state, so they can be shared by all screens.
|
|
6
|
+
* @author Manoel Campos
|
|
7
|
+
*/
|
|
8
|
+
/** Excel format (`.xlsx`), with a sheet in the file for each sheet of the document. */
|
|
9
|
+
export declare const XLSX_FORMAT: XlsxFormat;
|
|
10
|
+
export declare const CSV_FORMAT: CsvFormat;
|
|
11
|
+
/** All built-in export formats, in the order they appear in an export menu. */
|
|
12
|
+
export declare const EXPORT_FORMATS: readonly ExportFormat[];
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { CsvFormat } from "./csv/CsvFormat.js";
|
|
3
|
+
import { XlsxFormat } from "./xlsx/XlsxFormat.js";
|
|
4
|
+
// src/export/ExportFormats.ts
|
|
5
|
+
/**
|
|
6
|
+
* Single instances of the export formats. The formats have no state, so they can be shared by all screens.
|
|
7
|
+
* @author Manoel Campos
|
|
8
|
+
*/
|
|
9
|
+
/** Excel format (`.xlsx`), with a sheet in the file for each sheet of the document. */
|
|
10
|
+
var XLSX_FORMAT = new XlsxFormat();
|
|
11
|
+
var CSV_FORMAT = new CsvFormat();
|
|
12
|
+
/** All built-in export formats, in the order they appear in an export menu. */
|
|
13
|
+
var EXPORT_FORMATS = [XLSX_FORMAT, CSV_FORMAT];
|
|
14
|
+
export { CSV_FORMAT, EXPORT_FORMATS, XLSX_FORMAT };
|
|
15
|
+
|
|
16
|
+
//# sourceMappingURL=ExportFormats.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExportFormats.js","names":[],"sources":["../../src/export/ExportFormats.ts"],"sourcesContent":["import { CsvFormat } from './csv/CsvFormat';\nimport { ExportFormat } from './ExportFormat';\nimport { XlsxFormat } from './xlsx/XlsxFormat';\n\n/**\n * Single instances of the export formats. The formats have no state, so they can be shared by all screens.\n * @author Manoel Campos\n */\n\n/** Excel format (`.xlsx`), with a sheet in the file for each sheet of the document. */\nexport const XLSX_FORMAT = new XlsxFormat();\nexport const CSV_FORMAT = new CsvFormat();\n\n/** All built-in export formats, in the order they appear in an export menu. */\nexport const EXPORT_FORMATS: readonly ExportFormat[] = [XLSX_FORMAT, CSV_FORMAT];\n"],"mappings":";;;;;;;;;AAUA,IAAa,cAAc,IAAI,WAAW;AAC1C,IAAa,aAAa,IAAI,UAAU;;AAGxC,IAAa,iBAA0C,CAAC,aAAa,UAAU"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ExportMessages } from '../i18n/KitMessages';
|
|
2
|
+
import { ExportDocument } from './ExportDocument';
|
|
3
|
+
/**
|
|
4
|
+
* Returns the texts of an exported document: the ones of its locale, with the ones the document overrides.
|
|
5
|
+
* @param document exported document
|
|
6
|
+
* @return the texts shown in the file
|
|
7
|
+
*/
|
|
8
|
+
export declare function exportMessages(document: Pick<ExportDocument, 'locale' | 'messages'>): ExportMessages;
|
|
9
|
+
/**
|
|
10
|
+
* Returns the locale of an exported document.
|
|
11
|
+
* @param document exported document
|
|
12
|
+
* @return the locale of the document, or the default one
|
|
13
|
+
*/
|
|
14
|
+
export declare function exportLocale(document: Pick<ExportDocument, 'locale'>): string;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import "../i18n/KitLocale.js";
|
|
3
|
+
import { resolveMessages } from "../i18n/resolveMessages.js";
|
|
4
|
+
// src/export/ExportTexts.ts
|
|
5
|
+
/**
|
|
6
|
+
* Returns the texts of an exported document: the ones of its locale, with the ones the document overrides.
|
|
7
|
+
* @param document exported document
|
|
8
|
+
* @return the texts shown in the file
|
|
9
|
+
*/
|
|
10
|
+
function exportMessages(document) {
|
|
11
|
+
return resolveMessages(document.locale, { export: document.messages }).export;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Returns the locale of an exported document.
|
|
15
|
+
* @param document exported document
|
|
16
|
+
* @return the locale of the document, or the default one
|
|
17
|
+
*/
|
|
18
|
+
function exportLocale(document) {
|
|
19
|
+
return document.locale ?? "en-US";
|
|
20
|
+
}
|
|
21
|
+
export { exportLocale, exportMessages };
|
|
22
|
+
|
|
23
|
+
//# sourceMappingURL=ExportTexts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExportTexts.js","names":[],"sources":["../../src/export/ExportTexts.ts"],"sourcesContent":["import { DEFAULT_LOCALE } from '../i18n/KitLocale';\nimport { ExportMessages } from '../i18n/KitMessages';\nimport { resolveMessages } from '../i18n/resolveMessages';\nimport { ExportDocument } from './ExportDocument';\n\n/**\n * Returns the texts of an exported document: the ones of its locale, with the ones the document overrides.\n * @param document exported document\n * @return the texts shown in the file\n */\nexport function exportMessages(document: Pick<ExportDocument, 'locale' | 'messages'>): ExportMessages {\n return resolveMessages(document.locale, { export: document.messages }).export;\n}\n\n/**\n * Returns the locale of an exported document.\n * @param document exported document\n * @return the locale of the document, or the default one\n */\nexport function exportLocale(document: Pick<ExportDocument, 'locale'>): string {\n return document.locale ?? DEFAULT_LOCALE;\n}\n"],"mappings":";;;;;;;;;AAUA,SAAgB,eAAe,UAAuE;CAClG,OAAO,gBAAgB,SAAS,QAAQ,EAAE,QAAQ,SAAS,SAAS,CAAC,CAAC,CAAC;AAC3E;;;;;;AAOA,SAAgB,aAAa,UAAkD;CAC3E,OAAO,SAAS,UAAA;AACpB"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { ExportDocument, ExportSheet } from '../ExportDocument';
|
|
2
|
+
import { ExportFormat } from '../ExportFormat';
|
|
3
|
+
/**
|
|
4
|
+
* Column separator used when the decimal separator of the locale is the comma (e.g. `pt-BR`), which is what Excel
|
|
5
|
+
* expects in these languages.
|
|
6
|
+
*/
|
|
7
|
+
export declare const CSV_SEPARATOR = ";";
|
|
8
|
+
/** Column separator used when the decimal separator of the locale is not the comma (e.g. `en-US`). */
|
|
9
|
+
export declare const CSV_COMMA_SEPARATOR = ",";
|
|
10
|
+
/**
|
|
11
|
+
* Returns the column separator of the CSV for a locale: `;` when the decimal separator is the comma, so numbers do not
|
|
12
|
+
* clash with the separator, or `,` otherwise.
|
|
13
|
+
* @param locale locale of the number format
|
|
14
|
+
*/
|
|
15
|
+
export declare function csvSeparator(locale: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* Exports to CSV, as Excel in the language of the locale expects: the decimal separator of the locale, a column
|
|
18
|
+
* separator that does not clash with it (see {@link csvSeparator}), no thousands separator and UTF-8 with BOM. The CSV
|
|
19
|
+
* has only the table (header and rows), without the title or the context, so other programs can also read the
|
|
20
|
+
* columns. Having no sheets, it accepts only documents with one sheet.
|
|
21
|
+
*
|
|
22
|
+
* The CSV is text, so each number has the decimal places of its format (the same as on the screen), rounded. The
|
|
23
|
+
* `.xlsx` stores the full value and just shows it with these places.
|
|
24
|
+
* @author Manoel Campos
|
|
25
|
+
*/
|
|
26
|
+
export declare class CsvFormat implements ExportFormat {
|
|
27
|
+
readonly id = "csv";
|
|
28
|
+
readonly label = "CSV";
|
|
29
|
+
readonly extension = "csv";
|
|
30
|
+
readonly mimeType = "text/csv;charset=utf-8";
|
|
31
|
+
readonly multipleSheets = false;
|
|
32
|
+
generate(document: ExportDocument): Promise<Blob>;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Builds the CSV text of a sheet.
|
|
36
|
+
* @param sheet columns and rows of the table
|
|
37
|
+
* @param locale locale of the number format, which also defines the column separator; defaults to `en-US`
|
|
38
|
+
* @param invalidText text of an infinite number
|
|
39
|
+
* @return the header and the rows, each one ended by a line break
|
|
40
|
+
*/
|
|
41
|
+
export declare function csvText(sheet: ExportSheet, locale?: string, invalidText?: string): string;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cellText } from "../ExportCellText.js";
|
|
3
|
+
import { classifyCell } from "../ExportDocument.js";
|
|
4
|
+
import { DEFAULT_LOCALE } from "../../i18n/KitLocale.js";
|
|
5
|
+
import { exportLocale, exportMessages } from "../ExportTexts.js";
|
|
6
|
+
// src/export/csv/CsvFormat.ts
|
|
7
|
+
/**
|
|
8
|
+
* Column separator used when the decimal separator of the locale is the comma (e.g. `pt-BR`), which is what Excel
|
|
9
|
+
* expects in these languages.
|
|
10
|
+
*/
|
|
11
|
+
var CSV_SEPARATOR = ";";
|
|
12
|
+
/** Column separator used when the decimal separator of the locale is not the comma (e.g. `en-US`). */
|
|
13
|
+
var CSV_COMMA_SEPARATOR = ",";
|
|
14
|
+
/** Line break of the CSV ({@link https://www.rfc-editor.org/rfc/rfc4180 RFC 4180}). */
|
|
15
|
+
var LINE_BREAK = "\r\n";
|
|
16
|
+
/** UTF-8 byte order mark (BOM): without it, Excel opens the file with garbled accents. */
|
|
17
|
+
var UTF8_BOM = "";
|
|
18
|
+
/**
|
|
19
|
+
* Start of a text that Excel would read as a formula (`=`, `+`, `-`, `@`, tab or CR). A name typed by a user as
|
|
20
|
+
* `=HYPERLINK(...)` would become a formula when the file is opened (CSV injection), so the text gets a leading
|
|
21
|
+
* apostrophe.
|
|
22
|
+
*/
|
|
23
|
+
var FORMULA_START = /^[=+\-@\t\r]/;
|
|
24
|
+
/**
|
|
25
|
+
* Returns the column separator of the CSV for a locale: `;` when the decimal separator is the comma, so numbers do not
|
|
26
|
+
* clash with the separator, or `,` otherwise.
|
|
27
|
+
* @param locale locale of the number format
|
|
28
|
+
*/
|
|
29
|
+
function csvSeparator(locale) {
|
|
30
|
+
return new Intl.NumberFormat(locale).formatToParts(1.1).find((part) => part.type === "decimal")?.value === "," ? ";" : ",";
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Exports to CSV, as Excel in the language of the locale expects: the decimal separator of the locale, a column
|
|
34
|
+
* separator that does not clash with it (see {@link csvSeparator}), no thousands separator and UTF-8 with BOM. The CSV
|
|
35
|
+
* has only the table (header and rows), without the title or the context, so other programs can also read the
|
|
36
|
+
* columns. Having no sheets, it accepts only documents with one sheet.
|
|
37
|
+
*
|
|
38
|
+
* The CSV is text, so each number has the decimal places of its format (the same as on the screen), rounded. The
|
|
39
|
+
* `.xlsx` stores the full value and just shows it with these places.
|
|
40
|
+
* @author Manoel Campos
|
|
41
|
+
*/
|
|
42
|
+
var CsvFormat = class {
|
|
43
|
+
id = "csv";
|
|
44
|
+
label = "CSV";
|
|
45
|
+
extension = "csv";
|
|
46
|
+
mimeType = "text/csv;charset=utf-8";
|
|
47
|
+
multipleSheets = false;
|
|
48
|
+
async generate(document) {
|
|
49
|
+
if (document.sheets.length !== 1) throw new Error(`A CSV file has a single sheet, but the document has ${document.sheets.length}.`);
|
|
50
|
+
const text = csvText(document.sheets[0], exportLocale(document), exportMessages(document).invalidCell);
|
|
51
|
+
return new Blob([UTF8_BOM + text], { type: this.mimeType });
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Builds the CSV text of a sheet.
|
|
56
|
+
* @param sheet columns and rows of the table
|
|
57
|
+
* @param locale locale of the number format, which also defines the column separator; defaults to `en-US`
|
|
58
|
+
* @param invalidText text of an infinite number
|
|
59
|
+
* @return the header and the rows, each one ended by a line break
|
|
60
|
+
*/
|
|
61
|
+
function csvText(sheet, locale = DEFAULT_LOCALE, invalidText) {
|
|
62
|
+
const separator = csvSeparator(locale);
|
|
63
|
+
const field = (text) => csvField(text, separator);
|
|
64
|
+
return [sheet.columns.map((column) => field(column.header)), ...sheet.rows.map((row) => sheet.columns.map((column, i) => csvCell(classifyCell(row[i], column.format, invalidText), locale, field)))].map((fields) => fields.join(separator) + LINE_BREAK).join("");
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Converts a cell to the CSV field. Numbers have the decimal separator of the locale and no thousands separator, which
|
|
68
|
+
* Excel in that language reads as a number (and a percentage, such as "85,5%", as 0.855). Texts, including the one of
|
|
69
|
+
* an invalid cell, go through the text field function.
|
|
70
|
+
* @param cell cell already classified
|
|
71
|
+
* @param locale locale of the number format
|
|
72
|
+
* @param field function that prepares a text field
|
|
73
|
+
* @return the CSV field
|
|
74
|
+
*/
|
|
75
|
+
function csvCell(cell, locale, field) {
|
|
76
|
+
const text = cellText(cell, false, locale);
|
|
77
|
+
return cell.kind === "number" ? text : field(text);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Prepares a text for the CSV: prevents it from becoming a formula and quotes it if needed.
|
|
81
|
+
* @param text text of the field
|
|
82
|
+
* @param separator column separator, which requires quotes when present in the text
|
|
83
|
+
* @return the CSV field
|
|
84
|
+
*/
|
|
85
|
+
function csvField(text, separator) {
|
|
86
|
+
const safeText = FORMULA_START.test(text) ? `'${text}` : text;
|
|
87
|
+
return safeText.includes(separator) || /["\r\n]/.test(safeText) ? `"${safeText.replaceAll("\"", "\"\"")}"` : safeText;
|
|
88
|
+
}
|
|
89
|
+
export { CSV_COMMA_SEPARATOR, CSV_SEPARATOR, CsvFormat, csvSeparator, csvText };
|
|
90
|
+
|
|
91
|
+
//# sourceMappingURL=CsvFormat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CsvFormat.js","names":[],"sources":["../../../src/export/csv/CsvFormat.ts"],"sourcesContent":["import { cellText } from '../ExportCellText';\nimport { ClassifiedCell, classifyCell, ExportDocument, ExportSheet } from '../ExportDocument';\nimport { ExportFormat } from '../ExportFormat';\nimport { DEFAULT_LOCALE } from '../../i18n/KitLocale';\nimport { exportLocale, exportMessages } from '../ExportTexts';\n\n/**\n * Column separator used when the decimal separator of the locale is the comma (e.g. `pt-BR`), which is what Excel\n * expects in these languages.\n */\nexport const CSV_SEPARATOR = ';';\n\n/** Column separator used when the decimal separator of the locale is not the comma (e.g. `en-US`). */\nexport const CSV_COMMA_SEPARATOR = ',';\n\n/** Line break of the CSV ({@link https://www.rfc-editor.org/rfc/rfc4180 RFC 4180}). */\nconst LINE_BREAK = '\\r\\n';\n\n/** UTF-8 byte order mark (BOM): without it, Excel opens the file with garbled accents. */\nconst UTF8_BOM = '';\n\n/**\n * Start of a text that Excel would read as a formula (`=`, `+`, `-`, `@`, tab or CR). A name typed by a user as\n * `=HYPERLINK(...)` would become a formula when the file is opened (CSV injection), so the text gets a leading\n * apostrophe.\n */\nconst FORMULA_START = /^[=+\\-@\\t\\r]/;\n\n/**\n * Returns the column separator of the CSV for a locale: `;` when the decimal separator is the comma, so numbers do not\n * clash with the separator, or `,` otherwise.\n * @param locale locale of the number format\n */\nexport function csvSeparator(locale: string): string {\n const decimal = new Intl.NumberFormat(locale).formatToParts(1.1).find(part => part.type === 'decimal')?.value;\n\n return decimal === ',' ? CSV_SEPARATOR : CSV_COMMA_SEPARATOR;\n}\n\n/**\n * Exports to CSV, as Excel in the language of the locale expects: the decimal separator of the locale, a column\n * separator that does not clash with it (see {@link csvSeparator}), no thousands separator and UTF-8 with BOM. The CSV\n * has only the table (header and rows), without the title or the context, so other programs can also read the\n * columns. Having no sheets, it accepts only documents with one sheet.\n *\n * The CSV is text, so each number has the decimal places of its format (the same as on the screen), rounded. The\n * `.xlsx` stores the full value and just shows it with these places.\n * @author Manoel Campos\n */\nexport class CsvFormat implements ExportFormat {\n readonly id = 'csv';\n readonly label = 'CSV';\n readonly extension = 'csv';\n readonly mimeType = 'text/csv;charset=utf-8';\n readonly multipleSheets = false;\n\n async generate(document: ExportDocument): Promise<Blob> {\n if (document.sheets.length !== 1) {\n throw new Error(`A CSV file has a single sheet, but the document has ${document.sheets.length}.`);\n }\n\n const text = csvText(document.sheets[0], exportLocale(document), exportMessages(document).invalidCell);\n return new Blob([UTF8_BOM + text], { type: this.mimeType });\n }\n}\n\n/**\n * Builds the CSV text of a sheet.\n * @param sheet columns and rows of the table\n * @param locale locale of the number format, which also defines the column separator; defaults to `en-US`\n * @param invalidText text of an infinite number\n * @return the header and the rows, each one ended by a line break\n */\nexport function csvText(sheet: ExportSheet, locale: string = DEFAULT_LOCALE, invalidText?: string): string {\n const separator = csvSeparator(locale);\n const field = (text: string) => csvField(text, separator);\n const header = sheet.columns.map(column => field(column.header));\n const rows = sheet.rows.map(row =>\n sheet.columns.map((column, i) => csvCell(classifyCell(row[i], column.format, invalidText), locale, field))\n );\n\n return [header, ...rows].map(fields => fields.join(separator) + LINE_BREAK).join('');\n}\n\n/**\n * Converts a cell to the CSV field. Numbers have the decimal separator of the locale and no thousands separator, which\n * Excel in that language reads as a number (and a percentage, such as \"85,5%\", as 0.855). Texts, including the one of\n * an invalid cell, go through the text field function.\n * @param cell cell already classified\n * @param locale locale of the number format\n * @param field function that prepares a text field\n * @return the CSV field\n */\nfunction csvCell(cell: ClassifiedCell, locale: string, field: (text: string) => string): string {\n const text = cellText(cell, false, locale);\n\n return cell.kind === 'number' ? text : field(text);\n}\n\n/**\n * Prepares a text for the CSV: prevents it from becoming a formula and quotes it if needed.\n * @param text text of the field\n * @param separator column separator, which requires quotes when present in the text\n * @return the CSV field\n */\nfunction csvField(text: string, separator: string): string {\n const safeText = FORMULA_START.test(text) ? `'${text}` : text;\n const needsQuotes = safeText.includes(separator) || /[\"\\r\\n]/.test(safeText);\n\n return needsQuotes ? `\"${safeText.replaceAll('\"', '\"\"')}\"` : safeText;\n}\n"],"mappings":";;;;;;;;;;AAUA,IAAa,gBAAgB;;AAG7B,IAAa,sBAAsB;;AAGnC,IAAM,aAAa;;AAGnB,IAAM,WAAW;;;;;;AAOjB,IAAM,gBAAgB;;;;;;AAOtB,SAAgB,aAAa,QAAwB;CAGjD,OAFgB,IAAI,KAAK,aAAa,MAAM,CAAC,CAAC,cAAc,GAAG,CAAC,CAAC,MAAK,SAAQ,KAAK,SAAS,SAAS,CAAC,EAAE,UAErF,MAAA,MAAA;AACvB;;;;;;;;;;;AAYA,IAAa,YAAb,MAA+C;CAC3C,KAAc;CACd,QAAiB;CACjB,YAAqB;CACrB,WAAoB;CACpB,iBAA0B;CAE1B,MAAM,SAAS,UAAyC;EACpD,IAAI,SAAS,OAAO,WAAW,GAC3B,MAAM,IAAI,MAAM,uDAAuD,SAAS,OAAO,OAAO,EAAE;EAGpG,MAAM,OAAO,QAAQ,SAAS,OAAO,IAAI,aAAa,QAAQ,GAAG,eAAe,QAAQ,CAAC,CAAC,WAAW;EACrG,OAAO,IAAI,KAAK,CAAC,WAAW,IAAI,GAAG,EAAE,MAAM,KAAK,SAAS,CAAC;CAC9D;AACJ;;;;;;;;AASA,SAAgB,QAAQ,OAAoB,SAAiB,gBAAgB,aAA8B;CACvG,MAAM,YAAY,aAAa,MAAM;CACrC,MAAM,SAAS,SAAiB,SAAS,MAAM,SAAS;CAMxD,OAAO,CALQ,MAAM,QAAQ,KAAI,WAAU,MAAM,OAAO,MAAM,CAKtD,GAAQ,GAJH,MAAM,KAAK,KAAI,QACxB,MAAM,QAAQ,KAAK,QAAQ,MAAM,QAAQ,aAAa,IAAI,IAAI,OAAO,QAAQ,WAAW,GAAG,QAAQ,KAAK,CAAC,CAG1F,CAAI,CAAC,CAAC,KAAI,WAAU,OAAO,KAAK,SAAS,IAAI,UAAU,CAAC,CAAC,KAAK,EAAE;AACvF;;;;;;;;;;AAWA,SAAS,QAAQ,MAAsB,QAAgB,OAAyC;CAC5F,MAAM,OAAO,SAAS,MAAM,OAAO,MAAM;CAEzC,OAAO,KAAK,SAAS,WAAW,OAAO,MAAM,IAAI;AACrD;;;;;;;AAQA,SAAS,SAAS,MAAc,WAA2B;CACvD,MAAM,WAAW,cAAc,KAAK,IAAI,IAAI,IAAI,SAAS;CAGzD,OAFoB,SAAS,SAAS,SAAS,KAAK,UAAU,KAAK,QAAQ,IAEtD,IAAI,SAAS,WAAW,MAAK,MAAI,EAAE,KAAK;AACjE"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Workbook } from 'exceljs';
|
|
2
|
+
import { ExportDocument } from '../ExportDocument';
|
|
3
|
+
import { ExportFormat } from '../ExportFormat';
|
|
4
|
+
import { XlsxColors } from './XlsxStyle';
|
|
5
|
+
/** Options of an {@link XlsxFormat}. */
|
|
6
|
+
export type XlsxFormatOptions = {
|
|
7
|
+
/** Colors of the file (e.g. the brand colors of the app); the ones not given use the defaults. */
|
|
8
|
+
colors?: Partial<XlsxColors>;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Exports to Excel (`.xlsx`) with [ExcelJS](https://github.com/exceljs/exceljs): a sheet in the file for each sheet
|
|
12
|
+
* of the document, with styles, the logo and the numbers in a numeric format (not text).
|
|
13
|
+
*
|
|
14
|
+
* ExcelJS is loaded on demand (dynamic `import()`), like ECharts: imported statically, it would be in the bundle of
|
|
15
|
+
* every page that can export, even if the user exports nothing.
|
|
16
|
+
* @author Manoel Campos
|
|
17
|
+
*/
|
|
18
|
+
export declare class XlsxFormat implements ExportFormat {
|
|
19
|
+
readonly id = "xlsx";
|
|
20
|
+
readonly label = "Excel (.xlsx)";
|
|
21
|
+
readonly extension = "xlsx";
|
|
22
|
+
readonly mimeType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
|
23
|
+
readonly multipleSheets = true;
|
|
24
|
+
private readonly styles;
|
|
25
|
+
/** @param options options of the format, such as the colors of the file */
|
|
26
|
+
constructor(options?: XlsxFormatOptions);
|
|
27
|
+
generate(document: ExportDocument): Promise<Blob>;
|
|
28
|
+
/**
|
|
29
|
+
* Builds the workbook with a sheet for each sheet of the document.
|
|
30
|
+
* @param document data to export
|
|
31
|
+
* @return the workbook ready to be written
|
|
32
|
+
* @throws Error if the document has no sheets
|
|
33
|
+
*/
|
|
34
|
+
buildWorkbook(document: ExportDocument): Promise<Workbook>;
|
|
35
|
+
}
|
|
@@ -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[];
|