@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,63 @@
|
|
|
1
|
+
import type { EChartsOption } from 'echarts';
|
|
2
|
+
import { ChartSeries, ChartUnit } from './ChartSeries';
|
|
3
|
+
/**
|
|
4
|
+
* Splits the series of a chart into panels, one per unit, stacked vertically and sharing the same X axis of
|
|
5
|
+
* categories (small multiples). So series with different units (e.g. $ and %) never share the same Y axis, and each
|
|
6
|
+
* panel shows its unit in the name of the axis, without repeating the unit in the legend.
|
|
7
|
+
* @author Manoel Campos
|
|
8
|
+
*/
|
|
9
|
+
/** Series of the same unit, drawn in the same panel. */
|
|
10
|
+
export type Panel = {
|
|
11
|
+
unit: ChartUnit;
|
|
12
|
+
series: ChartSeries[];
|
|
13
|
+
};
|
|
14
|
+
/** Room at the top of the chart, for the title and one legend row (px). */
|
|
15
|
+
export declare const PANELS_TOP = 100;
|
|
16
|
+
/** Height of each panel (px). */
|
|
17
|
+
export declare const PANEL_HEIGHT = 280;
|
|
18
|
+
/** Space between a panel and the next one, where the category labels of the upper panel are (px). */
|
|
19
|
+
export declare const PANEL_GAP = 60;
|
|
20
|
+
/** Room below the last panel, for the category labels (px). */
|
|
21
|
+
export declare const BOTTOM_MARGIN = 40;
|
|
22
|
+
/** Extra height for the zoom bar of the X axis, when it is shown (px). */
|
|
23
|
+
export declare const ZOOM_HEIGHT = 50;
|
|
24
|
+
/** From how many categories the X axis gets a zoom bar, so the columns are not squeezed. */
|
|
25
|
+
export declare const MIN_CATEGORIES_FOR_ZOOM = 16;
|
|
26
|
+
/**
|
|
27
|
+
* Formats a number in a compact way (e.g. 1,250,000 → "1.3M" in `en-US`, "1,3 mi" in `pt-BR`), so the axes are not
|
|
28
|
+
* cluttered. The full value stays in the tooltip.
|
|
29
|
+
* @param value value to format
|
|
30
|
+
* @param locale locale of the format; defaults to `en-US`
|
|
31
|
+
* @return the value in the compact format of the locale
|
|
32
|
+
*/
|
|
33
|
+
export declare function formatCompactNumber(value: number, locale?: string): string;
|
|
34
|
+
/**
|
|
35
|
+
* Groups the series by the label of the unit, in the order each unit first appears.
|
|
36
|
+
* @param series series of the chart
|
|
37
|
+
* @return a panel per unit
|
|
38
|
+
*/
|
|
39
|
+
export declare function groupByUnit(series: ChartSeries[]): Panel[];
|
|
40
|
+
/**
|
|
41
|
+
* Checks whether the X axis needs a zoom bar, so many categories are not squeezed.
|
|
42
|
+
* @param categoriesCount number of categories in the X axis
|
|
43
|
+
* @return true if the X axis should have a zoom bar
|
|
44
|
+
*/
|
|
45
|
+
export declare function needsZoom(categoriesCount: number): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Computes the total height of the chart, which grows with the number of panels.
|
|
48
|
+
* @param panelsCount number of panels (different units)
|
|
49
|
+
* @param categoriesCount number of categories in the X axis, which defines whether there is a zoom bar
|
|
50
|
+
* @param extraTop extra room at the top, besides {@link PANELS_TOP}, for the extra rows of the legend (px)
|
|
51
|
+
* @return the height of the chart (px)
|
|
52
|
+
*/
|
|
53
|
+
export declare function panelsHeight(panelsCount: number, categoriesCount: number, extraTop?: number): number;
|
|
54
|
+
/**
|
|
55
|
+
* Builds the grids and the axes of each panel. Panel `i` uses the grid, the X axis and the Y axis of index `i`.
|
|
56
|
+
* The pointers of the X axes are linked, so hovering a category highlights it in all panels.
|
|
57
|
+
* @param panels panels of the chart
|
|
58
|
+
* @param categories categories of the X axis
|
|
59
|
+
* @param extraTop extra room at the top, besides {@link PANELS_TOP}, for the extra rows of the legend (px)
|
|
60
|
+
* @param locale locale of the number format of the Y axes; defaults to `en-US`
|
|
61
|
+
* @return the parts of the ECharts `option` of the layout of the panels
|
|
62
|
+
*/
|
|
63
|
+
export declare function buildPanelAxes(panels: Panel[], categories: (string | number)[], extraTop?: number, locale?: string): Pick<EChartsOption, 'grid' | 'xAxis' | 'yAxis' | 'dataZoom' | 'axisPointer'>;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { DEFAULT_LOCALE } from "../../../../i18n/KitLocale.js";
|
|
3
|
+
// src/component/organism/EChart/chart/UnitPanels.ts
|
|
4
|
+
/** Room at the top of the chart, for the title and one legend row (px). */
|
|
5
|
+
var PANELS_TOP = 100;
|
|
6
|
+
/** Height of each panel (px). */
|
|
7
|
+
var PANEL_HEIGHT = 280;
|
|
8
|
+
/** Space between a panel and the next one, where the category labels of the upper panel are (px). */
|
|
9
|
+
var PANEL_GAP = 60;
|
|
10
|
+
/** Room below the last panel, for the category labels (px). */
|
|
11
|
+
var BOTTOM_MARGIN = 40;
|
|
12
|
+
/** Extra height for the zoom bar of the X axis, when it is shown (px). */
|
|
13
|
+
var ZOOM_HEIGHT = 50;
|
|
14
|
+
/** Side margins of the panels (px). The left one is wider to fit the values of the Y axis. */
|
|
15
|
+
var LEFT_MARGIN = 80;
|
|
16
|
+
var RIGHT_MARGIN = 40;
|
|
17
|
+
/** From how many categories the X axis gets a zoom bar, so the columns are not squeezed. */
|
|
18
|
+
var MIN_CATEGORIES_FOR_ZOOM = 16;
|
|
19
|
+
/** Compact number formatters already created, by locale. */
|
|
20
|
+
var compactFormatters = /* @__PURE__ */ new Map();
|
|
21
|
+
/**
|
|
22
|
+
* Formats a number in a compact way (e.g. 1,250,000 → "1.3M" in `en-US`, "1,3 mi" in `pt-BR`), so the axes are not
|
|
23
|
+
* cluttered. The full value stays in the tooltip.
|
|
24
|
+
* @param value value to format
|
|
25
|
+
* @param locale locale of the format; defaults to `en-US`
|
|
26
|
+
* @return the value in the compact format of the locale
|
|
27
|
+
*/
|
|
28
|
+
function formatCompactNumber(value, locale = DEFAULT_LOCALE) {
|
|
29
|
+
let formatter = compactFormatters.get(locale);
|
|
30
|
+
if (!formatter) {
|
|
31
|
+
formatter = new Intl.NumberFormat(locale, {
|
|
32
|
+
notation: "compact",
|
|
33
|
+
maximumFractionDigits: 1
|
|
34
|
+
});
|
|
35
|
+
compactFormatters.set(locale, formatter);
|
|
36
|
+
}
|
|
37
|
+
return formatter.format(value);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Groups the series by the label of the unit, in the order each unit first appears.
|
|
41
|
+
* @param series series of the chart
|
|
42
|
+
* @return a panel per unit
|
|
43
|
+
*/
|
|
44
|
+
function groupByUnit(series) {
|
|
45
|
+
const panels = /* @__PURE__ */ new Map();
|
|
46
|
+
series.forEach((serie) => {
|
|
47
|
+
const panel = panels.get(serie.unit.label) ?? {
|
|
48
|
+
unit: serie.unit,
|
|
49
|
+
series: []
|
|
50
|
+
};
|
|
51
|
+
panel.series.push(serie);
|
|
52
|
+
panels.set(serie.unit.label, panel);
|
|
53
|
+
});
|
|
54
|
+
return Array.from(panels.values());
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Checks whether the X axis needs a zoom bar, so many categories are not squeezed.
|
|
58
|
+
* @param categoriesCount number of categories in the X axis
|
|
59
|
+
* @return true if the X axis should have a zoom bar
|
|
60
|
+
*/
|
|
61
|
+
function needsZoom(categoriesCount) {
|
|
62
|
+
return categoriesCount >= 16;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Computes the total height of the chart, which grows with the number of panels.
|
|
66
|
+
* @param panelsCount number of panels (different units)
|
|
67
|
+
* @param categoriesCount number of categories in the X axis, which defines whether there is a zoom bar
|
|
68
|
+
* @param extraTop extra room at the top, besides {@link PANELS_TOP}, for the extra rows of the legend (px)
|
|
69
|
+
* @return the height of the chart (px)
|
|
70
|
+
*/
|
|
71
|
+
function panelsHeight(panelsCount, categoriesCount, extraTop = 0) {
|
|
72
|
+
const panels = panelsCount * 280 + Math.max(panelsCount - 1, 0) * 60;
|
|
73
|
+
const zoom = needsZoom(categoriesCount) ? 50 : 0;
|
|
74
|
+
return 100 + extraTop + panels + 40 + zoom;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Builds the grids and the axes of each panel. Panel `i` uses the grid, the X axis and the Y axis of index `i`.
|
|
78
|
+
* The pointers of the X axes are linked, so hovering a category highlights it in all panels.
|
|
79
|
+
* @param panels panels of the chart
|
|
80
|
+
* @param categories categories of the X axis
|
|
81
|
+
* @param extraTop extra room at the top, besides {@link PANELS_TOP}, for the extra rows of the legend (px)
|
|
82
|
+
* @param locale locale of the number format of the Y axes; defaults to `en-US`
|
|
83
|
+
* @return the parts of the ECharts `option` of the layout of the panels
|
|
84
|
+
*/
|
|
85
|
+
function buildPanelAxes(panels, categories, extraTop = 0, locale = DEFAULT_LOCALE) {
|
|
86
|
+
const indexes = panels.map((_, index) => index);
|
|
87
|
+
const categoryLabels = categories.map(String);
|
|
88
|
+
return {
|
|
89
|
+
grid: indexes.map((index) => ({
|
|
90
|
+
top: 100 + extraTop + index * 340,
|
|
91
|
+
height: 280,
|
|
92
|
+
left: LEFT_MARGIN,
|
|
93
|
+
right: RIGHT_MARGIN
|
|
94
|
+
})),
|
|
95
|
+
xAxis: indexes.map((index) => ({
|
|
96
|
+
type: "category",
|
|
97
|
+
gridIndex: index,
|
|
98
|
+
data: categoryLabels
|
|
99
|
+
})),
|
|
100
|
+
yAxis: panels.map((panel, index) => ({
|
|
101
|
+
type: "value",
|
|
102
|
+
gridIndex: index,
|
|
103
|
+
name: panel.unit.label,
|
|
104
|
+
axisLabel: { formatter: (value) => formatCompactNumber(value, locale) }
|
|
105
|
+
})),
|
|
106
|
+
dataZoom: needsZoom(categories.length) ? buildZoom(indexes) : [],
|
|
107
|
+
axisPointer: { link: [{ xAxisIndex: "all" }] }
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Creates the zoom bar (and the zoom by the mouse wheel) applied to all X axes at once.
|
|
112
|
+
* @param xAxisIndexes indexes of the X axes of the panels
|
|
113
|
+
* @return the ECharts `dataZoom` configuration
|
|
114
|
+
*/
|
|
115
|
+
function buildZoom(xAxisIndexes) {
|
|
116
|
+
return [{
|
|
117
|
+
type: "slider",
|
|
118
|
+
xAxisIndex: xAxisIndexes,
|
|
119
|
+
bottom: 10
|
|
120
|
+
}, {
|
|
121
|
+
type: "inside",
|
|
122
|
+
xAxisIndex: xAxisIndexes
|
|
123
|
+
}];
|
|
124
|
+
}
|
|
125
|
+
export { BOTTOM_MARGIN, MIN_CATEGORIES_FOR_ZOOM, PANELS_TOP, PANEL_GAP, PANEL_HEIGHT, ZOOM_HEIGHT, buildPanelAxes, formatCompactNumber, groupByUnit, needsZoom, panelsHeight };
|
|
126
|
+
|
|
127
|
+
//# sourceMappingURL=UnitPanels.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UnitPanels.js","names":[],"sources":["../../../../../src/component/organism/EChart/chart/UnitPanels.ts"],"sourcesContent":["import type { EChartsOption } from 'echarts';\n\nimport { DEFAULT_LOCALE } from '../../../../i18n/KitLocale';\nimport { ChartSeries, ChartUnit } from './ChartSeries';\n\n/**\n * Splits the series of a chart into panels, one per unit, stacked vertically and sharing the same X axis of\n * categories (small multiples). So series with different units (e.g. $ and %) never share the same Y axis, and each\n * panel shows its unit in the name of the axis, without repeating the unit in the legend.\n * @author Manoel Campos\n */\n\n/** Series of the same unit, drawn in the same panel. */\nexport type Panel = {\n unit: ChartUnit;\n series: ChartSeries[];\n};\n\n/** Room at the top of the chart, for the title and one legend row (px). */\nexport const PANELS_TOP = 100;\n\n/** Height of each panel (px). */\nexport const PANEL_HEIGHT = 280;\n\n/** Space between a panel and the next one, where the category labels of the upper panel are (px). */\nexport const PANEL_GAP = 60;\n\n/** Room below the last panel, for the category labels (px). */\nexport const BOTTOM_MARGIN = 40;\n\n/** Extra height for the zoom bar of the X axis, when it is shown (px). */\nexport const ZOOM_HEIGHT = 50;\n\n/** Side margins of the panels (px). The left one is wider to fit the values of the Y axis. */\nconst LEFT_MARGIN = 80;\nconst RIGHT_MARGIN = 40;\n\n/** From how many categories the X axis gets a zoom bar, so the columns are not squeezed. */\nexport const MIN_CATEGORIES_FOR_ZOOM = 16;\n\n/** Compact number formatters already created, by locale. */\nconst compactFormatters = new Map<string, Intl.NumberFormat>();\n\n/**\n * Formats a number in a compact way (e.g. 1,250,000 → \"1.3M\" in `en-US`, \"1,3 mi\" in `pt-BR`), so the axes are not\n * cluttered. The full value stays in the tooltip.\n * @param value value to format\n * @param locale locale of the format; defaults to `en-US`\n * @return the value in the compact format of the locale\n */\nexport function formatCompactNumber(value: number, locale: string = DEFAULT_LOCALE): string {\n let formatter = compactFormatters.get(locale);\n if (!formatter) {\n formatter = new Intl.NumberFormat(locale, { notation: 'compact', maximumFractionDigits: 1 });\n compactFormatters.set(locale, formatter);\n }\n\n return formatter.format(value);\n}\n\n/**\n * Groups the series by the label of the unit, in the order each unit first appears.\n * @param series series of the chart\n * @return a panel per unit\n */\nexport function groupByUnit(series: ChartSeries[]): Panel[] {\n const panels = new Map<string, Panel>();\n series.forEach(serie => {\n const panel = panels.get(serie.unit.label) ?? { unit: serie.unit, series: [] };\n panel.series.push(serie);\n panels.set(serie.unit.label, panel);\n });\n\n return Array.from(panels.values());\n}\n\n/**\n * Checks whether the X axis needs a zoom bar, so many categories are not squeezed.\n * @param categoriesCount number of categories in the X axis\n * @return true if the X axis should have a zoom bar\n */\nexport function needsZoom(categoriesCount: number): boolean {\n return categoriesCount >= MIN_CATEGORIES_FOR_ZOOM;\n}\n\n/**\n * Computes the total height of the chart, which grows with the number of panels.\n * @param panelsCount number of panels (different units)\n * @param categoriesCount number of categories in the X axis, which defines whether there is a zoom bar\n * @param extraTop extra room at the top, besides {@link PANELS_TOP}, for the extra rows of the legend (px)\n * @return the height of the chart (px)\n */\nexport function panelsHeight(panelsCount: number, categoriesCount: number, extraTop: number = 0): number {\n const panels = panelsCount * PANEL_HEIGHT + Math.max(panelsCount - 1, 0) * PANEL_GAP;\n const zoom = needsZoom(categoriesCount) ? ZOOM_HEIGHT : 0;\n return PANELS_TOP + extraTop + panels + BOTTOM_MARGIN + zoom;\n}\n\n/**\n * Builds the grids and the axes of each panel. Panel `i` uses the grid, the X axis and the Y axis of index `i`.\n * The pointers of the X axes are linked, so hovering a category highlights it in all panels.\n * @param panels panels of the chart\n * @param categories categories of the X axis\n * @param extraTop extra room at the top, besides {@link PANELS_TOP}, for the extra rows of the legend (px)\n * @param locale locale of the number format of the Y axes; defaults to `en-US`\n * @return the parts of the ECharts `option` of the layout of the panels\n */\nexport function buildPanelAxes(\n panels: Panel[],\n categories: (string | number)[],\n extraTop: number = 0,\n locale: string = DEFAULT_LOCALE\n): Pick<EChartsOption, 'grid' | 'xAxis' | 'yAxis' | 'dataZoom' | 'axisPointer'> {\n const indexes = panels.map((_, index) => index);\n const categoryLabels = categories.map(String);\n\n return {\n grid: indexes.map(index => ({\n top: PANELS_TOP + extraTop + index * (PANEL_HEIGHT + PANEL_GAP),\n height: PANEL_HEIGHT,\n left: LEFT_MARGIN,\n right: RIGHT_MARGIN\n })),\n xAxis: indexes.map(index => ({ type: 'category', gridIndex: index, data: categoryLabels })),\n yAxis: panels.map((panel, index) => ({\n type: 'value',\n gridIndex: index,\n name: panel.unit.label,\n axisLabel: { formatter: (value: number) => formatCompactNumber(value, locale) }\n })),\n dataZoom: needsZoom(categories.length) ? buildZoom(indexes) : [],\n axisPointer: { link: [{ xAxisIndex: 'all' }] }\n };\n}\n\n/**\n * Creates the zoom bar (and the zoom by the mouse wheel) applied to all X axes at once.\n * @param xAxisIndexes indexes of the X axes of the panels\n * @return the ECharts `dataZoom` configuration\n */\nfunction buildZoom(xAxisIndexes: number[]): EChartsOption['dataZoom'] {\n return [\n { type: 'slider', xAxisIndex: xAxisIndexes, bottom: BOTTOM_MARGIN / 4 },\n { type: 'inside', xAxisIndex: xAxisIndexes }\n ];\n}\n"],"mappings":";;;;AAmBA,IAAa,aAAa;;AAG1B,IAAa,eAAe;;AAG5B,IAAa,YAAY;;AAGzB,IAAa,gBAAgB;;AAG7B,IAAa,cAAc;;AAG3B,IAAM,cAAc;AACpB,IAAM,eAAe;;AAGrB,IAAa,0BAA0B;;AAGvC,IAAM,oCAAoB,IAAI,IAA+B;;;;;;;;AAS7D,SAAgB,oBAAoB,OAAe,SAAiB,gBAAwB;CACxF,IAAI,YAAY,kBAAkB,IAAI,MAAM;CAC5C,IAAI,CAAC,WAAW;EACZ,YAAY,IAAI,KAAK,aAAa,QAAQ;GAAE,UAAU;GAAW,uBAAuB;EAAE,CAAC;EAC3F,kBAAkB,IAAI,QAAQ,SAAS;CAC3C;CAEA,OAAO,UAAU,OAAO,KAAK;AACjC;;;;;;AAOA,SAAgB,YAAY,QAAgC;CACxD,MAAM,yBAAS,IAAI,IAAmB;CACtC,OAAO,SAAQ,UAAS;EACpB,MAAM,QAAQ,OAAO,IAAI,MAAM,KAAK,KAAK,KAAK;GAAE,MAAM,MAAM;GAAM,QAAQ,CAAC;EAAE;EAC7E,MAAM,OAAO,KAAK,KAAK;EACvB,OAAO,IAAI,MAAM,KAAK,OAAO,KAAK;CACtC,CAAC;CAED,OAAO,MAAM,KAAK,OAAO,OAAO,CAAC;AACrC;;;;;;AAOA,SAAgB,UAAU,iBAAkC;CACxD,OAAO,mBAAA;AACX;;;;;;;;AASA,SAAgB,aAAa,aAAqB,iBAAyB,WAAmB,GAAW;CACrG,MAAM,SAAS,cAAA,MAA6B,KAAK,IAAI,cAAc,GAAG,CAAC,IAAA;CACvE,MAAM,OAAO,UAAU,eAAe,IAAA,KAAkB;CACxD,OAAA,MAAoB,WAAW,SAAA,KAAyB;AAC5D;;;;;;;;;;AAWA,SAAgB,eACZ,QACA,YACA,WAAmB,GACnB,SAAiB,gBAC2D;CAC5E,MAAM,UAAU,OAAO,KAAK,GAAG,UAAU,KAAK;CAC9C,MAAM,iBAAiB,WAAW,IAAI,MAAM;CAE5C,OAAO;EACH,MAAM,QAAQ,KAAI,WAAU;GACxB,KAAA,MAAkB,WAAW,QAAS;GACtC,QAAA;GACA,MAAM;GACN,OAAO;EACX,EAAE;EACF,OAAO,QAAQ,KAAI,WAAU;GAAE,MAAM;GAAY,WAAW;GAAO,MAAM;EAAe,EAAE;EAC1F,OAAO,OAAO,KAAK,OAAO,WAAW;GACjC,MAAM;GACN,WAAW;GACX,MAAM,MAAM,KAAK;GACjB,WAAW,EAAE,YAAY,UAAkB,oBAAoB,OAAO,MAAM,EAAE;EAClF,EAAE;EACF,UAAU,UAAU,WAAW,MAAM,IAAI,UAAU,OAAO,IAAI,CAAC;EAC/D,aAAa,EAAE,MAAM,CAAC,EAAE,YAAY,MAAM,CAAC,EAAE;CACjD;AACJ;;;;;;AAOA,SAAS,UAAU,cAAmD;CAClE,OAAO,CACH;EAAE,MAAM;EAAU,YAAY;EAAc,QAAA;CAA0B,GACtE;EAAE,MAAM;EAAU,YAAY;CAAa,CAC/C;AACJ"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { CSSProperties } from 'react';
|
|
2
|
+
import type { EChartsOption, ToolboxComponentOption, TooltipComponentOption, VisualMapComponentOption } from 'echarts';
|
|
3
|
+
/** Shows the tooltip when hovering each element (map area, bar, slice etc.). */
|
|
4
|
+
export declare const DEFAULT_TOOLTIP: TooltipComponentOption;
|
|
5
|
+
/**
|
|
6
|
+
* Pixel density of the image saved by the "save as image" button.
|
|
7
|
+
* 3x gives a high resolution image, suited to printed reports.
|
|
8
|
+
*/
|
|
9
|
+
export declare const SAVE_IMAGE_PIXEL_RATIO = 3;
|
|
10
|
+
/** Adds to the chart the button that saves it as a high resolution image. */
|
|
11
|
+
export declare const DEFAULT_TOOLBOX: ToolboxComponentOption;
|
|
12
|
+
/** Color of the lowest values of the scale of the {@link DEFAULT_VISUAL_MAP}. */
|
|
13
|
+
export declare const VISUAL_MAP_MIN_COLOR = "#e0f3f8";
|
|
14
|
+
/** Color of the highest values of the scale of the {@link DEFAULT_VISUAL_MAP}. */
|
|
15
|
+
export declare const VISUAL_MAP_MAX_COLOR = "#08589e";
|
|
16
|
+
/**
|
|
17
|
+
* Color scale (the ECharts `visualMap` component) that paints each element of the chart (map area, bar etc.)
|
|
18
|
+
* according to its value, in a gradient from {@link VISUAL_MAP_MIN_COLOR} (value 0) to {@link VISUAL_MAP_MAX_COLOR}
|
|
19
|
+
* (value 1). It also shows a legend bar with this gradient, labeled from "0%" to "100%", with handles the user can drag
|
|
20
|
+
* to highlight only the elements within a range of values (`calculable`).
|
|
21
|
+
*
|
|
22
|
+
* The 0..1 scale matches percentage values.
|
|
23
|
+
* Since the color comes from the value, and not from the palette of the series, it does not suit charts of absolute
|
|
24
|
+
* values (money, volumes): turn it off with the `withVisualMap` prop of the {@link EChart}.
|
|
25
|
+
*/
|
|
26
|
+
export declare const DEFAULT_VISUAL_MAP: VisualMapComponentOption;
|
|
27
|
+
/** Default values of the `option` of any chart, except the {@link DEFAULT_VISUAL_MAP} (which is optional). */
|
|
28
|
+
export declare const DEFAULT_OPTION: EChartsOption;
|
|
29
|
+
/** Default height of the chart, in pixels. */
|
|
30
|
+
export declare const DEFAULT_CHART_HEIGHT = 600;
|
|
31
|
+
/** Style used when no `style` is given to the {@link EChart}: it takes the whole available width. */
|
|
32
|
+
export declare const DEFAULT_STYLE: CSSProperties;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
// src/component/organism/EChart/echartDefaults.ts
|
|
3
|
+
/** Shows the tooltip when hovering each element (map area, bar, slice etc.). */
|
|
4
|
+
var DEFAULT_TOOLTIP = { trigger: "item" };
|
|
5
|
+
/**
|
|
6
|
+
* Pixel density of the image saved by the "save as image" button.
|
|
7
|
+
* 3x gives a high resolution image, suited to printed reports.
|
|
8
|
+
*/
|
|
9
|
+
var SAVE_IMAGE_PIXEL_RATIO = 3;
|
|
10
|
+
/** Adds to the chart the button that saves it as a high resolution image. */
|
|
11
|
+
var DEFAULT_TOOLBOX = { feature: { saveAsImage: { pixelRatio: 3 } } };
|
|
12
|
+
/** Color of the lowest values of the scale of the {@link DEFAULT_VISUAL_MAP}. */
|
|
13
|
+
var VISUAL_MAP_MIN_COLOR = "#e0f3f8";
|
|
14
|
+
/** Color of the highest values of the scale of the {@link DEFAULT_VISUAL_MAP}. */
|
|
15
|
+
var VISUAL_MAP_MAX_COLOR = "#08589e";
|
|
16
|
+
/**
|
|
17
|
+
* Color scale (the ECharts `visualMap` component) that paints each element of the chart (map area, bar etc.)
|
|
18
|
+
* according to its value, in a gradient from {@link VISUAL_MAP_MIN_COLOR} (value 0) to {@link VISUAL_MAP_MAX_COLOR}
|
|
19
|
+
* (value 1). It also shows a legend bar with this gradient, labeled from "0%" to "100%", with handles the user can drag
|
|
20
|
+
* to highlight only the elements within a range of values (`calculable`).
|
|
21
|
+
*
|
|
22
|
+
* The 0..1 scale matches percentage values.
|
|
23
|
+
* Since the color comes from the value, and not from the palette of the series, it does not suit charts of absolute
|
|
24
|
+
* values (money, volumes): turn it off with the `withVisualMap` prop of the {@link EChart}.
|
|
25
|
+
*/
|
|
26
|
+
var DEFAULT_VISUAL_MAP = {
|
|
27
|
+
min: 0,
|
|
28
|
+
max: 1,
|
|
29
|
+
calculable: true,
|
|
30
|
+
text: ["100%", "0%"],
|
|
31
|
+
inRange: { color: [VISUAL_MAP_MIN_COLOR, VISUAL_MAP_MAX_COLOR] }
|
|
32
|
+
};
|
|
33
|
+
/** Default values of the `option` of any chart, except the {@link DEFAULT_VISUAL_MAP} (which is optional). */
|
|
34
|
+
var DEFAULT_OPTION = {
|
|
35
|
+
tooltip: DEFAULT_TOOLTIP,
|
|
36
|
+
toolbox: DEFAULT_TOOLBOX
|
|
37
|
+
};
|
|
38
|
+
/** Default height of the chart, in pixels. */
|
|
39
|
+
var DEFAULT_CHART_HEIGHT = 600;
|
|
40
|
+
/** Style used when no `style` is given to the {@link EChart}: it takes the whole available width. */
|
|
41
|
+
var DEFAULT_STYLE = {
|
|
42
|
+
width: "100%",
|
|
43
|
+
height: 600
|
|
44
|
+
};
|
|
45
|
+
export { DEFAULT_CHART_HEIGHT, DEFAULT_OPTION, DEFAULT_STYLE, DEFAULT_TOOLBOX, DEFAULT_TOOLTIP, DEFAULT_VISUAL_MAP, SAVE_IMAGE_PIXEL_RATIO, VISUAL_MAP_MAX_COLOR, VISUAL_MAP_MIN_COLOR };
|
|
46
|
+
|
|
47
|
+
//# sourceMappingURL=echartDefaults.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"echartDefaults.js","names":[],"sources":["../../../../src/component/organism/EChart/echartDefaults.ts"],"sourcesContent":["import { CSSProperties } from 'react';\n\nimport type { EChartsOption, ToolboxComponentOption, TooltipComponentOption, VisualMapComponentOption } from 'echarts';\n\n/** Shows the tooltip when hovering each element (map area, bar, slice etc.). */\nexport const DEFAULT_TOOLTIP: TooltipComponentOption = { trigger: 'item' };\n\n/**\n * Pixel density of the image saved by the \"save as image\" button.\n * 3x gives a high resolution image, suited to printed reports.\n */\nexport const SAVE_IMAGE_PIXEL_RATIO = 3;\n\n/** Adds to the chart the button that saves it as a high resolution image. */\nexport const DEFAULT_TOOLBOX: ToolboxComponentOption = {\n feature: { saveAsImage: { pixelRatio: SAVE_IMAGE_PIXEL_RATIO } }\n};\n\n/** Color of the lowest values of the scale of the {@link DEFAULT_VISUAL_MAP}. */\nexport const VISUAL_MAP_MIN_COLOR = '#e0f3f8';\n\n/** Color of the highest values of the scale of the {@link DEFAULT_VISUAL_MAP}. */\nexport const VISUAL_MAP_MAX_COLOR = '#08589e';\n\n/**\n * Color scale (the ECharts `visualMap` component) that paints each element of the chart (map area, bar etc.)\n * according to its value, in a gradient from {@link VISUAL_MAP_MIN_COLOR} (value 0) to {@link VISUAL_MAP_MAX_COLOR}\n * (value 1). It also shows a legend bar with this gradient, labeled from \"0%\" to \"100%\", with handles the user can drag\n * to highlight only the elements within a range of values (`calculable`).\n *\n * The 0..1 scale matches percentage values.\n * Since the color comes from the value, and not from the palette of the series, it does not suit charts of absolute\n * values (money, volumes): turn it off with the `withVisualMap` prop of the {@link EChart}.\n */\nexport const DEFAULT_VISUAL_MAP: VisualMapComponentOption = {\n min: 0,\n max: 1,\n calculable: true,\n text: ['100%', '0%'],\n inRange: { color: [VISUAL_MAP_MIN_COLOR, VISUAL_MAP_MAX_COLOR] }\n};\n\n/** Default values of the `option` of any chart, except the {@link DEFAULT_VISUAL_MAP} (which is optional). */\nexport const DEFAULT_OPTION: EChartsOption = {\n tooltip: DEFAULT_TOOLTIP,\n toolbox: DEFAULT_TOOLBOX\n};\n\n/** Default height of the chart, in pixels. */\nexport const DEFAULT_CHART_HEIGHT = 600;\n\n/** Style used when no `style` is given to the {@link EChart}: it takes the whole available width. */\nexport const DEFAULT_STYLE: CSSProperties = { width: '100%', height: DEFAULT_CHART_HEIGHT };\n"],"mappings":";;;AAKA,IAAa,kBAA0C,EAAE,SAAS,OAAO;;;;;AAMzE,IAAa,yBAAyB;;AAGtC,IAAa,kBAA0C,EACnD,SAAS,EAAE,aAAa,EAAE,YAAA,EAAmC,EAAE,EACnE;;AAGA,IAAa,uBAAuB;;AAGpC,IAAa,uBAAuB;;;;;;;;;;;AAYpC,IAAa,qBAA+C;CACxD,KAAK;CACL,KAAK;CACL,YAAY;CACZ,MAAM,CAAC,QAAQ,IAAI;CACnB,SAAS,EAAE,OAAO,CAAC,sBAAsB,oBAAoB,EAAE;AACnE;;AAGA,IAAa,iBAAgC;CACzC,SAAS;CACT,SAAS;AACb;;AAGA,IAAa,uBAAuB;;AAGpC,IAAa,gBAA+B;CAAE,OAAO;CAAQ,QAAA;AAA6B"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { RefObject } from 'react';
|
|
2
|
+
import type { EChartsOption } from 'echarts';
|
|
3
|
+
/** Data ECharts gives to whoever handles an event (e.g. the name of the clicked series). */
|
|
4
|
+
export type EChartEventParams = {
|
|
5
|
+
/** Name of the element (e.g. legend item or slice) related to the event. */
|
|
6
|
+
name?: string;
|
|
7
|
+
/** Name of the series related to the event, in click events on an element of the chart. */
|
|
8
|
+
seriesName?: string;
|
|
9
|
+
[attribute: string]: unknown;
|
|
10
|
+
};
|
|
11
|
+
/** Functions that handle ECharts events, indexed by the event name (e.g. `click`, `legendselectchanged`). */
|
|
12
|
+
export type EChartEventHandlers = Record<string, (params: EChartEventParams) => void>;
|
|
13
|
+
/** Geometry of a map (e.g. a GeoJSON with the areas of the cities), in the format accepted by `echarts.registerMap`. */
|
|
14
|
+
export type EChartMapSource = Parameters<typeof import('echarts').registerMap>[1];
|
|
15
|
+
/** Maps used by the chart, indexed by the name the `map` series (or the `geo` component) use in the `map` attribute. */
|
|
16
|
+
export type EChartMaps = Record<string, EChartMapSource>;
|
|
17
|
+
/**
|
|
18
|
+
* How ECharts draws the chart: in `canvas` (default, faster on screen) or in `svg`, which is printed as sharp vector
|
|
19
|
+
* graphics or saved as PDF. Use `svg` in reports.
|
|
20
|
+
*/
|
|
21
|
+
export type EChartRenderer = 'canvas' | 'svg';
|
|
22
|
+
/**
|
|
23
|
+
* Manages the life cycle of an ECharts instance bound to a DOM element: creates the instance on mount, applies the
|
|
24
|
+
* `option` whenever it changes, resizes the chart when the container changes its size and disposes the instance on
|
|
25
|
+
* unmount.
|
|
26
|
+
*
|
|
27
|
+
* ECharts is loaded on demand (dynamic `import()`), so only the pages that show charts download the library.
|
|
28
|
+
* @param option final option shown in the chart
|
|
29
|
+
* @param onEvents functions that handle the chart events; they are replaced when the object changes
|
|
30
|
+
* @param maps maps registered in ECharts before creating the chart; when they change, they are registered again and
|
|
31
|
+
* the chart is redrawn
|
|
32
|
+
* @param renderer how the chart is drawn; read only when the chart is created
|
|
33
|
+
* @return ref to assign to the element that will hold the chart
|
|
34
|
+
*/
|
|
35
|
+
export declare function useEChart(option: EChartsOption, onEvents?: EChartEventHandlers, maps?: EChartMaps, renderer?: EChartRenderer): RefObject<HTMLDivElement | null>;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useEffect, useRef } from "react";
|
|
3
|
+
// src/component/organism/EChart/useEChart.ts
|
|
4
|
+
/** notMerge: replaces the previous option, so attributes removed from the props disappear from the chart. */
|
|
5
|
+
var SET_OPTION_OPTS = { notMerge: true };
|
|
6
|
+
/**
|
|
7
|
+
* Print media query. It changes when the browser applies (or removes) the paper layout, whose width differs from the
|
|
8
|
+
* screen. It is more reliable than `beforeprint`, which fires before this layout and would measure the screen.
|
|
9
|
+
*/
|
|
10
|
+
var PRINT_MEDIA_QUERY = "print";
|
|
11
|
+
/**
|
|
12
|
+
* Manages the life cycle of an ECharts instance bound to a DOM element: creates the instance on mount, applies the
|
|
13
|
+
* `option` whenever it changes, resizes the chart when the container changes its size and disposes the instance on
|
|
14
|
+
* unmount.
|
|
15
|
+
*
|
|
16
|
+
* ECharts is loaded on demand (dynamic `import()`), so only the pages that show charts download the library.
|
|
17
|
+
* @param option final option shown in the chart
|
|
18
|
+
* @param onEvents functions that handle the chart events; they are replaced when the object changes
|
|
19
|
+
* @param maps maps registered in ECharts before creating the chart; when they change, they are registered again and
|
|
20
|
+
* the chart is redrawn
|
|
21
|
+
* @param renderer how the chart is drawn; read only when the chart is created
|
|
22
|
+
* @return ref to assign to the element that will hold the chart
|
|
23
|
+
*/
|
|
24
|
+
function useEChart(option, onEvents, maps, renderer = "canvas") {
|
|
25
|
+
const containerRef = useRef(null);
|
|
26
|
+
const chartRef = useRef(null);
|
|
27
|
+
const optionRef = useRef(option);
|
|
28
|
+
const onEventsRef = useRef(onEvents);
|
|
29
|
+
const boundEventsRef = useRef(void 0);
|
|
30
|
+
const mapsRef = useRef(maps);
|
|
31
|
+
const echartsRef = useRef(null);
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
mapsRef.current = maps;
|
|
34
|
+
if (!echartsRef.current || !chartRef.current) return;
|
|
35
|
+
registerMaps(echartsRef.current, maps);
|
|
36
|
+
chartRef.current.setOption(optionRef.current, SET_OPTION_OPTS);
|
|
37
|
+
}, [maps]);
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
optionRef.current = option;
|
|
40
|
+
chartRef.current?.setOption(option, SET_OPTION_OPTS);
|
|
41
|
+
}, [option]);
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
onEventsRef.current = onEvents;
|
|
44
|
+
if (chartRef.current) replaceEvents(chartRef.current, boundEventsRef, onEvents);
|
|
45
|
+
}, [onEvents]);
|
|
46
|
+
const rendererRef = useRef(renderer);
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
let unmounted = false;
|
|
49
|
+
let resizeObserver = null;
|
|
50
|
+
const resize = () => chartRef.current?.resize();
|
|
51
|
+
const printMedia = window.matchMedia(PRINT_MEDIA_QUERY);
|
|
52
|
+
printMedia.addEventListener("change", resize);
|
|
53
|
+
import("echarts").then((echarts) => {
|
|
54
|
+
const container = containerRef.current;
|
|
55
|
+
if (unmounted || !container) return;
|
|
56
|
+
echartsRef.current = echarts;
|
|
57
|
+
registerMaps(echarts, mapsRef.current);
|
|
58
|
+
const chart = echarts.init(container, void 0, { renderer: rendererRef.current });
|
|
59
|
+
chart.setOption(optionRef.current, SET_OPTION_OPTS);
|
|
60
|
+
replaceEvents(chart, boundEventsRef, onEventsRef.current);
|
|
61
|
+
chartRef.current = chart;
|
|
62
|
+
resizeObserver = new ResizeObserver(() => chart.resize());
|
|
63
|
+
resizeObserver.observe(container);
|
|
64
|
+
});
|
|
65
|
+
return () => {
|
|
66
|
+
unmounted = true;
|
|
67
|
+
printMedia.removeEventListener("change", resize);
|
|
68
|
+
resizeObserver?.disconnect();
|
|
69
|
+
chartRef.current?.dispose();
|
|
70
|
+
chartRef.current = null;
|
|
71
|
+
};
|
|
72
|
+
}, []);
|
|
73
|
+
return containerRef;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Registers the maps in ECharts, so the series can use them by name.
|
|
77
|
+
* @param echarts ECharts module
|
|
78
|
+
* @param maps maps indexed by name; `undefined` registers nothing
|
|
79
|
+
*/
|
|
80
|
+
function registerMaps(echarts, maps) {
|
|
81
|
+
Object.entries(maps ?? {}).forEach(([name, map]) => echarts.registerMap(name, map));
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Unbinds from the chart the handlers bound before and binds the new ones.
|
|
85
|
+
* @param chart chart instance
|
|
86
|
+
* @param boundEventsRef ref with the handlers currently bound; it is updated with the new ones
|
|
87
|
+
* @param newHandlers handlers to bind; `undefined` just unbinds the previous ones
|
|
88
|
+
*/
|
|
89
|
+
function replaceEvents(chart, boundEventsRef, newHandlers) {
|
|
90
|
+
if (boundEventsRef.current) unbindEvents(chart, boundEventsRef.current);
|
|
91
|
+
if (newHandlers) bindEvents(chart, newHandlers);
|
|
92
|
+
boundEventsRef.current = newHandlers;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Binds each handler to its event in the chart.
|
|
96
|
+
* @param chart chart instance
|
|
97
|
+
* @param onEvents handlers indexed by the event name
|
|
98
|
+
*/
|
|
99
|
+
function bindEvents(chart, onEvents) {
|
|
100
|
+
Object.entries(onEvents).forEach(([event, handler]) => chart.on(event, handler));
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Unbinds from the chart the handlers bound by {@link bindEvents}.
|
|
104
|
+
* @param chart chart instance
|
|
105
|
+
* @param onEvents handlers indexed by the event name
|
|
106
|
+
*/
|
|
107
|
+
function unbindEvents(chart, onEvents) {
|
|
108
|
+
Object.entries(onEvents).forEach(([event, handler]) => chart.off(event, handler));
|
|
109
|
+
}
|
|
110
|
+
export { useEChart };
|
|
111
|
+
|
|
112
|
+
//# sourceMappingURL=useEChart.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useEChart.js","names":[],"sources":["../../../../src/component/organism/EChart/useEChart.ts"],"sourcesContent":["import { RefObject, useEffect, useRef } from 'react';\n\nimport type { EChartsOption, EChartsType, SetOptionOpts } from 'echarts';\n\n/** notMerge: replaces the previous option, so attributes removed from the props disappear from the chart. */\nconst SET_OPTION_OPTS: SetOptionOpts = { notMerge: true };\n\n/** Data ECharts gives to whoever handles an event (e.g. the name of the clicked series). */\nexport type EChartEventParams = {\n /** Name of the element (e.g. legend item or slice) related to the event. */\n name?: string;\n\n /** Name of the series related to the event, in click events on an element of the chart. */\n seriesName?: string;\n\n [attribute: string]: unknown;\n};\n\n/** Functions that handle ECharts events, indexed by the event name (e.g. `click`, `legendselectchanged`). */\nexport type EChartEventHandlers = Record<string, (params: EChartEventParams) => void>;\n\n/** Generic handler signature accepted by `chart.on`/`chart.off`, which does not type the parameters of each event. */\ntype EChartsHandler = (...args: unknown[]) => void;\n\n/** ECharts module, loaded on demand. */\ntype EChartsModule = typeof import('echarts');\n\n/** Geometry of a map (e.g. a GeoJSON with the areas of the cities), in the format accepted by `echarts.registerMap`. */\nexport type EChartMapSource = Parameters<typeof import('echarts').registerMap>[1];\n\n/** Maps used by the chart, indexed by the name the `map` series (or the `geo` component) use in the `map` attribute. */\nexport type EChartMaps = Record<string, EChartMapSource>;\n\n/**\n * How ECharts draws the chart: in `canvas` (default, faster on screen) or in `svg`, which is printed as sharp vector\n * graphics or saved as PDF. Use `svg` in reports.\n */\nexport type EChartRenderer = 'canvas' | 'svg';\n\n/**\n * Print media query. It changes when the browser applies (or removes) the paper layout, whose width differs from the\n * screen. It is more reliable than `beforeprint`, which fires before this layout and would measure the screen.\n */\nconst PRINT_MEDIA_QUERY = 'print';\n\n/**\n * Manages the life cycle of an ECharts instance bound to a DOM element: creates the instance on mount, applies the\n * `option` whenever it changes, resizes the chart when the container changes its size and disposes the instance on\n * unmount.\n *\n * ECharts is loaded on demand (dynamic `import()`), so only the pages that show charts download the library.\n * @param option final option shown in the chart\n * @param onEvents functions that handle the chart events; they are replaced when the object changes\n * @param maps maps registered in ECharts before creating the chart; when they change, they are registered again and\n * the chart is redrawn\n * @param renderer how the chart is drawn; read only when the chart is created\n * @return ref to assign to the element that will hold the chart\n */\nexport function useEChart(\n option: EChartsOption,\n onEvents?: EChartEventHandlers,\n maps?: EChartMaps,\n renderer: EChartRenderer = 'canvas'\n): RefObject<HTMLDivElement | null> {\n const containerRef = useRef<HTMLDivElement>(null);\n const chartRef = useRef<EChartsType | null>(null);\n\n // Keeps the latest option, to apply it when ECharts finishes loading.\n const optionRef = useRef(option);\n\n // Keeps the latest handlers, to bind them when ECharts finishes loading.\n const onEventsRef = useRef(onEvents);\n\n // Handlers currently bound to the chart, so they are unbound before binding the new ones.\n const boundEventsRef = useRef<EChartEventHandlers | undefined>(undefined);\n\n // Keeps the latest maps, to register them when ECharts finishes loading.\n const mapsRef = useRef(maps);\n\n // ECharts module, kept after loading to register the maps that change.\n const echartsRef = useRef<EChartsModule | null>(null);\n\n /* Registers the new maps and redraws the chart already created, which still uses the previous geometry. Before\n ECharts loads, just keeps the maps. It comes before the option effect so that, if both change together, the new\n option already finds the new map. */\n useEffect(() => {\n mapsRef.current = maps;\n if (!echartsRef.current || !chartRef.current) return;\n\n registerMaps(echartsRef.current, maps);\n chartRef.current.setOption(optionRef.current, SET_OPTION_OPTS);\n }, [maps]);\n\n // Applies the new option to the chart already created. Before ECharts loads, just keeps the option for the other effect.\n useEffect(() => {\n optionRef.current = option;\n chartRef.current?.setOption(option, SET_OPTION_OPTS);\n }, [option]);\n\n // Replaces the event handlers of the chart already created. Before ECharts loads, just keeps the handlers.\n useEffect(() => {\n onEventsRef.current = onEvents;\n if (chartRef.current) replaceEvents(chartRef.current, boundEventsRef, onEvents);\n }, [onEvents]);\n\n // Keeps the renderer of the chart creation: changing it would require recreating the chart, which the hook does not do.\n const rendererRef = useRef(renderer);\n\n /* Runs only on mount: loads ECharts, registers the maps, creates the chart in the container with the latest option\n and resizes it when the container changes its size or the page is about to be printed. The maps are registered\n before the first `setOption`, otherwise ECharts does not find the map used by the series. */\n useEffect(() => {\n let unmounted = false;\n let resizeObserver: ResizeObserver | null = null;\n const resize = (): void => chartRef.current?.resize();\n const printMedia = window.matchMedia(PRINT_MEDIA_QUERY);\n printMedia.addEventListener('change', resize);\n\n import('echarts').then(echarts => {\n const container = containerRef.current;\n if (unmounted || !container) return;\n\n echartsRef.current = echarts;\n registerMaps(echarts, mapsRef.current);\n const chart = echarts.init(container, undefined, { renderer: rendererRef.current });\n chart.setOption(optionRef.current, SET_OPTION_OPTS);\n replaceEvents(chart, boundEventsRef, onEventsRef.current);\n chartRef.current = chart;\n\n resizeObserver = new ResizeObserver(() => chart.resize());\n resizeObserver.observe(container);\n });\n\n /* Cleanup, which React calls on unmount: releases the observer and the chart instance. The `unmounted` flag\n prevents the chart from being created if ECharts finishes loading after the component left the screen. */\n return (): void => {\n unmounted = true;\n printMedia.removeEventListener('change', resize);\n resizeObserver?.disconnect();\n chartRef.current?.dispose();\n chartRef.current = null;\n };\n }, []);\n\n return containerRef;\n}\n\n/**\n * Registers the maps in ECharts, so the series can use them by name.\n * @param echarts ECharts module\n * @param maps maps indexed by name; `undefined` registers nothing\n */\nfunction registerMaps(echarts: EChartsModule, maps?: EChartMaps): void {\n Object.entries(maps ?? {}).forEach(([name, map]) => echarts.registerMap(name, map));\n}\n\n/**\n * Unbinds from the chart the handlers bound before and binds the new ones.\n * @param chart chart instance\n * @param boundEventsRef ref with the handlers currently bound; it is updated with the new ones\n * @param newHandlers handlers to bind; `undefined` just unbinds the previous ones\n */\nfunction replaceEvents(\n chart: EChartsType,\n boundEventsRef: RefObject<EChartEventHandlers | undefined>,\n newHandlers?: EChartEventHandlers\n): void {\n if (boundEventsRef.current) unbindEvents(chart, boundEventsRef.current);\n if (newHandlers) bindEvents(chart, newHandlers);\n boundEventsRef.current = newHandlers;\n}\n\n/**\n * Binds each handler to its event in the chart.\n * @param chart chart instance\n * @param onEvents handlers indexed by the event name\n */\nfunction bindEvents(chart: EChartsType, onEvents: EChartEventHandlers): void {\n Object.entries(onEvents).forEach(([event, handler]) => chart.on(event, handler as EChartsHandler));\n}\n\n/**\n * Unbinds from the chart the handlers bound by {@link bindEvents}.\n * @param chart chart instance\n * @param onEvents handlers indexed by the event name\n */\nfunction unbindEvents(chart: EChartsType, onEvents: EChartEventHandlers): void {\n Object.entries(onEvents).forEach(([event, handler]) => chart.off(event, handler as EChartsHandler));\n}\n"],"mappings":";;;;AAKA,IAAM,kBAAiC,EAAE,UAAU,KAAK;;;;;AAsCxD,IAAM,oBAAoB;;;;;;;;;;;;;;AAe1B,SAAgB,UACZ,QACA,UACA,MACA,WAA2B,UACK;CAChC,MAAM,eAAe,OAAuB,IAAI;CAChD,MAAM,WAAW,OAA2B,IAAI;CAGhD,MAAM,YAAY,OAAO,MAAM;CAG/B,MAAM,cAAc,OAAO,QAAQ;CAGnC,MAAM,iBAAiB,OAAwC,KAAA,CAAS;CAGxE,MAAM,UAAU,OAAO,IAAI;CAG3B,MAAM,aAAa,OAA6B,IAAI;CAKpD,gBAAgB;EACZ,QAAQ,UAAU;EAClB,IAAI,CAAC,WAAW,WAAW,CAAC,SAAS,SAAS;EAE9C,aAAa,WAAW,SAAS,IAAI;EACrC,SAAS,QAAQ,UAAU,UAAU,SAAS,eAAe;CACjE,GAAG,CAAC,IAAI,CAAC;CAGT,gBAAgB;EACZ,UAAU,UAAU;EACpB,SAAS,SAAS,UAAU,QAAQ,eAAe;CACvD,GAAG,CAAC,MAAM,CAAC;CAGX,gBAAgB;EACZ,YAAY,UAAU;EACtB,IAAI,SAAS,SAAS,cAAc,SAAS,SAAS,gBAAgB,QAAQ;CAClF,GAAG,CAAC,QAAQ,CAAC;CAGb,MAAM,cAAc,OAAO,QAAQ;CAKnC,gBAAgB;EACZ,IAAI,YAAY;EAChB,IAAI,iBAAwC;EAC5C,MAAM,eAAqB,SAAS,SAAS,OAAO;EACpD,MAAM,aAAa,OAAO,WAAW,iBAAiB;EACtD,WAAW,iBAAiB,UAAU,MAAM;EAE5C,OAAO,UAAU,CAAC,MAAK,YAAW;GAC9B,MAAM,YAAY,aAAa;GAC/B,IAAI,aAAa,CAAC,WAAW;GAE7B,WAAW,UAAU;GACrB,aAAa,SAAS,QAAQ,OAAO;GACrC,MAAM,QAAQ,QAAQ,KAAK,WAAW,KAAA,GAAW,EAAE,UAAU,YAAY,QAAQ,CAAC;GAClF,MAAM,UAAU,UAAU,SAAS,eAAe;GAClD,cAAc,OAAO,gBAAgB,YAAY,OAAO;GACxD,SAAS,UAAU;GAEnB,iBAAiB,IAAI,qBAAqB,MAAM,OAAO,CAAC;GACxD,eAAe,QAAQ,SAAS;EACpC,CAAC;EAID,aAAmB;GACf,YAAY;GACZ,WAAW,oBAAoB,UAAU,MAAM;GAC/C,gBAAgB,WAAW;GAC3B,SAAS,SAAS,QAAQ;GAC1B,SAAS,UAAU;EACvB;CACJ,GAAG,CAAC,CAAC;CAEL,OAAO;AACX;;;;;;AAOA,SAAS,aAAa,SAAwB,MAAyB;CACnE,OAAO,QAAQ,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,SAAS,QAAQ,YAAY,MAAM,GAAG,CAAC;AACtF;;;;;;;AAQA,SAAS,cACL,OACA,gBACA,aACI;CACJ,IAAI,eAAe,SAAS,aAAa,OAAO,eAAe,OAAO;CACtE,IAAI,aAAa,WAAW,OAAO,WAAW;CAC9C,eAAe,UAAU;AAC7B;;;;;;AAOA,SAAS,WAAW,OAAoB,UAAqC;CACzE,OAAO,QAAQ,QAAQ,CAAC,CAAC,SAAS,CAAC,OAAO,aAAa,MAAM,GAAG,OAAO,OAAyB,CAAC;AACrG;;;;;;AAOA,SAAS,aAAa,OAAoB,UAAqC;CAC3E,OAAO,QAAQ,QAAQ,CAAC,CAAC,SAAS,CAAC,OAAO,aAAa,MAAM,IAAI,OAAO,OAAyB,CAAC;AACtG"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ComponentType } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Item of the side menu ({@link Navbar}). An item with `children` is a collapsible group, which does not navigate: only
|
|
4
|
+
* its children have a `link`.
|
|
5
|
+
*/
|
|
6
|
+
export interface NavItem {
|
|
7
|
+
/** Path of the page opened by the item; absent in the groups. */
|
|
8
|
+
link?: string;
|
|
9
|
+
label: string;
|
|
10
|
+
/** Icon of the item (e.g. an icon of `@tabler/icons-react`). */
|
|
11
|
+
icon: ComponentType<{
|
|
12
|
+
stroke?: number;
|
|
13
|
+
}>;
|
|
14
|
+
/** Items of the group, shown below it when the group is open. */
|
|
15
|
+
children?: NavItem[];
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ReactElement, ReactNode } from 'react';
|
|
2
|
+
import { NavItem } from './NavItem';
|
|
3
|
+
type NavbarProps = {
|
|
4
|
+
/** Items of the menu, in the display order. */
|
|
5
|
+
items: NavItem[];
|
|
6
|
+
/** Content fixed at the bottom of the menu (e.g. a link to log out). */
|
|
7
|
+
footer?: ReactNode;
|
|
8
|
+
/** Called when a link is clicked (e.g. to close the menu on mobile devices). */
|
|
9
|
+
linkClickHandler?: () => void;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Tells whether the item, or an item inside it (for a group), opens the current page.
|
|
13
|
+
* @param item item of the menu
|
|
14
|
+
* @param pathname path of the current page
|
|
15
|
+
* @return `true` if the item holds the current page
|
|
16
|
+
*/
|
|
17
|
+
export declare function containsCurrentPage(item: NavItem, pathname: string): boolean;
|
|
18
|
+
/** Side menu of the {@link Layout}: links to the pages and collapsible groups, with the current page highlighted. */
|
|
19
|
+
export declare function Navbar({ items, footer, linkClickHandler }: NavbarProps): ReactElement;
|
|
20
|
+
export default Navbar;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useKitRouter } from "../../../provider/useKit.js";
|
|
3
|
+
import Navbar_module_default from "./Navbar.module.js";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { AppShell, NavLink } from "@mantine/core";
|
|
6
|
+
// src/component/organism/Navbar/Navbar.tsx
|
|
7
|
+
/**
|
|
8
|
+
* Tells whether the item, or an item inside it (for a group), opens the current page.
|
|
9
|
+
* @param item item of the menu
|
|
10
|
+
* @param pathname path of the current page
|
|
11
|
+
* @return `true` if the item holds the current page
|
|
12
|
+
*/
|
|
13
|
+
function containsCurrentPage(item, pathname) {
|
|
14
|
+
return item.link === pathname || (item.children ?? []).some((child) => containsCurrentPage(child, pathname));
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Item of the side menu: a link to a page or, if it has `children`, a collapsible group with its items. The group
|
|
18
|
+
* starts open when it holds the current page, and the item of the current page is highlighted.
|
|
19
|
+
*/
|
|
20
|
+
function MenuItem({ item, linkClickHandler }) {
|
|
21
|
+
const { Link, usePathname } = useKitRouter();
|
|
22
|
+
const pathname = usePathname();
|
|
23
|
+
const icon = /* @__PURE__ */ jsx(item.icon, { stroke: 1.5 });
|
|
24
|
+
if (item.children) return /* @__PURE__ */ jsx(NavLink, {
|
|
25
|
+
component: "button",
|
|
26
|
+
label: item.label,
|
|
27
|
+
leftSection: icon,
|
|
28
|
+
defaultOpened: containsCurrentPage(item, pathname),
|
|
29
|
+
className: Navbar_module_default.link,
|
|
30
|
+
children: item.children.map((child) => /* @__PURE__ */ jsx(MenuItem, {
|
|
31
|
+
item: child,
|
|
32
|
+
linkClickHandler
|
|
33
|
+
}, child.label))
|
|
34
|
+
});
|
|
35
|
+
return /* @__PURE__ */ jsx(NavLink, {
|
|
36
|
+
component: Link,
|
|
37
|
+
href: item.link ?? "#",
|
|
38
|
+
active: item.link === pathname,
|
|
39
|
+
label: item.label,
|
|
40
|
+
leftSection: icon,
|
|
41
|
+
className: Navbar_module_default.link,
|
|
42
|
+
onClick: linkClickHandler
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
/** Side menu of the {@link Layout}: links to the pages and collapsible groups, with the current page highlighted. */
|
|
46
|
+
function Navbar({ items, footer, linkClickHandler }) {
|
|
47
|
+
return /* @__PURE__ */ jsxs(AppShell.Navbar, {
|
|
48
|
+
p: "md",
|
|
49
|
+
className: Navbar_module_default.navbar,
|
|
50
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
51
|
+
className: Navbar_module_default.navbarMain,
|
|
52
|
+
children: items.map((item) => /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(MenuItem, {
|
|
53
|
+
item,
|
|
54
|
+
linkClickHandler
|
|
55
|
+
}) }, item.label))
|
|
56
|
+
}), footer && /* @__PURE__ */ jsx("div", {
|
|
57
|
+
className: Navbar_module_default.footer,
|
|
58
|
+
children: footer
|
|
59
|
+
})]
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
export { Navbar, Navbar as default, containsCurrentPage };
|
|
63
|
+
|
|
64
|
+
//# sourceMappingURL=Navbar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Navbar.js","names":["classes"],"sources":["../../../../src/component/organism/Navbar/Navbar.tsx"],"sourcesContent":["import { ReactElement, ReactNode } from 'react';\n\nimport { AppShell, NavLink } from '@mantine/core';\n\nimport { useKitRouter } from '../../../provider/useKit';\nimport classes from './Navbar.module.css';\nimport { NavItem } from './NavItem';\n\ntype NavbarProps = {\n /** Items of the menu, in the display order. */\n items: NavItem[];\n\n /** Content fixed at the bottom of the menu (e.g. a link to log out). */\n footer?: ReactNode;\n\n /** Called when a link is clicked (e.g. to close the menu on mobile devices). */\n linkClickHandler?: () => void;\n};\n\ntype MenuItemProps = {\n item: NavItem;\n\n /** Called when a link is clicked. */\n linkClickHandler?: () => void;\n};\n\n/**\n * Tells whether the item, or an item inside it (for a group), opens the current page.\n * @param item item of the menu\n * @param pathname path of the current page\n * @return `true` if the item holds the current page\n */\nexport function containsCurrentPage(item: NavItem, pathname: string): boolean {\n return item.link === pathname || (item.children ?? []).some(child => containsCurrentPage(child, pathname));\n}\n\n/**\n * Item of the side menu: a link to a page or, if it has `children`, a collapsible group with its items. The group\n * starts open when it holds the current page, and the item of the current page is highlighted.\n */\nfunction MenuItem({ item, linkClickHandler }: MenuItemProps): ReactElement {\n const { Link, usePathname } = useKitRouter();\n const pathname = usePathname();\n const icon = <item.icon stroke={1.5} />;\n if (item.children) {\n return (\n // A button, and not a link without destination, so the group can be opened with the keyboard.\n <NavLink\n component=\"button\"\n label={item.label}\n leftSection={icon}\n defaultOpened={containsCurrentPage(item, pathname)}\n className={classes.link}\n >\n {item.children.map(child => (\n <MenuItem key={child.label} item={child} linkClickHandler={linkClickHandler} />\n ))}\n </NavLink>\n );\n }\n\n return (\n <NavLink\n component={Link}\n href={item.link ?? '#'}\n active={item.link === pathname}\n label={item.label}\n leftSection={icon}\n className={classes.link}\n onClick={linkClickHandler}\n />\n );\n}\n\n/** Side menu of the {@link Layout}: links to the pages and collapsible groups, with the current page highlighted. */\nexport function Navbar({ items, footer, linkClickHandler }: NavbarProps): ReactElement {\n return (\n <AppShell.Navbar p=\"md\" className={classes.navbar}>\n <div className={classes.navbarMain}>\n {items.map(item => (\n <div key={item.label}>\n <MenuItem item={item} linkClickHandler={linkClickHandler} />\n </div>\n ))}\n </div>\n\n {footer && <div className={classes.footer}>{footer}</div>}\n </AppShell.Navbar>\n );\n}\n\nexport default Navbar;\n"],"mappings":";;;;;;;;;;;;AAgCA,SAAgB,oBAAoB,MAAe,UAA2B;CAC1E,OAAO,KAAK,SAAS,aAAa,KAAK,YAAY,CAAC,EAAA,CAAG,MAAK,UAAS,oBAAoB,OAAO,QAAQ,CAAC;AAC7G;;;;;AAMA,SAAS,SAAS,EAAE,MAAM,oBAAiD;CACvE,MAAM,EAAE,MAAM,gBAAgB,aAAa;CAC3C,MAAM,WAAW,YAAY;CAC7B,MAAM,OAAO,oBAAC,KAAK,MAAN,EAAW,QAAQ,IAAM,CAAA;CACtC,IAAI,KAAK,UACL,OAEI,oBAAC,SAAD;EACI,WAAU;EACV,OAAO,KAAK;EACZ,aAAa;EACb,eAAe,oBAAoB,MAAM,QAAQ;EACjD,WAAWA,sBAAQ;EAElB,UAAA,KAAK,SAAS,KAAI,UACf,oBAAC,UAAD;GAA4B,MAAM;GAAyB;EAAmB,GAA/D,MAAM,KAAyD,CACjF;CACI,CAAA;CAIjB,OACI,oBAAC,SAAD;EACI,WAAW;EACX,MAAM,KAAK,QAAQ;EACnB,QAAQ,KAAK,SAAS;EACtB,OAAO,KAAK;EACZ,aAAa;EACb,WAAWA,sBAAQ;EACnB,SAAS;CACZ,CAAA;AAET;;AAGA,SAAgB,OAAO,EAAE,OAAO,QAAQ,oBAA+C;CACnF,OACI,qBAAC,SAAS,QAAV;EAAiB,GAAE;EAAK,WAAWA,sBAAQ;EAA3C,UAAA,CACI,oBAAC,OAAD;GAAK,WAAWA,sBAAQ;GACnB,UAAA,MAAM,KAAI,SACP,oBAAC,OAAD,EAAA,UACI,oBAAC,UAAD;IAAgB;IAAwB;GAAmB,CAAA,EAC1D,GAFK,KAAK,KAEV,CACR;EACA,CAAA,GAEJ,UAAU,oBAAC,OAAD;GAAK,WAAWA,sBAAQ;GAAS,UAAA;EAAY,CAAA,CAC3C;;AAEzB"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
// src/component/organism/Navbar/Navbar.module.css
|
|
3
|
+
var navbar = "mk-Navbar-module-navbar-0W9zF";
|
|
4
|
+
var navbarMain = "mk-Navbar-module-navbarMain-QxMWi";
|
|
5
|
+
var header = "mk-Navbar-module-header-q16r1";
|
|
6
|
+
var footer = "mk-Navbar-module-footer-48Z0e";
|
|
7
|
+
var link = "mk-Navbar-module-link-eQT-Z";
|
|
8
|
+
var linkIcon = "mk-Navbar-module-linkIcon-5b3By";
|
|
9
|
+
var Navbar_module_default = {
|
|
10
|
+
navbar,
|
|
11
|
+
navbarMain,
|
|
12
|
+
header,
|
|
13
|
+
footer,
|
|
14
|
+
link,
|
|
15
|
+
linkIcon
|
|
16
|
+
};
|
|
17
|
+
export { Navbar_module_default as default, footer, header, link, linkIcon, navbar, navbarMain };
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=Navbar.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Navbar.module.js","names":[],"sources":["../../../../src/component/organism/Navbar/Navbar.module.css"],"sourcesContent":[".navbar {\n padding: var(--mantine-spacing-md);\n display: flex;\n flex-direction: column;\n border-right: rem(1px) solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-4));\n}\n\n.navbarMain {\n flex: 1;\n}\n\n.header {\n padding-bottom: var(--mantine-spacing-md);\n margin-bottom: calc(var(--mantine-spacing-md) * 1.5);\n border-bottom: rem(1px) solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-4));\n}\n\n.footer {\n padding-top: var(--mantine-spacing-md);\n margin-top: var(--mantine-spacing-md);\n border-top: rem(1px) solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-4));\n}\n\n.link {\n border-radius: var(--mantine-radius-md);\n font-weight: 500;\n}\n\n.linkIcon {\n color: light-dark(var(--mantine-color-gray-6), var(--mantine-color-dark-2));\n margin-right: var(--mantine-spacing-sm);\n width: rem(25px);\n height: rem(25px);\n}\n"],"mappings":""}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { PaperProps } from '@mantine/core';
|
|
2
|
+
import { BreadcrumbItem } from '../../molecule/Breadcrumb/Breadcrumb';
|
|
3
|
+
type PageHeaderProps = {
|
|
4
|
+
title: string;
|
|
5
|
+
breadcrumbItems?: BreadcrumbItem[];
|
|
6
|
+
/** Route of the "Add" button. Without it, the page has no "Add" button. */
|
|
7
|
+
addActionRoute?: string;
|
|
8
|
+
} & PaperProps;
|
|
9
|
+
/**
|
|
10
|
+
* Header of a page: the title, the breadcrumb and, in list pages, the "Add" button. With the button, the breadcrumb
|
|
11
|
+
* starts at the home page.
|
|
12
|
+
*/
|
|
13
|
+
declare const PageHeader: (props: PageHeaderProps) => import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export default PageHeader;
|