@ifto/mantine-kit 0.2.1 → 0.4.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/README.md +6 -2
- package/dist/component/atom/DateField/DateField.d.ts +5 -1
- package/dist/component/atom/DateField/DateField.js +15 -3
- package/dist/component/atom/DateField/DateField.js.map +1 -1
- package/dist/component/organism/EChart/chart/BarChart.d.ts +3 -0
- package/dist/component/organism/EChart/chart/BarChart.js +5 -0
- package/dist/component/organism/EChart/chart/BarChart.js.map +1 -1
- package/dist/component/organism/EChart/chart/CartesianChart.d.ts +4 -0
- package/dist/component/organism/EChart/chart/CartesianChart.js +5 -0
- package/dist/component/organism/EChart/chart/CartesianChart.js.map +1 -1
- package/dist/component/organism/EChart/chart/ChartType.d.ts +3 -0
- package/dist/component/organism/EChart/chart/DonutChart.d.ts +4 -0
- package/dist/component/organism/EChart/chart/DonutChart.js +6 -0
- package/dist/component/organism/EChart/chart/DonutChart.js.map +1 -1
- package/dist/component/organism/EChart/chart/LineChart.d.ts +3 -0
- package/dist/component/organism/EChart/chart/LineChart.js +5 -0
- package/dist/component/organism/EChart/chart/LineChart.js.map +1 -1
- package/dist/component/organism/EChart/chart/StackedBarChart.d.ts +3 -0
- package/dist/component/organism/EChart/chart/StackedBarChart.js +5 -0
- package/dist/component/organism/EChart/chart/StackedBarChart.js.map +1 -1
- package/dist/i18n/KitLocale.d.ts +5 -1
- package/dist/i18n/KitLocale.js +6 -2
- package/dist/i18n/KitLocale.js.map +1 -1
- package/dist/i18n/messages/enUS.js +3 -2
- package/dist/i18n/messages/enUS.js.map +1 -1
- package/dist/i18n/messages/ptBR.js +3 -2
- package/dist/i18n/messages/ptBR.js.map +1 -1
- package/dist/i18n/resolveMessages.js +3 -3
- package/dist/i18n/resolveMessages.js.map +1 -1
- package/dist/util/DateUtil.d.ts +24 -7
- package/dist/util/DateUtil.js +82 -16
- package/dist/util/DateUtil.js.map +1 -1
- package/package.json +1 -2
package/README.md
CHANGED
|
@@ -38,7 +38,7 @@ a REST HTTP client.
|
|
|
38
38
|
**1. Install** the library and its required peer dependencies:
|
|
39
39
|
|
|
40
40
|
```bash
|
|
41
|
-
yarn add @ifto/mantine-kit @mantine/core @mantine/hooks @mantine/notifications @tabler/icons-react clsx
|
|
41
|
+
yarn add @ifto/mantine-kit @mantine/core @mantine/hooks @mantine/notifications @tabler/icons-react clsx \
|
|
42
42
|
react react-dom
|
|
43
43
|
```
|
|
44
44
|
|
|
@@ -48,7 +48,7 @@ Install the optional ones only if you use the components that need them:
|
|
|
48
48
|
|---|---|
|
|
49
49
|
| `@mantine/form` | the form templates (`FormPage`, `CreateFormPage`, `EditFormPage`) and `DataForm`, which take a `useForm` form |
|
|
50
50
|
| `@mantine/modals` | the confirmations of `Table` (delete), `ListPage` and `DataForm` |
|
|
51
|
-
| `@mantine/dates` | `DateField` |
|
|
51
|
+
| `@mantine/dates` and `dayjs` (its peer dependency) | `DateField` |
|
|
52
52
|
| `mantine-datatable` | `Table`, `ViewTable`, `ListPage` |
|
|
53
53
|
| `echarts` | `EChart` and the chart types |
|
|
54
54
|
| `exceljs` | Excel export |
|
|
@@ -226,6 +226,10 @@ The chart types in `component/organism/EChart/chart` (`LINE_CHART`, `BAR_CHART`,
|
|
|
226
226
|
build a complete option, with one panel per unit, from generic series:
|
|
227
227
|
`option={LINE_CHART.buildOption(data, { title: 'Revenue', locale: 'en-US' })}`.
|
|
228
228
|
|
|
229
|
+
Each of these types has an `icon`, to show in a chart type selector (e.g. `IconChartBar` for `BAR_CHART`). To use another
|
|
230
|
+
one, create the type with it: `new BarChart(IconChartHistogram)`. The `icon` is optional in the `ChartType` contract, so
|
|
231
|
+
a custom chart type does not need one.
|
|
232
|
+
|
|
229
233
|
### Export to Excel or CSV
|
|
230
234
|
|
|
231
235
|
```tsx
|
|
@@ -3,5 +3,9 @@ import { DateInputProps } from '@mantine/dates';
|
|
|
3
3
|
export interface DateProps extends DateInputProps {
|
|
4
4
|
label: string;
|
|
5
5
|
}
|
|
6
|
-
/**
|
|
6
|
+
/**
|
|
7
|
+
* Clearable date input in the date format of the locale (e.g. `DD/MM/YYYY` in `pt-BR`).
|
|
8
|
+
* A text `value` can be in that format or in the `YYYY-MM-DD` format `onChange` gives, so it can be controlled with
|
|
9
|
+
* what `onChange` gives.
|
|
10
|
+
*/
|
|
7
11
|
export declare function DateField({ label, value, ...rest }: DateProps): ReactElement;
|
|
@@ -1,17 +1,29 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useKitMessages } from "../../../provider/useKit.js";
|
|
3
|
-
import { parseDate } from "../../../util/DateUtil.js";
|
|
3
|
+
import { ISO_DATE_FORMAT, isValidDate, parseDate } from "../../../util/DateUtil.js";
|
|
4
4
|
import { jsx } from "react/jsx-runtime";
|
|
5
5
|
import { DateInput } from "@mantine/dates";
|
|
6
6
|
// src/component/atom/DateField/DateField.tsx
|
|
7
|
-
/**
|
|
7
|
+
/**
|
|
8
|
+
* Reads the value of the field, which is a `YYYY-MM-DD` text when it comes from the `onChange` of `DateInput`.
|
|
9
|
+
* @param format format of the locale, for the texts not in the ISO format
|
|
10
|
+
*/
|
|
11
|
+
function parseFieldValue(value, format) {
|
|
12
|
+
const isoDate = parseDate(value, ISO_DATE_FORMAT);
|
|
13
|
+
return isValidDate(isoDate) ? isoDate : parseDate(value, format);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Clearable date input in the date format of the locale (e.g. `DD/MM/YYYY` in `pt-BR`).
|
|
17
|
+
* A text `value` can be in that format or in the `YYYY-MM-DD` format `onChange` gives, so it can be controlled with
|
|
18
|
+
* what `onChange` gives.
|
|
19
|
+
*/
|
|
8
20
|
function DateField({ label, value, ...rest }) {
|
|
9
21
|
const { dateFormat } = useKitMessages().common;
|
|
10
22
|
return /* @__PURE__ */ jsx(DateInput, {
|
|
11
23
|
label,
|
|
12
24
|
placeholder: dateFormat,
|
|
13
25
|
valueFormat: dateFormat,
|
|
14
|
-
value:
|
|
26
|
+
value: parseFieldValue(value, dateFormat),
|
|
15
27
|
clearable: true,
|
|
16
28
|
...rest
|
|
17
29
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DateField.js","names":[],"sources":["../../../../src/component/atom/DateField/DateField.tsx"],"sourcesContent":["import { ReactElement } from 'react';\nimport { DateInput, DateInputProps } from '@mantine/dates';\n\nimport { useKitMessages } from '../../../provider/useKit';\nimport { parseDate } from '../../../util/DateUtil';\n\nexport interface DateProps extends DateInputProps {\n label: string;\n}\n\n
|
|
1
|
+
{"version":3,"file":"DateField.js","names":[],"sources":["../../../../src/component/atom/DateField/DateField.tsx"],"sourcesContent":["import { ReactElement } from 'react';\nimport { DateInput, DateInputProps } from '@mantine/dates';\n\nimport { useKitMessages } from '../../../provider/useKit';\nimport { DateFieldValue, ISO_DATE_FORMAT, isValidDate, parseDate } from '../../../util/DateUtil';\n\nexport interface DateProps extends DateInputProps {\n label: string;\n}\n\n/**\n * Reads the value of the field, which is a `YYYY-MM-DD` text when it comes from the `onChange` of `DateInput`.\n * @param format format of the locale, for the texts not in the ISO format\n */\nfunction parseFieldValue(value: DateFieldValue, format: string): Date | null {\n const isoDate = parseDate(value, ISO_DATE_FORMAT);\n\n return isValidDate(isoDate) ? isoDate : parseDate(value, format);\n}\n\n/**\n * Clearable date input in the date format of the locale (e.g. `DD/MM/YYYY` in `pt-BR`).\n * A text `value` can be in that format or in the `YYYY-MM-DD` format `onChange` gives, so it can be controlled with\n * what `onChange` gives.\n */\nexport function DateField({ label, value, ...rest }: DateProps): ReactElement {\n const { dateFormat } = useKitMessages().common;\n\n return (\n <DateInput\n label={label}\n placeholder={dateFormat}\n valueFormat={dateFormat}\n value={parseFieldValue(value, dateFormat)}\n clearable\n {...rest}\n />\n );\n}\n"],"mappings":";;;;;;;;;;AAcA,SAAS,gBAAgB,OAAuB,QAA6B;CACzE,MAAM,UAAU,UAAU,OAAO,eAAe;CAEhD,OAAO,YAAY,OAAO,IAAI,UAAU,UAAU,OAAO,MAAM;AACnE;;;;;;AAOA,SAAgB,UAAU,EAAE,OAAO,OAAO,GAAG,QAAiC;CAC1E,MAAM,EAAE,eAAe,eAAe,CAAC,CAAC;CAExC,OACI,oBAAC,WAAD;EACW;EACP,aAAa;EACb,aAAa;EACb,OAAO,gBAAgB,OAAO,UAAU;EACxC,WAAA;EACA,GAAI;CACP,CAAA;AAET"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type Icon } from '@tabler/icons-react';
|
|
1
2
|
import { ChartSeries } from './ChartSeries';
|
|
2
3
|
import { ChartTypeId } from './ChartTypeId';
|
|
3
4
|
import { CartesianChart, CartesianSeries, DataPoint } from './CartesianChart';
|
|
@@ -11,6 +12,8 @@ export declare const NEGATIVE_VALUE_COLOR = "#d9480f";
|
|
|
11
12
|
*/
|
|
12
13
|
export declare class BarChart extends CartesianChart {
|
|
13
14
|
readonly id: ChartTypeId;
|
|
15
|
+
/** @param icon icon that replaces the default one */
|
|
16
|
+
constructor(icon?: Icon);
|
|
14
17
|
protected seriesStyle(): CartesianSeries;
|
|
15
18
|
protected seriesData(serie: ChartSeries): DataPoint[];
|
|
16
19
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { CartesianChart } from "./CartesianChart.js";
|
|
3
|
+
import { IconChartBar } from "@tabler/icons-react";
|
|
3
4
|
// src/component/organism/EChart/chart/BarChart.ts
|
|
4
5
|
/** Color of the columns with a negative value (e.g. a deficit), to set them apart from the positive ones. */
|
|
5
6
|
var NEGATIVE_VALUE_COLOR = "#d9480f";
|
|
@@ -11,6 +12,10 @@ var NEGATIVE_VALUE_COLOR = "#d9480f";
|
|
|
11
12
|
*/
|
|
12
13
|
var BarChart = class extends CartesianChart {
|
|
13
14
|
id = "bar";
|
|
15
|
+
/** @param icon icon that replaces the default one */
|
|
16
|
+
constructor(icon = IconChartBar) {
|
|
17
|
+
super(icon);
|
|
18
|
+
}
|
|
14
19
|
seriesStyle() {
|
|
15
20
|
return { type: "bar" };
|
|
16
21
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BarChart.js","names":[],"sources":["../../../../../src/component/organism/EChart/chart/BarChart.ts"],"sourcesContent":["import { ChartSeries } from './ChartSeries';\nimport { ChartTypeId } from './ChartTypeId';\nimport { CartesianChart, CartesianSeries, DataPoint } from './CartesianChart';\n\n/** Color of the columns with a negative value (e.g. a deficit), to set them apart from the positive ones. */\nexport const NEGATIVE_VALUE_COLOR = '#d9480f';\n\n/**\n * Grouped column chart: compares the series category by category.\n * Suited to flows (e.g. yearly values) and to balances that may be negative (deficit/surplus): the negative columns\n * get the {@link NEGATIVE_VALUE_COLOR}, without changing the color of the series in the legend.\n * @author Manoel Campos\n */\nexport class BarChart extends CartesianChart {\n readonly id: ChartTypeId = 'bar';\n\n protected seriesStyle(): CartesianSeries {\n return { type: 'bar' };\n }\n\n protected seriesData(serie: ChartSeries): DataPoint[] {\n return highlightNegativeValues(serie.values);\n }\n}\n\n/**\n * Gives the {@link NEGATIVE_VALUE_COLOR} only to the negative values. The others keep the color of the series.\n * @param values values of a series\n * @return the values in the `series[i].data` format, with their own style in the negative ones\n */\nexport function highlightNegativeValues(values: (number | null)[]): DataPoint[] {\n return values.map(value =>\n value !== null && value < 0 ? { value, itemStyle: { color: NEGATIVE_VALUE_COLOR } } : value\n );\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"BarChart.js","names":[],"sources":["../../../../../src/component/organism/EChart/chart/BarChart.ts"],"sourcesContent":["import { IconChartBar, type Icon } from '@tabler/icons-react';\n\nimport { ChartSeries } from './ChartSeries';\nimport { ChartTypeId } from './ChartTypeId';\nimport { CartesianChart, CartesianSeries, DataPoint } from './CartesianChart';\n\n/** Color of the columns with a negative value (e.g. a deficit), to set them apart from the positive ones. */\nexport const NEGATIVE_VALUE_COLOR = '#d9480f';\n\n/**\n * Grouped column chart: compares the series category by category.\n * Suited to flows (e.g. yearly values) and to balances that may be negative (deficit/surplus): the negative columns\n * get the {@link NEGATIVE_VALUE_COLOR}, without changing the color of the series in the legend.\n * @author Manoel Campos\n */\nexport class BarChart extends CartesianChart {\n readonly id: ChartTypeId = 'bar';\n\n /** @param icon icon that replaces the default one */\n constructor(icon: Icon = IconChartBar) {\n super(icon);\n }\n\n protected seriesStyle(): CartesianSeries {\n return { type: 'bar' };\n }\n\n protected seriesData(serie: ChartSeries): DataPoint[] {\n return highlightNegativeValues(serie.values);\n }\n}\n\n/**\n * Gives the {@link NEGATIVE_VALUE_COLOR} only to the negative values. The others keep the color of the series.\n * @param values values of a series\n * @return the values in the `series[i].data` format, with their own style in the negative ones\n */\nexport function highlightNegativeValues(values: (number | null)[]): DataPoint[] {\n return values.map(value =>\n value !== null && value < 0 ? { value, itemStyle: { color: NEGATIVE_VALUE_COLOR } } : value\n );\n}\n"],"mappings":";;;;;AAOA,IAAa,uBAAuB;;;;;;;AAQpC,IAAa,WAAb,cAA8B,eAAe;CACzC,KAA2B;;CAG3B,YAAY,OAAa,cAAc;EACnC,MAAM,IAAI;CACd;CAEA,cAAyC;EACrC,OAAO,EAAE,MAAM,MAAM;CACzB;CAEA,WAAqB,OAAiC;EAClD,OAAO,wBAAwB,MAAM,MAAM;CAC/C;AACJ;;;;;;AAOA,SAAgB,wBAAwB,QAAwC;CAC5E,OAAO,OAAO,KAAI,UACd,UAAU,QAAQ,QAAQ,IAAI;EAAE;EAAO,WAAW,EAAE,OAAO,qBAAqB;CAAE,IAAI,KAC1F;AACJ"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Icon } from '@tabler/icons-react';
|
|
1
2
|
import type { BarSeriesOption, EChartsOption, LineSeriesOption } from 'echarts';
|
|
2
3
|
import { ChartData, ChartSeries } from './ChartSeries';
|
|
3
4
|
import { ChartContext, ChartType } from './ChartType';
|
|
@@ -17,8 +18,11 @@ export type DataPoint = number | null | {
|
|
|
17
18
|
* @author Manoel Campos
|
|
18
19
|
*/
|
|
19
20
|
export declare abstract class CartesianChart implements ChartType {
|
|
21
|
+
readonly icon?: Icon | undefined;
|
|
20
22
|
abstract readonly id: ChartTypeId;
|
|
21
23
|
readonly singleCategory = false;
|
|
24
|
+
/** @param icon icon of the type (see {@link ChartType#icon}) */
|
|
25
|
+
constructor(icon?: Icon | undefined);
|
|
22
26
|
/** Types with axes work for any set of series, except the ones that restrict it (see the subclasses). */
|
|
23
27
|
isAvailable(series: ChartSeries[]): boolean;
|
|
24
28
|
buildOption(data: ChartData, context: ChartContext): EChartsOption;
|
|
@@ -9,7 +9,12 @@ import { buildChartHeader, legendExtraHeight, tooltipFormatter } from "./ChartHe
|
|
|
9
9
|
* @author Manoel Campos
|
|
10
10
|
*/
|
|
11
11
|
var CartesianChart = class {
|
|
12
|
+
icon;
|
|
12
13
|
singleCategory = false;
|
|
14
|
+
/** @param icon icon of the type (see {@link ChartType#icon}) */
|
|
15
|
+
constructor(icon) {
|
|
16
|
+
this.icon = icon;
|
|
17
|
+
}
|
|
13
18
|
/** Types with axes work for any set of series, except the ones that restrict it (see the subclasses). */
|
|
14
19
|
isAvailable(series) {
|
|
15
20
|
return series.length > 0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CartesianChart.js","names":[],"sources":["../../../../../src/component/organism/EChart/chart/CartesianChart.ts"],"sourcesContent":["import type { BarSeriesOption, EChartsOption, LineSeriesOption } from 'echarts';\n\nimport { ChartData, ChartSeries } from './ChartSeries';\nimport { ChartContext, ChartType } from './ChartType';\nimport { ChartTypeId } from './ChartTypeId';\nimport { chartLocale, chartMessages } from './ChartTexts';\nimport { buildPanelAxes, groupByUnit, panelsHeight } from './UnitPanels';\nimport { buildChartHeader, legendExtraHeight, tooltipFormatter } from './ChartHeader';\n\n/** Column or line series, the two formats used in the charts with axes (cartesian). */\nexport type CartesianSeries = BarSeriesOption | LineSeriesOption;\n\n/** Value of a category in a series, in the format accepted by `series[i].data` (with or without its own style). */\nexport type DataPoint = number | null | { value: number; itemStyle: { color: string } };\n\n/**\n * Base of the chart types with an X axis of categories (line, columns, stacked columns).\n * It builds the panels per unit, the header and the tooltip, leaving to each type just the style of each series.\n * @author Manoel Campos\n */\nexport abstract class CartesianChart implements ChartType {\n abstract readonly id: ChartTypeId;\n readonly singleCategory = false;\n\n /** Types with axes work for any set of series, except the ones that restrict it (see the subclasses). */\n isAvailable(series: ChartSeries[]): boolean {\n return series.length > 0;\n }\n\n buildOption(data: ChartData, context: ChartContext): EChartsOption {\n const panels = groupByUnit(data.series);\n const series = panels.flatMap((panel, index) =>\n panel.series.map(serie => this.buildSeries(serie, data.series, index))\n );\n const names = data.series.map(serie => serie.name);\n const extraTop = legendExtraHeight(names, context.width);\n\n return {\n ...buildChartHeader(context.title, names, chartMessages(context)),\n tooltip: { trigger: 'axis' },\n ...buildPanelAxes(panels, data.categories, extraTop, chartLocale(context)),\n series\n };\n }\n\n height(data: ChartData, context: ChartContext): number {\n const extraTop = legendExtraHeight(\n data.series.map(serie => serie.name),\n context.width\n );\n return panelsHeight(groupByUnit(data.series).length, data.categories.length, extraTop);\n }\n\n /**\n * Defines how a series is drawn (type, stacking etc.).\n * @param serie series to draw\n * @param all all series of the chart, for types that depend on the whole set (e.g. stacking)\n * @return the style of the series in the ECharts format, without name, data and axes (filled by the base)\n */\n protected abstract seriesStyle(serie: ChartSeries, all: ChartSeries[]): CartesianSeries;\n\n /**\n * Values of the series in the `series[i].data` format. By default, the values themselves; subclasses may give\n * their own style to some values (e.g. negative values).\n * @param serie series of the chart\n * @return one value per category\n */\n protected seriesData(serie: ChartSeries): DataPoint[] {\n return serie.values;\n }\n\n /**\n * Creates the complete ECharts series: style of the type, name, values, axes of the panel and tooltip format.\n * @param serie series of the chart\n * @param all all series of the chart\n * @param panelIndex index of the panel (and of the axes) of the unit of the series\n * @return the series in the ECharts format\n */\n private buildSeries(serie: ChartSeries, all: ChartSeries[], panelIndex: number): CartesianSeries {\n return {\n ...this.seriesStyle(serie, all),\n id: serie.id,\n name: serie.name,\n data: this.seriesData(serie),\n xAxisIndex: panelIndex,\n yAxisIndex: panelIndex,\n tooltip: { valueFormatter: tooltipFormatter(serie.unit) }\n } as CartesianSeries;\n }\n}\n"],"mappings":";;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"CartesianChart.js","names":[],"sources":["../../../../../src/component/organism/EChart/chart/CartesianChart.ts"],"sourcesContent":["import type { Icon } from '@tabler/icons-react';\nimport type { BarSeriesOption, EChartsOption, LineSeriesOption } from 'echarts';\n\nimport { ChartData, ChartSeries } from './ChartSeries';\nimport { ChartContext, ChartType } from './ChartType';\nimport { ChartTypeId } from './ChartTypeId';\nimport { chartLocale, chartMessages } from './ChartTexts';\nimport { buildPanelAxes, groupByUnit, panelsHeight } from './UnitPanels';\nimport { buildChartHeader, legendExtraHeight, tooltipFormatter } from './ChartHeader';\n\n/** Column or line series, the two formats used in the charts with axes (cartesian). */\nexport type CartesianSeries = BarSeriesOption | LineSeriesOption;\n\n/** Value of a category in a series, in the format accepted by `series[i].data` (with or without its own style). */\nexport type DataPoint = number | null | { value: number; itemStyle: { color: string } };\n\n/**\n * Base of the chart types with an X axis of categories (line, columns, stacked columns).\n * It builds the panels per unit, the header and the tooltip, leaving to each type just the style of each series.\n * @author Manoel Campos\n */\nexport abstract class CartesianChart implements ChartType {\n abstract readonly id: ChartTypeId;\n readonly singleCategory = false;\n\n /** @param icon icon of the type (see {@link ChartType#icon}) */\n constructor(readonly icon?: Icon) {}\n\n /** Types with axes work for any set of series, except the ones that restrict it (see the subclasses). */\n isAvailable(series: ChartSeries[]): boolean {\n return series.length > 0;\n }\n\n buildOption(data: ChartData, context: ChartContext): EChartsOption {\n const panels = groupByUnit(data.series);\n const series = panels.flatMap((panel, index) =>\n panel.series.map(serie => this.buildSeries(serie, data.series, index))\n );\n const names = data.series.map(serie => serie.name);\n const extraTop = legendExtraHeight(names, context.width);\n\n return {\n ...buildChartHeader(context.title, names, chartMessages(context)),\n tooltip: { trigger: 'axis' },\n ...buildPanelAxes(panels, data.categories, extraTop, chartLocale(context)),\n series\n };\n }\n\n height(data: ChartData, context: ChartContext): number {\n const extraTop = legendExtraHeight(\n data.series.map(serie => serie.name),\n context.width\n );\n return panelsHeight(groupByUnit(data.series).length, data.categories.length, extraTop);\n }\n\n /**\n * Defines how a series is drawn (type, stacking etc.).\n * @param serie series to draw\n * @param all all series of the chart, for types that depend on the whole set (e.g. stacking)\n * @return the style of the series in the ECharts format, without name, data and axes (filled by the base)\n */\n protected abstract seriesStyle(serie: ChartSeries, all: ChartSeries[]): CartesianSeries;\n\n /**\n * Values of the series in the `series[i].data` format. By default, the values themselves; subclasses may give\n * their own style to some values (e.g. negative values).\n * @param serie series of the chart\n * @return one value per category\n */\n protected seriesData(serie: ChartSeries): DataPoint[] {\n return serie.values;\n }\n\n /**\n * Creates the complete ECharts series: style of the type, name, values, axes of the panel and tooltip format.\n * @param serie series of the chart\n * @param all all series of the chart\n * @param panelIndex index of the panel (and of the axes) of the unit of the series\n * @return the series in the ECharts format\n */\n private buildSeries(serie: ChartSeries, all: ChartSeries[], panelIndex: number): CartesianSeries {\n return {\n ...this.seriesStyle(serie, all),\n id: serie.id,\n name: serie.name,\n data: this.seriesData(serie),\n xAxisIndex: panelIndex,\n yAxisIndex: panelIndex,\n tooltip: { valueFormatter: tooltipFormatter(serie.unit) }\n } as CartesianSeries;\n }\n}\n"],"mappings":";;;;;;;;;;AAqBA,IAAsB,iBAAtB,MAA0D;CAKjC;CAHrB,iBAA0B;;CAG1B,YAAY,MAAsB;EAAb,KAAA,OAAA;CAAc;;CAGnC,YAAY,QAAgC;EACxC,OAAO,OAAO,SAAS;CAC3B;CAEA,YAAY,MAAiB,SAAsC;EAC/D,MAAM,SAAS,YAAY,KAAK,MAAM;EACtC,MAAM,SAAS,OAAO,SAAS,OAAO,UAClC,MAAM,OAAO,KAAI,UAAS,KAAK,YAAY,OAAO,KAAK,QAAQ,KAAK,CAAC,CACzE;EACA,MAAM,QAAQ,KAAK,OAAO,KAAI,UAAS,MAAM,IAAI;EACjD,MAAM,WAAW,kBAAkB,OAAO,QAAQ,KAAK;EAEvD,OAAO;GACH,GAAG,iBAAiB,QAAQ,OAAO,OAAO,cAAc,OAAO,CAAC;GAChE,SAAS,EAAE,SAAS,OAAO;GAC3B,GAAG,eAAe,QAAQ,KAAK,YAAY,UAAU,YAAY,OAAO,CAAC;GACzE;EACJ;CACJ;CAEA,OAAO,MAAiB,SAA+B;EACnD,MAAM,WAAW,kBACb,KAAK,OAAO,KAAI,UAAS,MAAM,IAAI,GACnC,QAAQ,KACZ;EACA,OAAO,aAAa,YAAY,KAAK,MAAM,CAAC,CAAC,QAAQ,KAAK,WAAW,QAAQ,QAAQ;CACzF;;;;;;;CAgBA,WAAqB,OAAiC;EAClD,OAAO,MAAM;CACjB;;;;;;;;CASA,YAAoB,OAAoB,KAAoB,YAAqC;EAC7F,OAAO;GACH,GAAG,KAAK,YAAY,OAAO,GAAG;GAC9B,IAAI,MAAM;GACV,MAAM,MAAM;GACZ,MAAM,KAAK,WAAW,KAAK;GAC3B,YAAY;GACZ,YAAY;GACZ,SAAS,EAAE,gBAAgB,iBAAiB,MAAM,IAAI,EAAE;EAC5D;CACJ;AACJ"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Icon } from '@tabler/icons-react';
|
|
1
2
|
import type { EChartsOption } from 'echarts';
|
|
2
3
|
import { KitLocale } from '../../../../i18n/KitLocale';
|
|
3
4
|
import { ChartMessages } from '../../../../i18n/KitMessages';
|
|
@@ -25,6 +26,8 @@ export type ChartContext = {
|
|
|
25
26
|
};
|
|
26
27
|
export interface ChartType {
|
|
27
28
|
readonly id: ChartTypeId;
|
|
29
|
+
/** Icon that represents the type, such as in a chart type selector; absent if the type has none. */
|
|
30
|
+
readonly icon?: Icon;
|
|
28
31
|
/** Whether the type shows a single category (so the screen should show a category selector, such as the year). */
|
|
29
32
|
readonly singleCategory: boolean;
|
|
30
33
|
/**
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type Icon } from '@tabler/icons-react';
|
|
1
2
|
import type { EChartsOption } from 'echarts';
|
|
2
3
|
import { ChartData, ChartSeries } from './ChartSeries';
|
|
3
4
|
import { ChartContext, ChartType } from './ChartType';
|
|
@@ -16,8 +17,11 @@ export declare const DONUT_HEIGHT = 520;
|
|
|
16
17
|
* @author Manoel Campos
|
|
17
18
|
*/
|
|
18
19
|
export declare class DonutChart implements ChartType {
|
|
20
|
+
readonly icon: Icon;
|
|
19
21
|
readonly id: ChartTypeId;
|
|
20
22
|
readonly singleCategory = true;
|
|
23
|
+
/** @param icon icon that replaces the default one */
|
|
24
|
+
constructor(icon?: Icon);
|
|
21
25
|
isAvailable(series: ChartSeries[]): boolean;
|
|
22
26
|
buildOption(data: ChartData, context: ChartContext): EChartsOption;
|
|
23
27
|
height(data: ChartData, context: ChartContext): number;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { groupByStack } from "./ChartSeries.js";
|
|
3
3
|
import { chartMessages } from "./ChartTexts.js";
|
|
4
4
|
import { buildChartHeader, legendExtraHeight, tooltipFormatter } from "./ChartHeader.js";
|
|
5
|
+
import { IconChartDonut } from "@tabler/icons-react";
|
|
5
6
|
// src/component/organism/EChart/chart/DonutChart.ts
|
|
6
7
|
/**
|
|
7
8
|
* Height of the donut chart with the legend in one row (px). It does not depend on the number of categories; it only
|
|
@@ -21,8 +22,13 @@ var DONUT_CENTER = ["50%", "58%"];
|
|
|
21
22
|
* @author Manoel Campos
|
|
22
23
|
*/
|
|
23
24
|
var DonutChart = class {
|
|
25
|
+
icon;
|
|
24
26
|
id = "donut";
|
|
25
27
|
singleCategory = true;
|
|
28
|
+
/** @param icon icon that replaces the default one */
|
|
29
|
+
constructor(icon = IconChartDonut) {
|
|
30
|
+
this.icon = icon;
|
|
31
|
+
}
|
|
26
32
|
isAvailable(series) {
|
|
27
33
|
const stacks = [...groupByStack(series).entries()];
|
|
28
34
|
if (stacks.length !== 1) return false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DonutChart.js","names":[],"sources":["../../../../../src/component/organism/EChart/chart/DonutChart.ts"],"sourcesContent":["import type { EChartsOption } from 'echarts';\n\nimport { ChartData, ChartSeries, groupByStack } from './ChartSeries';\nimport { ChartContext, ChartType } from './ChartType';\nimport { ChartTypeId } from './ChartTypeId';\nimport { chartMessages } from './ChartTexts';\nimport { buildChartHeader, legendExtraHeight, tooltipFormatter } from './ChartHeader';\n\n/**\n * Height of the donut chart with the legend in one row (px). It does not depend on the number of categories; it only\n * grows when the legend wraps in more rows.\n */\nexport const DONUT_HEIGHT = 520;\n\n/** Inner and outer radius of the donut, relative to the area of the donut ({@link DONUT_HEIGHT} high). */\nconst DONUT_RADIUS = ['40%', '68%'];\n\n/** Center of the donut: moved down so it is not under the title. */\nconst DONUT_CENTER = ['50%', '58%'];\n\n/**\n * Donut chart: shows how the total of a stack ({@link ChartSeries#stack}) splits among its series in a single\n * category (e.g. \"how the revenue splits by category in 2040\").\n * It is available only when there is exactly one stack, none of its series has a negative value (negative slices make\n * no sense) and all series of the chart are in the stack or are its total ({@link ChartSeries#totalOf}).\n * So choosing the donut never stops showing, without warning, a series the user selected.\n * @author Manoel Campos\n */\nexport class DonutChart implements ChartType {\n readonly id: ChartTypeId = 'donut';\n readonly singleCategory = true;\n\n isAvailable(series: ChartSeries[]): boolean {\n const stacks = [...groupByStack(series).entries()];\n if (stacks.length !== 1) return false;\n\n const [stack, slicesSeries] = stacks[0];\n const belongsToStack = (serie: ChartSeries) => serie.stack === stack || serie.totalOf === stack;\n return series.every(belongsToStack) && slicesSeries.every(hasNoNegativeValues);\n }\n\n buildOption(data: ChartData, context: ChartContext): EChartsOption {\n const messages = chartMessages(context);\n const category = shownCategory(data.categories, context.category);\n const slices = buildSlices(data, context);\n const unit = stackSeries(data)[0]?.unit;\n const total = slices.reduce((sum, slice) => sum + slice.value, 0);\n const header = buildChartHeader(\n `${context.title} - ${category}`,\n slices.map(slice => slice.name),\n messages\n );\n\n return {\n ...header,\n title: { ...header.title, subtext: unit && messages.total(unit.format(total)) },\n // The legend goes to the bottom, so it is not under the subtitle with the total.\n legend: { ...header.legend, top: undefined, bottom: 0 },\n tooltip: { trigger: 'item', valueFormatter: unit && tooltipFormatter(unit) },\n series: [\n {\n type: 'pie',\n // The area of the donut is fixed at the top; the extra legend rows stay below it.\n top: 0,\n height: DONUT_HEIGHT,\n radius: DONUT_RADIUS,\n center: DONUT_CENTER,\n data: slices,\n label: { formatter: '{b}: {d}%' }\n }\n ]\n } as EChartsOption;\n }\n\n height(data: ChartData, context: ChartContext): number {\n return (\n DONUT_HEIGHT +\n legendExtraHeight(\n buildSlices(data, context).map(slice => slice.name),\n context.width\n )\n );\n }\n}\n\n/** Slice of the donut: the value of a series of the stack in the category shown. */\ntype Slice = { name: string; value: number };\n\n/**\n * Returns the series of the only stack of the chart, which become the slices of the donut.\n * @param data series and categories of the chart\n * @return the series of the stack (empty if there is no stack)\n */\nfunction stackSeries(data: ChartData): ChartSeries[] {\n return [...groupByStack(data.series).values()][0] ?? [];\n}\n\n/**\n * Builds the slices of the donut in the category shown, without the series that have no value in it.\n * @param data series and categories of the chart\n * @param context category chosen on the screen\n * @return a slice per series of the stack with a value in the category\n */\nfunction buildSlices(data: ChartData, context: ChartContext): Slice[] {\n const categoryIndex = data.categories.indexOf(shownCategory(data.categories, context.category));\n return stackSeries(data)\n .map(serie => ({ name: serie.name, value: serie.values[categoryIndex] }))\n .filter((slice): slice is Slice => slice.value !== null);\n}\n\n/**\n * Checks whether a series has no negative values, which make no sense as slices.\n * @param serie series of a stack\n * @return true if the series has no negative value (categories without a value are ignored)\n */\nfunction hasNoNegativeValues(serie: ChartSeries): boolean {\n return serie.values.every(value => value === null || value >= 0);\n}\n\n/**\n * Returns the category a single-category chart should show: the chosen one, if it is in the chart; otherwise, the last.\n * @template C type of the categories (e.g. the years, as numbers)\n * @param categories categories of the chart\n * @param chosen category chosen on the screen; absent if none was chosen\n * @return the category to show\n */\nexport function shownCategory<C extends string | number>(categories: C[], chosen?: C): C {\n return chosen !== undefined && categories.includes(chosen) ? chosen : categories[categories.length - 1];\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"DonutChart.js","names":[],"sources":["../../../../../src/component/organism/EChart/chart/DonutChart.ts"],"sourcesContent":["import { IconChartDonut, type Icon } from '@tabler/icons-react';\nimport type { EChartsOption } from 'echarts';\n\nimport { ChartData, ChartSeries, groupByStack } from './ChartSeries';\nimport { ChartContext, ChartType } from './ChartType';\nimport { ChartTypeId } from './ChartTypeId';\nimport { chartMessages } from './ChartTexts';\nimport { buildChartHeader, legendExtraHeight, tooltipFormatter } from './ChartHeader';\n\n/**\n * Height of the donut chart with the legend in one row (px). It does not depend on the number of categories; it only\n * grows when the legend wraps in more rows.\n */\nexport const DONUT_HEIGHT = 520;\n\n/** Inner and outer radius of the donut, relative to the area of the donut ({@link DONUT_HEIGHT} high). */\nconst DONUT_RADIUS = ['40%', '68%'];\n\n/** Center of the donut: moved down so it is not under the title. */\nconst DONUT_CENTER = ['50%', '58%'];\n\n/**\n * Donut chart: shows how the total of a stack ({@link ChartSeries#stack}) splits among its series in a single\n * category (e.g. \"how the revenue splits by category in 2040\").\n * It is available only when there is exactly one stack, none of its series has a negative value (negative slices make\n * no sense) and all series of the chart are in the stack or are its total ({@link ChartSeries#totalOf}).\n * So choosing the donut never stops showing, without warning, a series the user selected.\n * @author Manoel Campos\n */\nexport class DonutChart implements ChartType {\n readonly id: ChartTypeId = 'donut';\n readonly singleCategory = true;\n\n /** @param icon icon that replaces the default one */\n constructor(readonly icon: Icon = IconChartDonut) {}\n\n isAvailable(series: ChartSeries[]): boolean {\n const stacks = [...groupByStack(series).entries()];\n if (stacks.length !== 1) return false;\n\n const [stack, slicesSeries] = stacks[0];\n const belongsToStack = (serie: ChartSeries) => serie.stack === stack || serie.totalOf === stack;\n return series.every(belongsToStack) && slicesSeries.every(hasNoNegativeValues);\n }\n\n buildOption(data: ChartData, context: ChartContext): EChartsOption {\n const messages = chartMessages(context);\n const category = shownCategory(data.categories, context.category);\n const slices = buildSlices(data, context);\n const unit = stackSeries(data)[0]?.unit;\n const total = slices.reduce((sum, slice) => sum + slice.value, 0);\n const header = buildChartHeader(\n `${context.title} - ${category}`,\n slices.map(slice => slice.name),\n messages\n );\n\n return {\n ...header,\n title: { ...header.title, subtext: unit && messages.total(unit.format(total)) },\n // The legend goes to the bottom, so it is not under the subtitle with the total.\n legend: { ...header.legend, top: undefined, bottom: 0 },\n tooltip: { trigger: 'item', valueFormatter: unit && tooltipFormatter(unit) },\n series: [\n {\n type: 'pie',\n // The area of the donut is fixed at the top; the extra legend rows stay below it.\n top: 0,\n height: DONUT_HEIGHT,\n radius: DONUT_RADIUS,\n center: DONUT_CENTER,\n data: slices,\n label: { formatter: '{b}: {d}%' }\n }\n ]\n } as EChartsOption;\n }\n\n height(data: ChartData, context: ChartContext): number {\n return (\n DONUT_HEIGHT +\n legendExtraHeight(\n buildSlices(data, context).map(slice => slice.name),\n context.width\n )\n );\n }\n}\n\n/** Slice of the donut: the value of a series of the stack in the category shown. */\ntype Slice = { name: string; value: number };\n\n/**\n * Returns the series of the only stack of the chart, which become the slices of the donut.\n * @param data series and categories of the chart\n * @return the series of the stack (empty if there is no stack)\n */\nfunction stackSeries(data: ChartData): ChartSeries[] {\n return [...groupByStack(data.series).values()][0] ?? [];\n}\n\n/**\n * Builds the slices of the donut in the category shown, without the series that have no value in it.\n * @param data series and categories of the chart\n * @param context category chosen on the screen\n * @return a slice per series of the stack with a value in the category\n */\nfunction buildSlices(data: ChartData, context: ChartContext): Slice[] {\n const categoryIndex = data.categories.indexOf(shownCategory(data.categories, context.category));\n return stackSeries(data)\n .map(serie => ({ name: serie.name, value: serie.values[categoryIndex] }))\n .filter((slice): slice is Slice => slice.value !== null);\n}\n\n/**\n * Checks whether a series has no negative values, which make no sense as slices.\n * @param serie series of a stack\n * @return true if the series has no negative value (categories without a value are ignored)\n */\nfunction hasNoNegativeValues(serie: ChartSeries): boolean {\n return serie.values.every(value => value === null || value >= 0);\n}\n\n/**\n * Returns the category a single-category chart should show: the chosen one, if it is in the chart; otherwise, the last.\n * @template C type of the categories (e.g. the years, as numbers)\n * @param categories categories of the chart\n * @param chosen category chosen on the screen; absent if none was chosen\n * @return the category to show\n */\nexport function shownCategory<C extends string | number>(categories: C[], chosen?: C): C {\n return chosen !== undefined && categories.includes(chosen) ? chosen : categories[categories.length - 1];\n}\n"],"mappings":";;;;;;;;;;AAaA,IAAa,eAAe;;AAG5B,IAAM,eAAe,CAAC,OAAO,KAAK;;AAGlC,IAAM,eAAe,CAAC,OAAO,KAAK;;;;;;;;;AAUlC,IAAa,aAAb,MAA6C;CAKpB;CAJrB,KAA2B;CAC3B,iBAA0B;;CAG1B,YAAY,OAAsB,gBAAgB;EAA7B,KAAA,OAAA;CAA8B;CAEnD,YAAY,QAAgC;EACxC,MAAM,SAAS,CAAC,GAAG,aAAa,MAAM,CAAC,CAAC,QAAQ,CAAC;EACjD,IAAI,OAAO,WAAW,GAAG,OAAO;EAEhC,MAAM,CAAC,OAAO,gBAAgB,OAAO;EACrC,MAAM,kBAAkB,UAAuB,MAAM,UAAU,SAAS,MAAM,YAAY;EAC1F,OAAO,OAAO,MAAM,cAAc,KAAK,aAAa,MAAM,mBAAmB;CACjF;CAEA,YAAY,MAAiB,SAAsC;EAC/D,MAAM,WAAW,cAAc,OAAO;EACtC,MAAM,WAAW,cAAc,KAAK,YAAY,QAAQ,QAAQ;EAChE,MAAM,SAAS,YAAY,MAAM,OAAO;EACxC,MAAM,OAAO,YAAY,IAAI,CAAC,CAAC,EAAE,EAAE;EACnC,MAAM,QAAQ,OAAO,QAAQ,KAAK,UAAU,MAAM,MAAM,OAAO,CAAC;EAChE,MAAM,SAAS,iBACX,GAAG,QAAQ,MAAM,KAAK,YACtB,OAAO,KAAI,UAAS,MAAM,IAAI,GAC9B,QACJ;EAEA,OAAO;GACH,GAAG;GACH,OAAO;IAAE,GAAG,OAAO;IAAO,SAAS,QAAQ,SAAS,MAAM,KAAK,OAAO,KAAK,CAAC;GAAE;GAE9E,QAAQ;IAAE,GAAG,OAAO;IAAQ,KAAK,KAAA;IAAW,QAAQ;GAAE;GACtD,SAAS;IAAE,SAAS;IAAQ,gBAAgB,QAAQ,iBAAiB,IAAI;GAAE;GAC3E,QAAQ,CACJ;IACI,MAAM;IAEN,KAAK;IACL,QAAA;IACA,QAAQ;IACR,QAAQ;IACR,MAAM;IACN,OAAO,EAAE,WAAW,YAAY;GACpC,CACJ;EACJ;CACJ;CAEA,OAAO,MAAiB,SAA+B;EACnD,OAAA,MAEI,kBACI,YAAY,MAAM,OAAO,CAAC,CAAC,KAAI,UAAS,MAAM,IAAI,GAClD,QAAQ,KACZ;CAER;AACJ;;;;;;AAUA,SAAS,YAAY,MAAgC;CACjD,OAAO,CAAC,GAAG,aAAa,KAAK,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;AAC1D;;;;;;;AAQA,SAAS,YAAY,MAAiB,SAAgC;CAClE,MAAM,gBAAgB,KAAK,WAAW,QAAQ,cAAc,KAAK,YAAY,QAAQ,QAAQ,CAAC;CAC9F,OAAO,YAAY,IAAI,CAAC,CACnB,KAAI,WAAU;EAAE,MAAM,MAAM;EAAM,OAAO,MAAM,OAAO;CAAe,EAAE,CAAC,CACxE,QAAQ,UAA0B,MAAM,UAAU,IAAI;AAC/D;;;;;;AAOA,SAAS,oBAAoB,OAA6B;CACtD,OAAO,MAAM,OAAO,OAAM,UAAS,UAAU,QAAQ,SAAS,CAAC;AACnE;;;;;;;;AASA,SAAgB,cAAyC,YAAiB,QAAe;CACrF,OAAO,WAAW,KAAA,KAAa,WAAW,SAAS,MAAM,IAAI,SAAS,WAAW,WAAW,SAAS;AACzG"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type Icon } from '@tabler/icons-react';
|
|
1
2
|
import { ChartTypeId } from './ChartTypeId';
|
|
2
3
|
import { CartesianChart, CartesianSeries } from './CartesianChart';
|
|
3
4
|
/**
|
|
@@ -7,5 +8,7 @@ import { CartesianChart, CartesianSeries } from './CartesianChart';
|
|
|
7
8
|
*/
|
|
8
9
|
export declare class LineChart extends CartesianChart {
|
|
9
10
|
readonly id: ChartTypeId;
|
|
11
|
+
/** @param icon icon that replaces the default one */
|
|
12
|
+
constructor(icon?: Icon);
|
|
10
13
|
protected seriesStyle(): CartesianSeries;
|
|
11
14
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { CartesianChart } from "./CartesianChart.js";
|
|
3
|
+
import { IconChartLine } from "@tabler/icons-react";
|
|
3
4
|
// src/component/organism/EChart/chart/LineChart.ts
|
|
4
5
|
/**
|
|
5
6
|
* Line chart: shows the trend of each series along the categories.
|
|
@@ -8,6 +9,10 @@ import { CartesianChart } from "./CartesianChart.js";
|
|
|
8
9
|
*/
|
|
9
10
|
var LineChart = class extends CartesianChart {
|
|
10
11
|
id = "line";
|
|
12
|
+
/** @param icon icon that replaces the default one */
|
|
13
|
+
constructor(icon = IconChartLine) {
|
|
14
|
+
super(icon);
|
|
15
|
+
}
|
|
11
16
|
seriesStyle() {
|
|
12
17
|
return {
|
|
13
18
|
type: "line",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LineChart.js","names":[],"sources":["../../../../../src/component/organism/EChart/chart/LineChart.ts"],"sourcesContent":["import { ChartTypeId } from './ChartTypeId';\nimport { CartesianChart, CartesianSeries } from './CartesianChart';\n\n/**\n * Line chart: shows the trend of each series along the categories.\n * Suited to rates and levels (e.g. percentages, coefficients, population).\n * @author Manoel Campos\n */\nexport class LineChart extends CartesianChart {\n readonly id: ChartTypeId = 'line';\n\n protected seriesStyle(): CartesianSeries {\n // connectNulls false: a category without a value is a gap in the line, instead of joining the neighbors.\n return { type: 'line', connectNulls: false };\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"LineChart.js","names":[],"sources":["../../../../../src/component/organism/EChart/chart/LineChart.ts"],"sourcesContent":["import { IconChartLine, type Icon } from '@tabler/icons-react';\n\nimport { ChartTypeId } from './ChartTypeId';\nimport { CartesianChart, CartesianSeries } from './CartesianChart';\n\n/**\n * Line chart: shows the trend of each series along the categories.\n * Suited to rates and levels (e.g. percentages, coefficients, population).\n * @author Manoel Campos\n */\nexport class LineChart extends CartesianChart {\n readonly id: ChartTypeId = 'line';\n\n /** @param icon icon that replaces the default one */\n constructor(icon: Icon = IconChartLine) {\n super(icon);\n }\n\n protected seriesStyle(): CartesianSeries {\n // connectNulls false: a category without a value is a gap in the line, instead of joining the neighbors.\n return { type: 'line', connectNulls: false };\n }\n}\n"],"mappings":";;;;;;;;;AAUA,IAAa,YAAb,cAA+B,eAAe;CAC1C,KAA2B;;CAG3B,YAAY,OAAa,eAAe;EACpC,MAAM,IAAI;CACd;CAEA,cAAyC;EAErC,OAAO;GAAE,MAAM;GAAQ,cAAc;EAAM;CAC/C;AACJ"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type Icon } from '@tabler/icons-react';
|
|
1
2
|
import { ChartSeries } from './ChartSeries';
|
|
2
3
|
import { ChartTypeId } from './ChartTypeId';
|
|
3
4
|
import { CartesianChart, CartesianSeries } from './CartesianChart';
|
|
@@ -10,6 +11,8 @@ import { CartesianChart, CartesianSeries } from './CartesianChart';
|
|
|
10
11
|
*/
|
|
11
12
|
export declare class StackedBarChart extends CartesianChart {
|
|
12
13
|
readonly id: ChartTypeId;
|
|
14
|
+
/** @param icon icon that replaces the default one */
|
|
15
|
+
constructor(icon?: Icon);
|
|
13
16
|
isAvailable(series: ChartSeries[]): boolean;
|
|
14
17
|
protected seriesStyle(serie: ChartSeries, all: ChartSeries[]): CartesianSeries;
|
|
15
18
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { groupByStack } from "./ChartSeries.js";
|
|
3
3
|
import { CartesianChart } from "./CartesianChart.js";
|
|
4
|
+
import { IconChartColumn } from "@tabler/icons-react";
|
|
4
5
|
// src/component/organism/EChart/chart/StackedBarChart.ts
|
|
5
6
|
/**
|
|
6
7
|
* Stacked column chart with lines: the series of the same stack ({@link ChartSeries#stack}) are stacked, showing how
|
|
@@ -11,6 +12,10 @@ import { CartesianChart } from "./CartesianChart.js";
|
|
|
11
12
|
*/
|
|
12
13
|
var StackedBarChart = class extends CartesianChart {
|
|
13
14
|
id = "stacked-bar";
|
|
15
|
+
/** @param icon icon that replaces the default one */
|
|
16
|
+
constructor(icon = IconChartColumn) {
|
|
17
|
+
super(icon);
|
|
18
|
+
}
|
|
14
19
|
isAvailable(series) {
|
|
15
20
|
return groupByStack(series).size > 0;
|
|
16
21
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StackedBarChart.js","names":[],"sources":["../../../../../src/component/organism/EChart/chart/StackedBarChart.ts"],"sourcesContent":["import { ChartSeries, groupByStack } from './ChartSeries';\nimport { ChartTypeId } from './ChartTypeId';\nimport { CartesianChart, CartesianSeries } from './CartesianChart';\n\n/**\n * Stacked column chart with lines: the series of the same stack ({@link ChartSeries#stack}) are stacked, showing how\n * much each one contributes to each category, and the other series (such as a total) become lines over the columns.\n * It is available only when there is a stack with enough series (see `groupByStack`). Whoever builds the series\n * decides which ones can be stacked, so series whose sum makes no sense are never stacked.\n * @author Manoel Campos\n */\nexport class StackedBarChart extends CartesianChart {\n readonly id: ChartTypeId = 'stacked-bar';\n\n isAvailable(series: ChartSeries[]): boolean {\n return groupByStack(series).size > 0;\n }\n\n protected seriesStyle(serie: ChartSeries, all: ChartSeries[]): CartesianSeries {\n // A series with a stack, but alone in it, has nothing to be stacked with: it becomes a line.\n if (!serie.stack || !groupByStack(all).has(serie.stack)) return { type: 'line', connectNulls: false };\n\n // Each stack is stacked separately, so series of different wholes are not added up.\n return { type: 'bar', stack: serie.stack };\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"StackedBarChart.js","names":[],"sources":["../../../../../src/component/organism/EChart/chart/StackedBarChart.ts"],"sourcesContent":["import { IconChartColumn, type Icon } from '@tabler/icons-react';\n\nimport { ChartSeries, groupByStack } from './ChartSeries';\nimport { ChartTypeId } from './ChartTypeId';\nimport { CartesianChart, CartesianSeries } from './CartesianChart';\n\n/**\n * Stacked column chart with lines: the series of the same stack ({@link ChartSeries#stack}) are stacked, showing how\n * much each one contributes to each category, and the other series (such as a total) become lines over the columns.\n * It is available only when there is a stack with enough series (see `groupByStack`). Whoever builds the series\n * decides which ones can be stacked, so series whose sum makes no sense are never stacked.\n * @author Manoel Campos\n */\nexport class StackedBarChart extends CartesianChart {\n readonly id: ChartTypeId = 'stacked-bar';\n\n /** @param icon icon that replaces the default one */\n constructor(icon: Icon = IconChartColumn) {\n super(icon);\n }\n\n isAvailable(series: ChartSeries[]): boolean {\n return groupByStack(series).size > 0;\n }\n\n protected seriesStyle(serie: ChartSeries, all: ChartSeries[]): CartesianSeries {\n // A series with a stack, but alone in it, has nothing to be stacked with: it becomes a line.\n if (!serie.stack || !groupByStack(all).has(serie.stack)) return { type: 'line', connectNulls: false };\n\n // Each stack is stacked separately, so series of different wholes are not added up.\n return { type: 'bar', stack: serie.stack };\n }\n}\n"],"mappings":";;;;;;;;;;;;AAaA,IAAa,kBAAb,cAAqC,eAAe;CAChD,KAA2B;;CAG3B,YAAY,OAAa,iBAAiB;EACtC,MAAM,IAAI;CACd;CAEA,YAAY,QAAgC;EACxC,OAAO,aAAa,MAAM,CAAC,CAAC,OAAO;CACvC;CAEA,YAAsB,OAAoB,KAAqC;EAE3E,IAAI,CAAC,MAAM,SAAS,CAAC,aAAa,GAAG,CAAC,CAAC,IAAI,MAAM,KAAK,GAAG,OAAO;GAAE,MAAM;GAAQ,cAAc;EAAM;EAGpG,OAAO;GAAE,MAAM;GAAO,OAAO,MAAM;EAAM;CAC7C;AACJ"}
|
package/dist/i18n/KitLocale.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
/** American English locale. */
|
|
2
|
+
export declare const LOCALE_EN_US = "en-US";
|
|
3
|
+
/** Brazilian Portuguese locale. */
|
|
4
|
+
export declare const LOCALE_PT_BR = "pt-BR";
|
|
1
5
|
/** Locales with a built-in message catalog. */
|
|
2
|
-
export type KitLocale =
|
|
6
|
+
export type KitLocale = typeof LOCALE_PT_BR | typeof LOCALE_EN_US;
|
|
3
7
|
/** Locale used when the app does not choose one. */
|
|
4
8
|
export declare const DEFAULT_LOCALE: KitLocale;
|
package/dist/i18n/KitLocale.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
// src/i18n/KitLocale.ts
|
|
3
|
+
/** American English locale. */
|
|
4
|
+
var LOCALE_EN_US = "en-US";
|
|
5
|
+
/** Brazilian Portuguese locale. */
|
|
6
|
+
var LOCALE_PT_BR = "pt-BR";
|
|
3
7
|
/** Locale used when the app does not choose one. */
|
|
4
|
-
var DEFAULT_LOCALE =
|
|
5
|
-
export { DEFAULT_LOCALE };
|
|
8
|
+
var DEFAULT_LOCALE = LOCALE_EN_US;
|
|
9
|
+
export { DEFAULT_LOCALE, LOCALE_EN_US, LOCALE_PT_BR };
|
|
6
10
|
|
|
7
11
|
//# sourceMappingURL=KitLocale.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"KitLocale.js","names":[],"sources":["../../src/i18n/KitLocale.ts"],"sourcesContent":["/** Locales with a built-in message catalog. */\nexport type KitLocale =
|
|
1
|
+
{"version":3,"file":"KitLocale.js","names":[],"sources":["../../src/i18n/KitLocale.ts"],"sourcesContent":["/** American English locale. */\nexport const LOCALE_EN_US = 'en-US';\n\n/** Brazilian Portuguese locale. */\nexport const LOCALE_PT_BR = 'pt-BR';\n\n/** Locales with a built-in message catalog. */\nexport type KitLocale = typeof LOCALE_PT_BR | typeof LOCALE_EN_US;\n\n/** Locale used when the app does not choose one. */\nexport const DEFAULT_LOCALE: KitLocale = LOCALE_EN_US;\n"],"mappings":";;;AACA,IAAa,eAAe;;AAG5B,IAAa,eAAe;;AAM5B,IAAa,iBAA4B"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import
|
|
2
|
+
import { formatLocaleDate, formatLocaleTime } from "../../util/DateUtil.js";
|
|
3
|
+
import { LOCALE_EN_US } from "../KitLocale.js";
|
|
3
4
|
// src/i18n/messages/enUS.ts
|
|
4
5
|
/** American English texts, the default locale. */
|
|
5
6
|
var enUS = {
|
|
@@ -69,7 +70,7 @@ var enUS = {
|
|
|
69
70
|
export: {
|
|
70
71
|
button: "Export",
|
|
71
72
|
failed: (formatLabel) => `Could not export to ${formatLabel}.`,
|
|
72
|
-
generatedAt: (date) => `Generated on ${
|
|
73
|
+
generatedAt: (date) => `Generated on ${formatLocaleDate(date, LOCALE_EN_US)} at ${formatLocaleTime(date, LOCALE_EN_US)}`,
|
|
73
74
|
footer: (systemName) => `Data generated by ${systemName}`,
|
|
74
75
|
excelPageNumber: "Page &P of &N",
|
|
75
76
|
invalidCell: "Error",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enUS.js","names":[],"sources":["../../../src/i18n/messages/enUS.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"file":"enUS.js","names":[],"sources":["../../../src/i18n/messages/enUS.ts"],"sourcesContent":["import { formatLocaleDate, formatLocaleTime } from '../../util/DateUtil';\nimport { LOCALE_EN_US } from '../KitLocale';\nimport { KitMessages } from '../KitMessages';\n\n/** American English texts, the default locale. */\nexport const enUS: KitMessages = {\n common: {\n back: 'Back',\n save: 'Save',\n cancel: 'Cancel',\n confirm: 'Confirm',\n add: 'Add',\n home: 'Home',\n success: 'Success',\n warning: 'Warning',\n error: 'Error',\n loadError: 'Error loading data',\n dateFormat: 'MM/DD/YYYY'\n },\n form: {\n action: { create: 'Create', edit: 'Update', view: 'View', custom: 'Customize' },\n saveSuccess: action => `Record ${pastTense(action)} successfully!`,\n saveError: action => `Error trying to ${action.toLowerCase()} the record`,\n createSuccess: 'Record created successfully',\n createError: 'There was an error creating the record!',\n updateSuccess: 'Record updated successfully',\n updateError: 'There was an error updating the record',\n confirmTitle: 'Confirm your action'\n },\n table: {\n actions: 'Actions',\n view: 'View',\n edit: 'Edit',\n delete: 'Delete',\n deleteConfirm: 'You are about to delete this record. Are you sure you want to continue?',\n deleteSuccess: 'Record deleted successfully!',\n noRecords: 'There are no records to display.',\n recordsPerPage: 'Records per page',\n pagination: ({ from, to, totalRecords }) => `Showing ${from} to ${to} of ${totalRecords} records`,\n listTitle: pluralName => `${pluralName} list`\n },\n rowEdit: {\n edit: 'Edit values (Enter)',\n confirm: 'Confirm editing (Enter)',\n cancel: 'Cancel editing (Esc)'\n },\n select: {\n placeholder: label => `Select the ${label}`,\n nothingFound: label => `${label} not found`\n },\n layout: {\n userMenu: 'Open user options',\n userMenuTitle: 'User Options',\n enableDarkTheme: 'Enable dark theme',\n enableLightTheme: 'Enable light theme',\n collapseNavigation: 'Collapse navigation menu',\n expandNavigation: 'Expand navigation menu'\n },\n print: {\n pdfTipTitle: 'To save as PDF',\n pdfTip:\n 'In the print dialog, choose \"Save as PDF\" as the destination and uncheck \"Headers and footers\", so ' +\n 'the PDF has only the ones of the report.',\n printButton: 'Print or save as PDF'\n },\n stats: {\n comparedToLastMonth: 'Compared to last month'\n },\n export: {\n button: 'Export',\n failed: formatLabel => `Could not export to ${formatLabel}.`,\n generatedAt: date =>\n `Generated on ${formatLocaleDate(date, LOCALE_EN_US)} at ${formatLocaleTime(date, LOCALE_EN_US)}`,\n footer: systemName => `Data generated by ${systemName}`,\n excelPageNumber: 'Page &P of &N',\n invalidCell: 'Error',\n defaultFileName: 'data',\n defaultSheetName: position => `Sheet ${position}`\n },\n chart: {\n types: { bar: 'Columns', line: 'Line', 'stacked-bar': 'Stacked columns', donut: 'Donut (one year)' },\n saveAsImage: 'Save as image',\n total: formattedTotal => `Total: ${formattedTotal}`\n },\n http: {\n unknownError: 'Unknown error',\n noResponse: 'No response received',\n requestFailed: 'Request failed'\n }\n};\n\n/** Past tense of the form action verbs (e.g. \"Create\" → \"created\"), used in the success message. */\nconst PAST_TENSE: Record<string, string> = { create: 'created', update: 'updated', view: 'viewed' };\n\n/**\n * Returns the past tense of a form action verb.\n * @param action verb, as in `form.action`\n * @return the past tense, in lower case; for an unknown verb, the verb itself followed by \"d\"\n */\nfunction pastTense(action: string): string {\n const verb = action.toLowerCase();\n\n return PAST_TENSE[verb] ?? `${verb}d`;\n}\n"],"mappings":";;;;;AAKA,IAAa,OAAoB;CAC7B,QAAQ;EACJ,MAAM;EACN,MAAM;EACN,QAAQ;EACR,SAAS;EACT,KAAK;EACL,MAAM;EACN,SAAS;EACT,SAAS;EACT,OAAO;EACP,WAAW;EACX,YAAY;CAChB;CACA,MAAM;EACF,QAAQ;GAAE,QAAQ;GAAU,MAAM;GAAU,MAAM;GAAQ,QAAQ;EAAY;EAC9E,cAAa,WAAU,UAAU,UAAU,MAAM,EAAE;EACnD,YAAW,WAAU,mBAAmB,OAAO,YAAY,EAAE;EAC7D,eAAe;EACf,aAAa;EACb,eAAe;EACf,aAAa;EACb,cAAc;CAClB;CACA,OAAO;EACH,SAAS;EACT,MAAM;EACN,MAAM;EACN,QAAQ;EACR,eAAe;EACf,eAAe;EACf,WAAW;EACX,gBAAgB;EAChB,aAAa,EAAE,MAAM,IAAI,mBAAmB,WAAW,KAAK,MAAM,GAAG,MAAM,aAAa;EACxF,YAAW,eAAc,GAAG,WAAW;CAC3C;CACA,SAAS;EACL,MAAM;EACN,SAAS;EACT,QAAQ;CACZ;CACA,QAAQ;EACJ,cAAa,UAAS,cAAc;EACpC,eAAc,UAAS,GAAG,MAAM;CACpC;CACA,QAAQ;EACJ,UAAU;EACV,eAAe;EACf,iBAAiB;EACjB,kBAAkB;EAClB,oBAAoB;EACpB,kBAAkB;CACtB;CACA,OAAO;EACH,aAAa;EACb,QACI;EAEJ,aAAa;CACjB;CACA,OAAO,EACH,qBAAqB,yBACzB;CACA,QAAQ;EACJ,QAAQ;EACR,SAAQ,gBAAe,uBAAuB,YAAY;EAC1D,cAAa,SACT,gBAAgB,iBAAiB,MAAM,YAAY,EAAE,MAAM,iBAAiB,MAAM,YAAY;EAClG,SAAQ,eAAc,qBAAqB;EAC3C,iBAAiB;EACjB,aAAa;EACb,iBAAiB;EACjB,mBAAkB,aAAY,SAAS;CAC3C;CACA,OAAO;EACH,OAAO;GAAE,KAAK;GAAW,MAAM;GAAQ,eAAe;GAAmB,OAAO;EAAmB;EACnG,aAAa;EACb,QAAO,mBAAkB,UAAU;CACvC;CACA,MAAM;EACF,cAAc;EACd,YAAY;EACZ,eAAe;CACnB;AACJ;;AAGA,IAAM,aAAqC;CAAE,QAAQ;CAAW,QAAQ;CAAW,MAAM;AAAS;;;;;;AAOlG,SAAS,UAAU,QAAwB;CACvC,MAAM,OAAO,OAAO,YAAY;CAEhC,OAAO,WAAW,SAAS,GAAG,KAAK;AACvC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import
|
|
2
|
+
import { formatLocaleDate, formatLocaleTime } from "../../util/DateUtil.js";
|
|
3
|
+
import { LOCALE_PT_BR } from "../KitLocale.js";
|
|
3
4
|
// src/i18n/messages/ptBR.ts
|
|
4
5
|
/** Brazilian Portuguese texts. */
|
|
5
6
|
var ptBR = {
|
|
@@ -69,7 +70,7 @@ var ptBR = {
|
|
|
69
70
|
export: {
|
|
70
71
|
button: "Exportar",
|
|
71
72
|
failed: (formatLabel) => `Não foi possível exportar em ${formatLabel}.`,
|
|
72
|
-
generatedAt: (date) => `Gerado em ${
|
|
73
|
+
generatedAt: (date) => `Gerado em ${formatLocaleDate(date, LOCALE_PT_BR)} às ${formatLocaleTime(date, LOCALE_PT_BR)}`,
|
|
73
74
|
footer: (systemName) => `Dados gerados pelo ${systemName}`,
|
|
74
75
|
excelPageNumber: "Página &P de &N",
|
|
75
76
|
invalidCell: "Erro",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ptBR.js","names":[],"sources":["../../../src/i18n/messages/ptBR.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"file":"ptBR.js","names":[],"sources":["../../../src/i18n/messages/ptBR.ts"],"sourcesContent":["import { formatLocaleDate, formatLocaleTime } from '../../util/DateUtil';\nimport { LOCALE_PT_BR } from '../KitLocale';\nimport { KitMessages } from '../KitMessages';\n\n/** Brazilian Portuguese texts. */\nexport const ptBR: KitMessages = {\n common: {\n back: 'Voltar',\n save: 'Salvar',\n cancel: 'Cancelar',\n confirm: 'Confirmar',\n add: 'Adicionar',\n home: 'Início',\n success: 'Sucesso',\n warning: 'Atenção',\n error: 'Erro',\n loadError: 'Erro ao carregar dados',\n dateFormat: 'DD/MM/YYYY'\n },\n form: {\n action: { create: 'Criar', edit: 'Atualizar', view: 'Visualizar', custom: 'Personalizar' },\n saveSuccess: action => `Sucesso ao ${action.toLowerCase()} cadastro!`,\n saveError: action => `Erro ao ${action.toLowerCase()} cadastro`,\n createSuccess: 'Registro cadastrado com sucesso',\n createError: 'Houve um erro ao realizar o cadastro!',\n updateSuccess: 'Cadastro atualizado com sucesso',\n updateError: 'Houve um erro ao atualizar o cadastro',\n confirmTitle: 'Confirme sua ação'\n },\n table: {\n actions: 'Ações',\n view: 'Visualizar',\n edit: 'Editar',\n delete: 'Deletar',\n deleteConfirm: 'Você está prestes a excluir este cadastro. Tem certeza de que deseja continuar?',\n deleteSuccess: 'Cadastro excluído com sucesso!',\n noRecords: 'Não há registros disponíveis para exibição.',\n recordsPerPage: 'Registros por página',\n pagination: ({ from, to, totalRecords }) => `Exibindo ${from} a ${to} de ${totalRecords} registros`,\n listTitle: pluralName => `Lista de ${pluralName}`\n },\n rowEdit: {\n edit: 'Editar valores (Enter)',\n confirm: 'Confirmar edição (Enter)',\n cancel: 'Cancelar edição (Esc)'\n },\n select: {\n placeholder: label => `Selecione o(a) ${label}`,\n nothingFound: label => `${label} não encontrado(a)`\n },\n layout: {\n userMenu: 'Acessar opções do usuário',\n userMenuTitle: 'Opções do Usuário',\n enableDarkTheme: 'Ativar tema escuro',\n enableLightTheme: 'Ativar tema claro',\n collapseNavigation: 'Recolher menu de navegação',\n expandNavigation: 'Expandir menu de navegação'\n },\n print: {\n pdfTipTitle: 'Para salvar em PDF',\n pdfTip:\n 'Na janela de impressão, escolha \"Salvar como PDF\" como destino e desmarque \"Cabeçalhos e rodapés\", ' +\n 'para o PDF ter só os do relatório.',\n printButton: 'Imprimir ou salvar como PDF'\n },\n stats: {\n comparedToLastMonth: 'Comparado ao último mês'\n },\n export: {\n button: 'Exportar',\n failed: formatLabel => `Não foi possível exportar em ${formatLabel}.`,\n generatedAt: date =>\n `Gerado em ${formatLocaleDate(date, LOCALE_PT_BR)} às ${formatLocaleTime(date, LOCALE_PT_BR)}`,\n footer: systemName => `Dados gerados pelo ${systemName}`,\n excelPageNumber: 'Página &P de &N',\n invalidCell: 'Erro',\n defaultFileName: 'dados',\n defaultSheetName: position => `Aba ${position}`\n },\n chart: {\n types: { bar: 'Colunas', line: 'Linha', 'stacked-bar': 'Colunas empilhadas', donut: 'Rosca (um ano)' },\n saveAsImage: 'Exportar imagem',\n total: formattedTotal => `Total: ${formattedTotal}`\n },\n http: {\n unknownError: 'Erro desconhecido',\n noResponse: 'Nenhuma resposta recebida',\n requestFailed: 'Requisição falhou'\n }\n};\n"],"mappings":";;;;;AAKA,IAAa,OAAoB;CAC7B,QAAQ;EACJ,MAAM;EACN,MAAM;EACN,QAAQ;EACR,SAAS;EACT,KAAK;EACL,MAAM;EACN,SAAS;EACT,SAAS;EACT,OAAO;EACP,WAAW;EACX,YAAY;CAChB;CACA,MAAM;EACF,QAAQ;GAAE,QAAQ;GAAS,MAAM;GAAa,MAAM;GAAc,QAAQ;EAAe;EACzF,cAAa,WAAU,cAAc,OAAO,YAAY,EAAE;EAC1D,YAAW,WAAU,WAAW,OAAO,YAAY,EAAE;EACrD,eAAe;EACf,aAAa;EACb,eAAe;EACf,aAAa;EACb,cAAc;CAClB;CACA,OAAO;EACH,SAAS;EACT,MAAM;EACN,MAAM;EACN,QAAQ;EACR,eAAe;EACf,eAAe;EACf,WAAW;EACX,gBAAgB;EAChB,aAAa,EAAE,MAAM,IAAI,mBAAmB,YAAY,KAAK,KAAK,GAAG,MAAM,aAAa;EACxF,YAAW,eAAc,YAAY;CACzC;CACA,SAAS;EACL,MAAM;EACN,SAAS;EACT,QAAQ;CACZ;CACA,QAAQ;EACJ,cAAa,UAAS,kBAAkB;EACxC,eAAc,UAAS,GAAG,MAAM;CACpC;CACA,QAAQ;EACJ,UAAU;EACV,eAAe;EACf,iBAAiB;EACjB,kBAAkB;EAClB,oBAAoB;EACpB,kBAAkB;CACtB;CACA,OAAO;EACH,aAAa;EACb,QACI;EAEJ,aAAa;CACjB;CACA,OAAO,EACH,qBAAqB,0BACzB;CACA,QAAQ;EACJ,QAAQ;EACR,SAAQ,gBAAe,gCAAgC,YAAY;EACnE,cAAa,SACT,aAAa,iBAAiB,MAAM,YAAY,EAAE,MAAM,iBAAiB,MAAM,YAAY;EAC/F,SAAQ,eAAc,sBAAsB;EAC5C,iBAAiB;EACjB,aAAa;EACb,iBAAiB;EACjB,mBAAkB,aAAY,OAAO;CACzC;CACA,OAAO;EACH,OAAO;GAAE,KAAK;GAAW,MAAM;GAAS,eAAe;GAAsB,OAAO;EAAiB;EACrG,aAAa;EACb,QAAO,mBAAkB,UAAU;CACvC;CACA,MAAM;EACF,cAAc;EACd,YAAY;EACZ,eAAe;CACnB;AACJ"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { DEFAULT_LOCALE } from "./KitLocale.js";
|
|
2
|
+
import { DEFAULT_LOCALE, LOCALE_EN_US, LOCALE_PT_BR } from "./KitLocale.js";
|
|
3
3
|
import { enUS } from "./messages/enUS.js";
|
|
4
4
|
import { ptBR } from "./messages/ptBR.js";
|
|
5
5
|
// src/i18n/resolveMessages.ts
|
|
6
6
|
/** Built-in message catalog of each locale. */
|
|
7
7
|
var KIT_MESSAGES = {
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
[LOCALE_PT_BR]: ptBR,
|
|
9
|
+
[LOCALE_EN_US]: enUS
|
|
10
10
|
};
|
|
11
11
|
/** Texts of the {@link DEFAULT_LOCALE}, used as defaults by the code outside React. */
|
|
12
12
|
var DEFAULT_MESSAGES = KIT_MESSAGES[DEFAULT_LOCALE];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolveMessages.js","names":[],"sources":["../../src/i18n/resolveMessages.ts"],"sourcesContent":["import { DEFAULT_LOCALE, KitLocale } from './KitLocale';\nimport { KitMessages, KitMessagesOverride } from './KitMessages';\nimport { enUS } from './messages/enUS';\nimport { ptBR } from './messages/ptBR';\n\n/** Built-in message catalog of each locale. */\nexport const KIT_MESSAGES: Readonly<Record<KitLocale, KitMessages>> = {
|
|
1
|
+
{"version":3,"file":"resolveMessages.js","names":[],"sources":["../../src/i18n/resolveMessages.ts"],"sourcesContent":["import { DEFAULT_LOCALE, KitLocale, LOCALE_EN_US, LOCALE_PT_BR } from './KitLocale';\nimport { KitMessages, KitMessagesOverride } from './KitMessages';\nimport { enUS } from './messages/enUS';\nimport { ptBR } from './messages/ptBR';\n\n/** Built-in message catalog of each locale. */\nexport const KIT_MESSAGES: Readonly<Record<KitLocale, KitMessages>> = {\n [LOCALE_PT_BR]: ptBR,\n [LOCALE_EN_US]: enUS\n};\n\n/** Texts of the {@link DEFAULT_LOCALE}, used as defaults by the code outside React. */\nexport const DEFAULT_MESSAGES: KitMessages = KIT_MESSAGES[DEFAULT_LOCALE];\n\n/**\n * Returns the texts of a locale, with the texts the app overrides.\n * @param locale locale of the texts; defaults to {@link DEFAULT_LOCALE}\n * @param override texts that replace the ones of the locale, by section\n * @return the texts, with every section complete\n */\nexport function resolveMessages(locale: KitLocale = DEFAULT_LOCALE, override: KitMessagesOverride = {}): KitMessages {\n const base = KIT_MESSAGES[locale];\n const sections = Object.keys(base) as (keyof KitMessages)[];\n\n return Object.fromEntries(\n sections.map(section => [section, { ...base[section], ...override[section] }])\n ) as KitMessages;\n}\n"],"mappings":";;;;;;AAMA,IAAa,eAAyD;EACjE,eAAe;EACf,eAAe;AACpB;;AAGA,IAAa,mBAAgC,aAAa;;;;;;;AAQ1D,SAAgB,gBAAgB,SAAoB,gBAAgB,WAAgC,CAAC,GAAgB;CACjH,MAAM,OAAO,aAAa;CAC1B,MAAM,WAAW,OAAO,KAAK,IAAI;CAEjC,OAAO,OAAO,YACV,SAAS,KAAI,YAAW,CAAC,SAAS;EAAE,GAAG,KAAK;EAAU,GAAG,SAAS;CAAS,CAAC,CAAC,CACjF;AACJ"}
|
package/dist/util/DateUtil.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { KitLocale } from '../i18n/KitLocale';
|
|
1
2
|
/** Value of a date field: a `Date`, a text in the given format, or nothing. */
|
|
2
3
|
export type DateFieldValue = Date | string | null | undefined;
|
|
3
4
|
export declare const BR_DATE_FORMAT = "DD/MM/YYYY";
|
|
@@ -7,24 +8,40 @@ export declare const ISO_DATE_FORMAT = "YYYY-MM-DD";
|
|
|
7
8
|
* `new Date(null)` (12/31/1969), which Zod's `coerce` produces when a date field is not filled and receives `null`.
|
|
8
9
|
*/
|
|
9
10
|
export declare const MIN_VALID_DATE: Date;
|
|
11
|
+
/** @return whether there is a date and it is valid: `Intl` throws an error for an Invalid Date */
|
|
12
|
+
export declare function isValidDate(date: Date | undefined | null): date is Date;
|
|
10
13
|
/**
|
|
11
|
-
* Formats a date.
|
|
14
|
+
* Formats a date in the numeric format of the locale, with 2-digit day and month (e.g. `10/05/2026` in `en-US`).
|
|
15
|
+
* @param date a valid date, shown in the time zone of the runtime
|
|
16
|
+
* @param locale locale that defines the order of the fields
|
|
17
|
+
*/
|
|
18
|
+
export declare function formatLocaleDate(date: Date, locale: KitLocale): string;
|
|
19
|
+
/**
|
|
20
|
+
* Formats a time, without seconds, in the format of the locale (e.g. `2:30 PM` in `en-US`, `14:30` in `pt-BR`).
|
|
21
|
+
* @param date a valid date, shown in the time zone of the runtime
|
|
22
|
+
* @param locale locale that defines the 12 or 24-hour clock
|
|
23
|
+
*/
|
|
24
|
+
export declare function formatLocaleTime(date: Date, locale: KitLocale): string;
|
|
25
|
+
/**
|
|
26
|
+
* Formats a date in the numeric format of the locale.
|
|
12
27
|
* @param date date to format
|
|
13
|
-
* @param
|
|
14
|
-
* @return the formatted date, or `null` if there is no date
|
|
28
|
+
* @param locale locale of the format; defaults to {@link DEFAULT_LOCALE}
|
|
29
|
+
* @return the formatted date, or `null` if there is no valid date
|
|
15
30
|
*/
|
|
16
|
-
export declare function formatDate(date: Date | undefined | null,
|
|
31
|
+
export declare function formatDate(date: Date | undefined | null, locale?: KitLocale): string | null;
|
|
17
32
|
/**
|
|
18
|
-
* Formats a date in the ISO 8601 format.
|
|
33
|
+
* Formats a date in the ISO 8601 format, in the time zone of the runtime.
|
|
19
34
|
* @param date date to format
|
|
35
|
+
* @return the formatted date, or `null` if there is no valid date
|
|
20
36
|
* @see #ISO_DATE_FORMAT
|
|
21
37
|
*/
|
|
22
38
|
export declare function formatDateToISO(date: Date | undefined | null): string | null;
|
|
23
39
|
/**
|
|
24
40
|
* Converts a date in the given format to a `Date` object.
|
|
25
41
|
* @param dateValue date to convert
|
|
26
|
-
* @param format format of
|
|
27
|
-
* @return the date,
|
|
42
|
+
* @param format format of a text date, with the tokens `DD`, `MM` and `YYYY`; defaults to {@link BR_DATE_FORMAT}
|
|
43
|
+
* @return the date, `null` if there is no date, or an Invalid Date if the text is not a date in the format
|
|
44
|
+
* @throws Error if a text date is given with an unsupported format
|
|
28
45
|
*/
|
|
29
46
|
export declare function parseDate(dateValue: DateFieldValue, format?: string): Date | null;
|
|
30
47
|
/** @return the current year and month in the `YYYY-MM` format */
|
package/dist/util/DateUtil.js
CHANGED
|
@@ -1,45 +1,111 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import
|
|
3
|
-
import customParseFormat from "dayjs/plugin/customParseFormat.js";
|
|
2
|
+
import { DEFAULT_LOCALE } from "../i18n/KitLocale.js";
|
|
4
3
|
// src/util/DateUtil.ts
|
|
5
|
-
dayjs.extend(customParseFormat);
|
|
6
4
|
var BR_DATE_FORMAT = "DD/MM/YYYY";
|
|
7
5
|
var ISO_DATE_FORMAT = "YYYY-MM-DD";
|
|
6
|
+
/** Tokens of the formats {@link parseDate} reads, with the part of the date each one captures. */
|
|
7
|
+
var DATE_TOKEN_PATTERNS = {
|
|
8
|
+
YYYY: "(?<year>\\d{4})",
|
|
9
|
+
MM: "(?<month>\\d{2})",
|
|
10
|
+
DD: "(?<day>\\d{2})"
|
|
11
|
+
};
|
|
12
|
+
var DATE_TOKEN = /YYYY|MM|DD/g;
|
|
13
|
+
/** Length of the `YYYY-MM` prefix of an ISO date. */
|
|
14
|
+
var YEAR_MONTH_LENGTH = 7;
|
|
8
15
|
/**
|
|
9
16
|
* Minimum value for a date to be considered valid when Zod coerces it. It is later than the date created by
|
|
10
17
|
* `new Date(null)` (12/31/1969), which Zod's `coerce` produces when a date field is not filled and receives `null`.
|
|
11
18
|
*/
|
|
12
19
|
var MIN_VALID_DATE = /* @__PURE__ */ new Date("01/01/1970");
|
|
20
|
+
/** @return whether there is a date and it is valid: `Intl` throws an error for an Invalid Date */
|
|
21
|
+
function isValidDate(date) {
|
|
22
|
+
return !!date && !Number.isNaN(date.getTime());
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Formats a date in the numeric format of the locale, with 2-digit day and month (e.g. `10/05/2026` in `en-US`).
|
|
26
|
+
* @param date a valid date, shown in the time zone of the runtime
|
|
27
|
+
* @param locale locale that defines the order of the fields
|
|
28
|
+
*/
|
|
29
|
+
function formatLocaleDate(date, locale) {
|
|
30
|
+
return date.toLocaleDateString(locale, {
|
|
31
|
+
day: "2-digit",
|
|
32
|
+
month: "2-digit",
|
|
33
|
+
year: "numeric"
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Formats a time, without seconds, in the format of the locale (e.g. `2:30 PM` in `en-US`, `14:30` in `pt-BR`).
|
|
38
|
+
* @param date a valid date, shown in the time zone of the runtime
|
|
39
|
+
* @param locale locale that defines the 12 or 24-hour clock
|
|
40
|
+
*/
|
|
41
|
+
function formatLocaleTime(date, locale) {
|
|
42
|
+
return date.toLocaleTimeString(locale, { timeStyle: "short" });
|
|
43
|
+
}
|
|
13
44
|
/**
|
|
14
|
-
* Formats a date.
|
|
45
|
+
* Formats a date in the numeric format of the locale.
|
|
15
46
|
* @param date date to format
|
|
16
|
-
* @param
|
|
17
|
-
* @return the formatted date, or `null` if there is no date
|
|
47
|
+
* @param locale locale of the format; defaults to {@link DEFAULT_LOCALE}
|
|
48
|
+
* @return the formatted date, or `null` if there is no valid date
|
|
18
49
|
*/
|
|
19
|
-
function formatDate(date,
|
|
20
|
-
return date ?
|
|
50
|
+
function formatDate(date, locale = DEFAULT_LOCALE) {
|
|
51
|
+
return isValidDate(date) ? formatLocaleDate(date, locale) : null;
|
|
52
|
+
}
|
|
53
|
+
/** @return the date in the {@link ISO_DATE_FORMAT}, in the time zone of the runtime */
|
|
54
|
+
function toLocalIsoText(date) {
|
|
55
|
+
return `${date.getFullYear().toString().padStart(4, "0")}-${(date.getMonth() + 1).toString().padStart(2, "0")}-${date.getDate().toString().padStart(2, "0")}`;
|
|
21
56
|
}
|
|
22
57
|
/**
|
|
23
|
-
* Formats a date in the ISO 8601 format.
|
|
58
|
+
* Formats a date in the ISO 8601 format, in the time zone of the runtime.
|
|
24
59
|
* @param date date to format
|
|
60
|
+
* @return the formatted date, or `null` if there is no valid date
|
|
25
61
|
* @see #ISO_DATE_FORMAT
|
|
26
62
|
*/
|
|
27
63
|
function formatDateToISO(date) {
|
|
28
|
-
return date ?
|
|
64
|
+
return isValidDate(date) ? toLocalIsoText(date) : null;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Creates the regular expression that reads a date in the given format.
|
|
68
|
+
* @param format format with the tokens `DD`, `MM` and `YYYY`, once each, and no other letters
|
|
69
|
+
* @throws Error if the format has anything else, such as the `MMM` or `YY` tokens of Mantine's `valueFormat`
|
|
70
|
+
*/
|
|
71
|
+
function dateFormatRegex(format) {
|
|
72
|
+
const tokens = format.match(DATE_TOKEN) ?? [];
|
|
73
|
+
const onlyKnownTokens = !/[a-z]/i.test(format.replace(DATE_TOKEN, ""));
|
|
74
|
+
if (tokens.length !== 3 || new Set(tokens).size !== 3 || !onlyKnownTokens) throw new Error(`Unsupported date format: ${format}. Use DD, MM and YYYY.`);
|
|
75
|
+
const literalsEscaped = format.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
76
|
+
return new RegExp(`^${literalsEscaped.replace(DATE_TOKEN, (token) => DATE_TOKEN_PATTERNS[token])}$`);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Converts the text of a date to a `Date` at midnight in the time zone of the runtime.
|
|
80
|
+
* @return the date, or an Invalid Date if the text is not in the format or is not a date of the calendar (e.g. 02/31)
|
|
81
|
+
*/
|
|
82
|
+
function parseDateText(text, format) {
|
|
83
|
+
const parts = dateFormatRegex(format).exec(text)?.groups;
|
|
84
|
+
if (!parts) return /* @__PURE__ */ new Date(NaN);
|
|
85
|
+
const [year, month, day] = [
|
|
86
|
+
Number(parts.year),
|
|
87
|
+
Number(parts.month),
|
|
88
|
+
Number(parts.day)
|
|
89
|
+
];
|
|
90
|
+
const date = /* @__PURE__ */ new Date(0);
|
|
91
|
+
date.setFullYear(year, month - 1, day);
|
|
92
|
+
date.setHours(0, 0, 0, 0);
|
|
93
|
+
return date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day ? date : /* @__PURE__ */ new Date(NaN);
|
|
29
94
|
}
|
|
30
95
|
/**
|
|
31
96
|
* Converts a date in the given format to a `Date` object.
|
|
32
97
|
* @param dateValue date to convert
|
|
33
|
-
* @param format format of
|
|
34
|
-
* @return the date,
|
|
98
|
+
* @param format format of a text date, with the tokens `DD`, `MM` and `YYYY`; defaults to {@link BR_DATE_FORMAT}
|
|
99
|
+
* @return the date, `null` if there is no date, or an Invalid Date if the text is not a date in the format
|
|
100
|
+
* @throws Error if a text date is given with an unsupported format
|
|
35
101
|
*/
|
|
36
102
|
function parseDate(dateValue, format = BR_DATE_FORMAT) {
|
|
37
|
-
|
|
103
|
+
if (!dateValue) return null;
|
|
104
|
+
return dateValue instanceof Date ? new Date(dateValue) : parseDateText(dateValue, format);
|
|
38
105
|
}
|
|
39
106
|
/** @return the current year and month in the `YYYY-MM` format */
|
|
40
107
|
function getCurrentYearMonth() {
|
|
41
|
-
|
|
42
|
-
return `${currentDate.getFullYear()}-${(currentDate.getMonth() + 1).toString().padStart(2, "0")}`;
|
|
108
|
+
return toLocalIsoText(/* @__PURE__ */ new Date()).slice(0, YEAR_MONTH_LENGTH);
|
|
43
109
|
}
|
|
44
110
|
/**
|
|
45
111
|
* Checks whether the end date is after the start date.
|
|
@@ -50,6 +116,6 @@ function getCurrentYearMonth() {
|
|
|
50
116
|
function validDateInterval(startDate, endDate) {
|
|
51
117
|
return !endDate || endDate <= MIN_VALID_DATE || endDate > startDate;
|
|
52
118
|
}
|
|
53
|
-
export { BR_DATE_FORMAT, ISO_DATE_FORMAT, MIN_VALID_DATE, formatDate, formatDateToISO, getCurrentYearMonth, parseDate, validDateInterval };
|
|
119
|
+
export { BR_DATE_FORMAT, ISO_DATE_FORMAT, MIN_VALID_DATE, formatDate, formatDateToISO, formatLocaleDate, formatLocaleTime, getCurrentYearMonth, isValidDate, parseDate, validDateInterval };
|
|
54
120
|
|
|
55
121
|
//# sourceMappingURL=DateUtil.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DateUtil.js","names":[],"sources":["../../src/util/DateUtil.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"file":"DateUtil.js","names":[],"sources":["../../src/util/DateUtil.ts"],"sourcesContent":["import { DEFAULT_LOCALE, KitLocale } from '../i18n/KitLocale';\n\n/** Value of a date field: a `Date`, a text in the given format, or nothing. */\nexport type DateFieldValue = Date | string | null | undefined;\n\nexport const BR_DATE_FORMAT = 'DD/MM/YYYY';\nexport const ISO_DATE_FORMAT = 'YYYY-MM-DD';\n\n/** Tokens of the formats {@link parseDate} reads, with the part of the date each one captures. */\nconst DATE_TOKEN_PATTERNS: Readonly<Record<string, string>> = {\n YYYY: '(?<year>\\\\d{4})',\n MM: '(?<month>\\\\d{2})',\n DD: '(?<day>\\\\d{2})'\n};\n\nconst DATE_TOKEN = /YYYY|MM|DD/g;\n\n/** Length of the `YYYY-MM` prefix of an ISO date. */\nconst YEAR_MONTH_LENGTH = 7;\n\n/**\n * Minimum value for a date to be considered valid when Zod coerces it. It is later than the date created by\n * `new Date(null)` (12/31/1969), which Zod's `coerce` produces when a date field is not filled and receives `null`.\n */\nexport const MIN_VALID_DATE = new Date('01/01/1970');\n\n/** @return whether there is a date and it is valid: `Intl` throws an error for an Invalid Date */\nexport function isValidDate(date: Date | undefined | null): date is Date {\n return !!date && !Number.isNaN(date.getTime());\n}\n\n/**\n * Formats a date in the numeric format of the locale, with 2-digit day and month (e.g. `10/05/2026` in `en-US`).\n * @param date a valid date, shown in the time zone of the runtime\n * @param locale locale that defines the order of the fields\n */\nexport function formatLocaleDate(date: Date, locale: KitLocale): string {\n return date.toLocaleDateString(locale, { day: '2-digit', month: '2-digit', year: 'numeric' });\n}\n\n/**\n * Formats a time, without seconds, in the format of the locale (e.g. `2:30 PM` in `en-US`, `14:30` in `pt-BR`).\n * @param date a valid date, shown in the time zone of the runtime\n * @param locale locale that defines the 12 or 24-hour clock\n */\nexport function formatLocaleTime(date: Date, locale: KitLocale): string {\n return date.toLocaleTimeString(locale, { timeStyle: 'short' });\n}\n\n/**\n * Formats a date in the numeric format of the locale.\n * @param date date to format\n * @param locale locale of the format; defaults to {@link DEFAULT_LOCALE}\n * @return the formatted date, or `null` if there is no valid date\n */\nexport function formatDate(date: Date | undefined | null, locale: KitLocale = DEFAULT_LOCALE): string | null {\n return isValidDate(date) ? formatLocaleDate(date, locale) : null;\n}\n\n/** @return the date in the {@link ISO_DATE_FORMAT}, in the time zone of the runtime */\nfunction toLocalIsoText(date: Date): string {\n const year = date.getFullYear().toString().padStart(4, '0');\n const month = (date.getMonth() + 1).toString().padStart(2, '0');\n const day = date.getDate().toString().padStart(2, '0');\n\n return `${year}-${month}-${day}`;\n}\n\n/**\n * Formats a date in the ISO 8601 format, in the time zone of the runtime.\n * @param date date to format\n * @return the formatted date, or `null` if there is no valid date\n * @see #ISO_DATE_FORMAT\n */\nexport function formatDateToISO(date: Date | undefined | null): string | null {\n return isValidDate(date) ? toLocalIsoText(date) : null;\n}\n\n/**\n * Creates the regular expression that reads a date in the given format.\n * @param format format with the tokens `DD`, `MM` and `YYYY`, once each, and no other letters\n * @throws Error if the format has anything else, such as the `MMM` or `YY` tokens of Mantine's `valueFormat`\n */\nfunction dateFormatRegex(format: string): RegExp {\n const tokens = format.match(DATE_TOKEN) ?? [];\n const onlyKnownTokens = !/[a-z]/i.test(format.replace(DATE_TOKEN, ''));\n if (tokens.length !== 3 || new Set(tokens).size !== 3 || !onlyKnownTokens) {\n throw new Error(`Unsupported date format: ${format}. Use DD, MM and YYYY.`);\n }\n\n const literalsEscaped = format.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n return new RegExp(`^${literalsEscaped.replace(DATE_TOKEN, token => DATE_TOKEN_PATTERNS[token])}$`);\n}\n\n/**\n * Converts the text of a date to a `Date` at midnight in the time zone of the runtime.\n * @return the date, or an Invalid Date if the text is not in the format or is not a date of the calendar (e.g. 02/31)\n */\nfunction parseDateText(text: string, format: string): Date {\n const parts = dateFormatRegex(format).exec(text)?.groups;\n if (!parts) return new Date(NaN);\n\n const [year, month, day] = [Number(parts.year), Number(parts.month), Number(parts.day)];\n\n // setFullYear, since the Date constructor reads the years 0 to 99 as 1900 to 1999.\n const date = new Date(0);\n date.setFullYear(year, month - 1, day);\n date.setHours(0, 0, 0, 0);\n\n // Date moves a day missing from the calendar (e.g. 02/31) to the next month, which changes the fields.\n const isSameDate = date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day;\n return isSameDate ? date : new Date(NaN);\n}\n\n/**\n * Converts a date in the given format to a `Date` object.\n * @param dateValue date to convert\n * @param format format of a text date, with the tokens `DD`, `MM` and `YYYY`; defaults to {@link BR_DATE_FORMAT}\n * @return the date, `null` if there is no date, or an Invalid Date if the text is not a date in the format\n * @throws Error if a text date is given with an unsupported format\n */\nexport function parseDate(dateValue: DateFieldValue, format: string = BR_DATE_FORMAT): Date | null {\n if (!dateValue) return null;\n\n return dateValue instanceof Date ? new Date(dateValue) : parseDateText(dateValue, format);\n}\n\n/** @return the current year and month in the `YYYY-MM` format */\nexport function getCurrentYearMonth(): string {\n return toLocalIsoText(new Date()).slice(0, YEAR_MONTH_LENGTH);\n}\n\n/**\n * Checks whether the end date is after the start date.\n * @param startDate start of the interval\n * @param endDate end of the interval; an absent or empty (before {@link MIN_VALID_DATE}) end date is valid\n * @return `true` if the interval is valid\n */\nexport function validDateInterval(startDate: Date, endDate: Date | undefined): boolean {\n return !endDate || endDate <= MIN_VALID_DATE || endDate > startDate;\n}\n"],"mappings":";;;AAKA,IAAa,iBAAiB;AAC9B,IAAa,kBAAkB;;AAG/B,IAAM,sBAAwD;CAC1D,MAAM;CACN,IAAI;CACJ,IAAI;AACR;AAEA,IAAM,aAAa;;AAGnB,IAAM,oBAAoB;;;;;AAM1B,IAAa,iCAAiB,IAAI,KAAK,YAAY;;AAGnD,SAAgB,YAAY,MAA6C;CACrE,OAAO,CAAC,CAAC,QAAQ,CAAC,OAAO,MAAM,KAAK,QAAQ,CAAC;AACjD;;;;;;AAOA,SAAgB,iBAAiB,MAAY,QAA2B;CACpE,OAAO,KAAK,mBAAmB,QAAQ;EAAE,KAAK;EAAW,OAAO;EAAW,MAAM;CAAU,CAAC;AAChG;;;;;;AAOA,SAAgB,iBAAiB,MAAY,QAA2B;CACpE,OAAO,KAAK,mBAAmB,QAAQ,EAAE,WAAW,QAAQ,CAAC;AACjE;;;;;;;AAQA,SAAgB,WAAW,MAA+B,SAAoB,gBAA+B;CACzG,OAAO,YAAY,IAAI,IAAI,iBAAiB,MAAM,MAAM,IAAI;AAChE;;AAGA,SAAS,eAAe,MAAoB;CAKxC,OAAO,GAJM,KAAK,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,GAAG,GAI7C,EAAK,IAHA,KAAK,SAAS,IAAI,EAAA,CAAG,SAAS,CAAC,CAAC,SAAS,GAAG,GAGzC,EAAM,GAFZ,KAAK,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,GAAG,GAEvB;AAC/B;;;;;;;AAQA,SAAgB,gBAAgB,MAA8C;CAC1E,OAAO,YAAY,IAAI,IAAI,eAAe,IAAI,IAAI;AACtD;;;;;;AAOA,SAAS,gBAAgB,QAAwB;CAC7C,MAAM,SAAS,OAAO,MAAM,UAAU,KAAK,CAAC;CAC5C,MAAM,kBAAkB,CAAC,SAAS,KAAK,OAAO,QAAQ,YAAY,EAAE,CAAC;CACrE,IAAI,OAAO,WAAW,KAAK,IAAI,IAAI,MAAM,CAAC,CAAC,SAAS,KAAK,CAAC,iBACtD,MAAM,IAAI,MAAM,4BAA4B,OAAO,uBAAuB;CAG9E,MAAM,kBAAkB,OAAO,QAAQ,uBAAuB,MAAM;CACpE,OAAO,IAAI,OAAO,IAAI,gBAAgB,QAAQ,aAAY,UAAS,oBAAoB,MAAM,EAAE,EAAE;AACrG;;;;;AAMA,SAAS,cAAc,MAAc,QAAsB;CACvD,MAAM,QAAQ,gBAAgB,MAAM,CAAC,CAAC,KAAK,IAAI,CAAC,EAAE;CAClD,IAAI,CAAC,OAAO,uBAAO,IAAI,KAAK,GAAG;CAE/B,MAAM,CAAC,MAAM,OAAO,OAAO;EAAC,OAAO,MAAM,IAAI;EAAG,OAAO,MAAM,KAAK;EAAG,OAAO,MAAM,GAAG;CAAC;CAGtF,MAAM,uBAAO,IAAI,KAAK,CAAC;CACvB,KAAK,YAAY,MAAM,QAAQ,GAAG,GAAG;CACrC,KAAK,SAAS,GAAG,GAAG,GAAG,CAAC;CAIxB,OADmB,KAAK,YAAY,MAAM,QAAQ,KAAK,SAAS,MAAM,QAAQ,KAAK,KAAK,QAAQ,MAAM,MAClF,uBAAO,IAAI,KAAK,GAAG;AAC3C;;;;;;;;AASA,SAAgB,UAAU,WAA2B,SAAiB,gBAA6B;CAC/F,IAAI,CAAC,WAAW,OAAO;CAEvB,OAAO,qBAAqB,OAAO,IAAI,KAAK,SAAS,IAAI,cAAc,WAAW,MAAM;AAC5F;;AAGA,SAAgB,sBAA8B;CAC1C,OAAO,+BAAe,IAAI,KAAK,CAAC,CAAC,CAAC,MAAM,GAAG,iBAAiB;AAChE;;;;;;;AAQA,SAAgB,kBAAkB,WAAiB,SAAoC;CACnF,OAAO,CAAC,WAAW,WAAW,kBAAkB,UAAU;AAC9D"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ifto/mantine-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "General purpose Mantine components for React apps: CRUD tables and forms, layout, ECharts charts, Excel/CSV export, print pages and a REST HTTP client, with i18n (en-US and pt-BR).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "IFTO - Campus Palmas",
|
|
@@ -72,7 +72,6 @@
|
|
|
72
72
|
"@tabler/icons-react": "^3.24.0",
|
|
73
73
|
"axios": "^1.20.0",
|
|
74
74
|
"clsx": "^2.1.1",
|
|
75
|
-
"dayjs": "^1.11.13",
|
|
76
75
|
"echarts": "^6.1.0",
|
|
77
76
|
"exceljs": "^4.4.0",
|
|
78
77
|
"mantine-datatable": "^9.4.0",
|