@manta-eu/react 0.7.0 → 0.8.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/dist/components/chart/ForecastChart.d.ts +41 -0
- package/dist/components/chart/ForecastChart.d.ts.map +1 -0
- package/dist/components/chart/ForecastChart.js +110 -0
- package/dist/components/chart/ForecastChart.js.map +1 -0
- package/dist/components/chart/ForecastEventCard.d.ts +28 -0
- package/dist/components/chart/ForecastEventCard.d.ts.map +1 -0
- package/dist/components/chart/ForecastEventCard.js +56 -0
- package/dist/components/chart/ForecastEventCard.js.map +1 -0
- package/dist/components/chart/ForecastHoverCard.d.ts +23 -0
- package/dist/components/chart/ForecastHoverCard.d.ts.map +1 -0
- package/dist/components/chart/ForecastHoverCard.js +22 -0
- package/dist/components/chart/ForecastHoverCard.js.map +1 -0
- package/dist/components/chart/ForecastLegend.d.ts +33 -0
- package/dist/components/chart/ForecastLegend.d.ts.map +1 -0
- package/dist/components/chart/ForecastLegend.js +38 -0
- package/dist/components/chart/ForecastLegend.js.map +1 -0
- package/dist/components/chart/forecast-model.d.ts +70 -0
- package/dist/components/chart/forecast-model.d.ts.map +1 -0
- package/dist/components/chart/forecast-model.js +89 -0
- package/dist/components/chart/forecast-model.js.map +1 -0
- package/dist/components/chart/forecast.d.ts +62 -0
- package/dist/components/chart/forecast.d.ts.map +1 -0
- package/dist/components/chart/forecast.js +90 -0
- package/dist/components/chart/forecast.js.map +1 -0
- package/dist/components/chart/index.d.ts +3 -0
- package/dist/components/chart/index.d.ts.map +1 -1
- package/dist/components/chart/index.js +1 -0
- package/dist/components/chart/index.js.map +1 -1
- package/dist/components/popover/index.d.ts +2 -1
- package/dist/components/popover/index.d.ts.map +1 -1
- package/dist/components/popover/index.js +2 -1
- package/dist/components/popover/index.js.map +1 -1
- package/dist/globals.css +58 -0
- package/dist/hooks/use-connection-problems.d.ts.map +1 -1
- package/dist/hooks/useAuth.d.ts +1 -0
- package/dist/hooks/useAuth.d.ts.map +1 -1
- package/dist/hooks/useAuth.js +1 -0
- package/dist/hooks/useAuth.js.map +1 -1
- package/dist/hooks/useValidateActionPlan.d.ts.map +1 -1
- package/dist/providers/AuthContext.d.ts +1 -0
- package/dist/providers/AuthContext.d.ts.map +1 -1
- package/dist/providers/AuthContext.js.map +1 -1
- package/package.json +8 -9
- package/src/components/chart/ForecastChart.tsx +383 -0
- package/src/components/chart/ForecastEventCard.tsx +163 -0
- package/src/components/chart/ForecastHoverCard.tsx +73 -0
- package/src/components/chart/ForecastLegend.tsx +97 -0
- package/src/components/chart/forecast-model.ts +130 -0
- package/src/components/chart/forecast.ts +144 -0
- package/src/components/chart/index.tsx +3 -0
- package/src/components/popover/index.tsx +2 -1
- package/src/globals.css +2 -0
- package/src/hooks/useAuth.ts +2 -0
- package/src/providers/AuthContext.ts +1 -0
- package/src/themes/manta-dark.css +2 -0
- package/src/themes/manta.css +2 -0
- package/src/themes/standard.css +2 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type ForecastEvent, type ForecastPlanShare } from "./forecast.js";
|
|
2
|
+
import { type ForecastBetween, type ForecastMetric } from "./forecast-model.js";
|
|
3
|
+
export type ForecastChartProps = {
|
|
4
|
+
/** One row per x value; each row carries `x` and a number per metric key. */
|
|
5
|
+
data: Record<string, unknown>[];
|
|
6
|
+
/** The x value of Today: lines are solid up to it and dotted after. Omit it for a history-only chart. */
|
|
7
|
+
today?: string | number;
|
|
8
|
+
metrics: ForecastMetric[];
|
|
9
|
+
/** Legend name of the shading between a metric and its `withoutPlans` line. */
|
|
10
|
+
gainLabel?: string;
|
|
11
|
+
/** A faint fill between two metrics, such as profit between revenue and costs. */
|
|
12
|
+
between?: ForecastBetween[];
|
|
13
|
+
goal?: {
|
|
14
|
+
value: number;
|
|
15
|
+
label: string;
|
|
16
|
+
};
|
|
17
|
+
events?: ForecastEvent[];
|
|
18
|
+
/** Called when an event's dot or its card link is chosen; without it, an event's `href` is a plain link. */
|
|
19
|
+
onEventSelect?: (event: ForecastEvent) => void;
|
|
20
|
+
/** The plans behind each projected point of a metric, shown in its hover card (the first two). */
|
|
21
|
+
planShares?: ForecastPlanShare[];
|
|
22
|
+
/** Formats axis ticks. */
|
|
23
|
+
formatValue?: (value: number) => string;
|
|
24
|
+
/** Formats the figures in the hover card. */
|
|
25
|
+
formatDetail?: (value: number) => string;
|
|
26
|
+
/** Follows the signed gap in the hover card: "+$2,664 with the plans". */
|
|
27
|
+
changeLabel?: string;
|
|
28
|
+
projectedLabel?: string;
|
|
29
|
+
/** The tag on the Today line. */
|
|
30
|
+
todayLabel?: string;
|
|
31
|
+
/** Legend names of the solid and dotted parts of a single metric. */
|
|
32
|
+
legendLabels?: {
|
|
33
|
+
historic?: string;
|
|
34
|
+
projected?: string;
|
|
35
|
+
};
|
|
36
|
+
title?: string;
|
|
37
|
+
height?: number;
|
|
38
|
+
className?: string;
|
|
39
|
+
};
|
|
40
|
+
export declare function ForecastChart(props: ForecastChartProps): import("react/jsx-runtime").JSX.Element;
|
|
41
|
+
//# sourceMappingURL=ForecastChart.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ForecastChart.d.ts","sourceRoot":"","sources":["../../../src/components/chart/ForecastChart.tsx"],"names":[],"mappings":"AAMA,OAAO,EAUL,KAAK,aAAa,EAElB,KAAK,iBAAiB,EACvB,MAAM,YAAY,CAAC;AACpB,OAAO,EAOL,KAAK,eAAe,EACpB,KAAK,cAAc,EACpB,MAAM,kBAAkB,CAAC;AAO1B,MAAM,MAAM,kBAAkB,GAAG;IAC/B,6EAA6E;IAC7E,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAChC,yGAAyG;IACzG,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,+EAA+E;IAC/E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kFAAkF;IAClF,OAAO,CAAC,EAAE,eAAe,EAAE,CAAC;IAC5B,IAAI,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACxC,MAAM,CAAC,EAAE,aAAa,EAAE,CAAC;IACzB,4GAA4G;IAC5G,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC/C,kGAAkG;IAClG,UAAU,CAAC,EAAE,iBAAiB,EAAE,CAAC;IACjC,0BAA0B;IAC1B,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACxC,6CAA6C;IAC7C,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACzC,0EAA0E;IAC1E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iCAAiC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qEAAqE;IACrE,YAAY,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACzD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AA6BF,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,2CA+RtD"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { isPresent } from "@manta-eu/lib/present";
|
|
3
|
+
import { useEffect, useId, useMemo, useRef, useState } from "react";
|
|
4
|
+
import { Area, CartesianGrid, ComposedChart, Line, ReferenceDot, ReferenceLine, XAxis, YAxis } from "recharts";
|
|
5
|
+
import { renderAnnotations } from "./annotations.js";
|
|
6
|
+
import { ChartTooltip } from "./chart.js";
|
|
7
|
+
import { ChartFrame } from "./ChartFrame.js";
|
|
8
|
+
import { forecastMargin, forecastXAxisHeight, formatCompact, formatWhole, nearestMetric, partKey, plotGeometry, rangeKey, valueAtY, } from "./forecast.js";
|
|
9
|
+
import { betweenName, buildForecastModel, forecastParts as parts, gainName, metricColor, withoutColor, } from "./forecast-model.js";
|
|
10
|
+
import { ForecastEventCard, ForecastEventDot } from "./ForecastEventCard.js";
|
|
11
|
+
import { ForecastHoverCard } from "./ForecastHoverCard.js";
|
|
12
|
+
import { ForecastLegend } from "./ForecastLegend.js";
|
|
13
|
+
import { Popover, PopoverAnchor } from "#components/popover/index";
|
|
14
|
+
import { cn } from "#style";
|
|
15
|
+
const projectedDash = "0.5 6";
|
|
16
|
+
const noBetween = [];
|
|
17
|
+
const noEvents = [];
|
|
18
|
+
const noPlanShares = [];
|
|
19
|
+
function TodayTag(props) {
|
|
20
|
+
const { text, viewBox } = props;
|
|
21
|
+
if (viewBox?.x === undefined || viewBox.y === undefined) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
return (_jsx("foreignObject", { x: viewBox.x - 100, y: viewBox.y, width: 200, height: 20, className: "pointer-events-none overflow-visible", children: _jsx("div", { className: "flex justify-center", children: _jsx("span", { className: "h-5 rounded-full border border-default-border bg-card px-2 typography-tiny-medium leading-5 text-default-foreground", children: text }) }) }));
|
|
25
|
+
}
|
|
26
|
+
export function ForecastChart(props) {
|
|
27
|
+
const { data, today, metrics, gainLabel = "Added by plans", between = noBetween, goal, events = noEvents, onEventSelect, planShares = noPlanShares, formatValue = formatCompact, formatDetail = formatWhole, changeLabel = "with the plans", projectedLabel = "projected", todayLabel = "Today", legendLabels, title, height = 320, className, } = props;
|
|
28
|
+
const id = useId().replace(/:/g, "");
|
|
29
|
+
const fadeId = `forecast-fade-${id}`;
|
|
30
|
+
const cardId = `forecast-event-${id}`;
|
|
31
|
+
const plotRef = useRef(null);
|
|
32
|
+
const closeTimer = useRef(undefined);
|
|
33
|
+
const [activeEvent, setActiveEvent] = useState();
|
|
34
|
+
const [focusKey, setFocusKey] = useState();
|
|
35
|
+
const model = useMemo(() => buildForecastModel({
|
|
36
|
+
data,
|
|
37
|
+
...(today === undefined ? {} : { today }),
|
|
38
|
+
metrics,
|
|
39
|
+
between,
|
|
40
|
+
gainLabel,
|
|
41
|
+
...(goal ? { goal } : {}),
|
|
42
|
+
...(legendLabels ? { legendLabels } : {}),
|
|
43
|
+
}), [data, today, metrics, between, goal, gainLabel, legendLabels]);
|
|
44
|
+
const emptyKeys = model.emptyKeys.join(", ");
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
if (isPresent(emptyKeys)) {
|
|
47
|
+
console.warn(`ForecastChart: no numbers in data for ${emptyKeys}; check the metric keys`);
|
|
48
|
+
}
|
|
49
|
+
}, [emptyKeys]);
|
|
50
|
+
const missingToday = model.todayMissing ? String(today) : "";
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
if (isPresent(missingToday)) {
|
|
53
|
+
console.warn(`ForecastChart: today "${missingToday}" matches no row's x; the Today line and projection are hidden`);
|
|
54
|
+
}
|
|
55
|
+
}, [missingToday]);
|
|
56
|
+
const { overlay, withPlans, rows, domain, ticks, firstColor } = model;
|
|
57
|
+
const gainOpacity = overlay ? { past: 0.5, ahead: 0.34 } : { past: 0.24, ahead: 0.14 };
|
|
58
|
+
const betweenOpacity = { past: 0.08, ahead: 0.05 };
|
|
59
|
+
const geometry = plotGeometry(height);
|
|
60
|
+
const focusedMetric = model.hoverMetrics.find((metric) => metric.key === focusKey) ?? model.hoverMetrics[0];
|
|
61
|
+
function followPointer(state) {
|
|
62
|
+
const row = state.activePayload?.[0]?.payload;
|
|
63
|
+
if (state.chartY === undefined || row === undefined) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const nearest = nearestMetric(row, metrics.map((metric) => metric.key), valueAtY(state.chartY, geometry.top, geometry.height, domain));
|
|
67
|
+
if (nearest !== focusKey) {
|
|
68
|
+
setFocusKey(nearest);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function cancelClose() {
|
|
72
|
+
clearTimeout(closeTimer.current);
|
|
73
|
+
}
|
|
74
|
+
function closeSoon() {
|
|
75
|
+
cancelClose();
|
|
76
|
+
closeTimer.current = setTimeout(() => setActiveEvent(undefined), 150);
|
|
77
|
+
}
|
|
78
|
+
function closeUnlessInside(next) {
|
|
79
|
+
const inside = [plotRef.current, document.getElementById(cardId)].some((container) => next instanceof Node && container?.contains(next));
|
|
80
|
+
if (!inside) {
|
|
81
|
+
setActiveEvent(undefined);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function showEvent(index, cx, cy) {
|
|
85
|
+
cancelClose();
|
|
86
|
+
setActiveEvent({ index, cx, cy });
|
|
87
|
+
}
|
|
88
|
+
function rangeArea(name, part, color, opacity) {
|
|
89
|
+
return (_jsx(Area, { dataKey: rangeKey(name, part), type: "monotone", fill: color, fillOpacity: opacity, stroke: "none", tooltipType: "none", activeDot: false, isAnimationActive: false }, rangeKey(name, part)));
|
|
90
|
+
}
|
|
91
|
+
function line(key, part, color, width, withPlans) {
|
|
92
|
+
const activeDot = { r: 3.5, fill: color, stroke: "var(--color-card)", strokeWidth: 1.5 };
|
|
93
|
+
return (_jsx(Line, { dataKey: partKey(key, part), type: "monotone", stroke: color, strokeWidth: width, strokeLinejoin: "round", strokeLinecap: "round", strokeDasharray: part === "ahead" && withPlans ? projectedDash : undefined, dot: false, activeDot: activeEvent ? false : activeDot, tooltipType: "none", isAnimationActive: false }, partKey(key, part)));
|
|
94
|
+
}
|
|
95
|
+
const shownEvent = activeEvent ? events[activeEvent.index] : undefined;
|
|
96
|
+
return (_jsxs("div", { className: cn("w-full", className), children: [isPresent(title) ? (_jsx("p", { className: "typography-small-medium mb-2 text-center text-default-foreground", children: title })) : null, _jsx(ForecastLegend, { items: model.legendItems }), _jsxs("div", { ref: plotRef, className: "relative", children: [_jsx(ChartFrame, { config: model.config, height: height, children: _jsxs(ComposedChart, { accessibilityLayer: true, data: rows, margin: forecastMargin, onMouseMove: followPointer, children: [_jsx("defs", { children: _jsxs("linearGradient", { id: fadeId, x1: "0", y1: "0", x2: "0", y2: "1", children: [_jsx("stop", { offset: "0%", stopColor: model.fadeColor, stopOpacity: overlay ? 0.3 : 0.34 }), _jsx("stop", { offset: "100%", stopColor: model.fadeColor, stopOpacity: 0 })] }) }), _jsx(CartesianGrid, { vertical: false, strokeDasharray: "2 3" }), _jsx(XAxis, { dataKey: "x", height: forecastXAxisHeight, tickLine: false, axisLine: false, tickMargin: 12, minTickGap: 24 }), _jsx(YAxis, { tickLine: false, axisLine: false, width: 56, domain: domain, ticks: ticks, interval: 0, tickFormatter: formatValue, allowDataOverflow: true }), model.fadeKeys.map(({ part, key }) => (_jsx(Area, { dataKey: partKey(key, part), baseValue: "dataMin", type: "monotone", stroke: "none", fill: `url(#${fadeId})`, tooltipType: "none", activeDot: false, isAnimationActive: false }, `fade-${part}`))), between.flatMap((_, index) => parts.map((part) => rangeArea(betweenName(index), part, firstColor, betweenOpacity[part]))), withPlans.flatMap((entry) => parts.map((part) => rangeArea(gainName(entry.index), part, metricColor(entry.metric, entry.index), gainOpacity[part]))), isPresent(goal)
|
|
97
|
+
? renderAnnotations([
|
|
98
|
+
{ kind: "reference-line", axis: "y", value: goal.value, label: goal.label, tone: "neutral" },
|
|
99
|
+
])
|
|
100
|
+
: null, model.todayIndex >= 0 && today !== undefined ? (_jsx(ReferenceLine, { x: today, stroke: "var(--color-default-foreground)", strokeOpacity: 0.4, label: _jsx(TodayTag, { text: todayLabel }) })) : null, _jsx(ChartTooltip, { active: shownEvent ? false : undefined, cursor: { stroke: "var(--color-default-border)" }, content: _jsx(ForecastHoverCard, { metric: focusedMetric, formatDetail: formatDetail, changeLabel: changeLabel, projectedLabel: projectedLabel, planShares: planShares }) }), withPlans.flatMap((entry) => parts.map((part) => line(entry.without.key, part, withoutColor, overlay ? 1.5 : 2, false))), metrics.flatMap((metric, index) => ["ahead", "past"].map((part) => line(metric.key, part, metricColor(metric, index), index === 0 ? 2.5 : 2.25, true))), events.map((event, index) => {
|
|
101
|
+
const metricIndex = metrics.findIndex((metric) => metric.key === event.metric);
|
|
102
|
+
const metric = metrics[metricIndex];
|
|
103
|
+
const value = data.find((row) => row.x === event.x)?.[event.metric];
|
|
104
|
+
if (typeof value !== "number" || metric === undefined) {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
return (_jsx(ReferenceDot, { x: event.x, y: value, shape: (dot) => (_jsx(ForecastEventDot, { event: event, color: metricColor(metric, metricIndex), ...(dot.cx === undefined ? {} : { cx: dot.cx }), ...(dot.cy === undefined ? {} : { cy: dot.cy }), active: activeEvent?.index === index, cardId: cardId, ...(onEventSelect ? { onSelect: onEventSelect } : {}), onShow: (cx, cy) => showEvent(index, cx, cy), onLeave: closeSoon, onBlur: closeUnlessInside })) }, `${event.metric}-${event.x}-${event.title}`));
|
|
108
|
+
})] }) }), _jsxs(Popover, { open: shownEvent !== undefined, onOpenChange: (open) => !open && setActiveEvent(undefined), children: [_jsx(PopoverAnchor, { asChild: true, children: _jsx("span", { "aria-hidden": "true", className: "pointer-events-none absolute size-0", style: { left: activeEvent?.cx ?? 0, top: activeEvent?.cy ?? 0 } }) }), shownEvent ? (_jsx(ForecastEventCard, { event: shownEvent, id: cardId, ...(onEventSelect ? { onSelect: onEventSelect } : {}), onEnter: cancelClose, onLeave: closeSoon, onBlur: closeUnlessInside })) : null] }, activeEvent?.index)] })] }));
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=ForecastChart.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ForecastChart.js","sourceRoot":"","sources":["../../../src/components/chart/ForecastChart.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ForecastEvent } from "./forecast.js";
|
|
2
|
+
export declare function eventLabel(event: ForecastEvent): string;
|
|
3
|
+
type ForecastEventDotProps = {
|
|
4
|
+
event: ForecastEvent;
|
|
5
|
+
color: string;
|
|
6
|
+
cx?: number;
|
|
7
|
+
cy?: number;
|
|
8
|
+
active: boolean;
|
|
9
|
+
cardId: string;
|
|
10
|
+
onSelect?: (event: ForecastEvent) => void;
|
|
11
|
+
onShow: (cx: number, cy: number) => void;
|
|
12
|
+
onLeave: () => void;
|
|
13
|
+
onBlur: (next: EventTarget | null) => void;
|
|
14
|
+
};
|
|
15
|
+
/** A dot on a metric's line. With `onSelect` it acts on click or Enter; otherwise an `href` makes it a plain link. */
|
|
16
|
+
export declare function ForecastEventDot(props: ForecastEventDotProps): import("react/jsx-runtime").JSX.Element | null;
|
|
17
|
+
type ForecastEventCardProps = {
|
|
18
|
+
event: ForecastEvent;
|
|
19
|
+
id: string;
|
|
20
|
+
onSelect?: (event: ForecastEvent) => void;
|
|
21
|
+
onEnter: () => void;
|
|
22
|
+
onLeave: () => void;
|
|
23
|
+
onBlur: (next: EventTarget | null) => void;
|
|
24
|
+
};
|
|
25
|
+
/** The dark card over a dot: its label, title, value and, with an `href`, an "Open plan" link. */
|
|
26
|
+
export declare function ForecastEventCard(props: ForecastEventCardProps): import("react/jsx-runtime").JSX.Element;
|
|
27
|
+
export {};
|
|
28
|
+
//# sourceMappingURL=ForecastEventCard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ForecastEventCard.d.ts","sourceRoot":"","sources":["../../../src/components/chart/ForecastEventCard.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAShD,wBAAgB,UAAU,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAEvD;AAED,KAAK,qBAAqB,GAAG;IAC3B,KAAK,EAAE,aAAa,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC1C,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,MAAM,EAAE,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAC;CAC5C,CAAC;AAEF,sHAAsH;AACtH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,kDAoE5D;AAED,KAAK,sBAAsB,GAAG;IAC5B,KAAK,EAAE,aAAa,CAAC;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC1C,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,MAAM,EAAE,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAC;CAC5C,CAAC;AAEF,kGAAkG;AAClG,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,2CAoD9D"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { isPresent } from "@manta-eu/lib/present";
|
|
3
|
+
import { ArrowUpRight } from "lucide-react";
|
|
4
|
+
import { PopoverArrow, PopoverContent } from "#components/popover/index";
|
|
5
|
+
import { cn } from "#style";
|
|
6
|
+
const eventLabels = {
|
|
7
|
+
applied: "Applied",
|
|
8
|
+
waiting: "Waiting for your approval",
|
|
9
|
+
};
|
|
10
|
+
export function eventLabel(event) {
|
|
11
|
+
return event.label ?? eventLabels[event.status];
|
|
12
|
+
}
|
|
13
|
+
/** A dot on a metric's line. With `onSelect` it acts on click or Enter; otherwise an `href` makes it a plain link. */
|
|
14
|
+
export function ForecastEventDot(props) {
|
|
15
|
+
const { event, color, cx, cy, active, cardId, onSelect, onShow, onLeave, onBlur } = props;
|
|
16
|
+
if (cx === undefined || cy === undefined) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
const label = `${eventLabel(event)}: ${event.title}`;
|
|
20
|
+
const waiting = event.status === "waiting";
|
|
21
|
+
const circles = (_jsxs(_Fragment, { children: [_jsx("circle", { cx: cx, cy: cy, r: 14, fill: "transparent" }), _jsx("circle", { cx: cx, cy: cy, r: 10, fill: color, className: cn("opacity-0 transition-opacity group-hover/event:opacity-20 group-focus-visible/event:opacity-35", active && "opacity-20") }), _jsx("circle", { cx: cx, cy: cy, r: active ? 6.5 : 5, fill: waiting ? "var(--color-card)" : color, stroke: waiting ? color : "var(--color-card)", strokeWidth: 2 })] }));
|
|
22
|
+
const shared = {
|
|
23
|
+
"aria-label": label,
|
|
24
|
+
"aria-describedby": active ? cardId : undefined,
|
|
25
|
+
className: "group/event cursor-pointer outline-none",
|
|
26
|
+
onMouseEnter: () => onShow(cx, cy),
|
|
27
|
+
onMouseLeave: onLeave,
|
|
28
|
+
onFocus: () => onShow(cx, cy),
|
|
29
|
+
onBlur: (focusEvent) => onBlur(focusEvent.relatedTarget),
|
|
30
|
+
};
|
|
31
|
+
if (onSelect === undefined && isPresent(event.href)) {
|
|
32
|
+
return (_jsx("a", { href: event.href, ...shared, children: circles }));
|
|
33
|
+
}
|
|
34
|
+
if (onSelect === undefined) {
|
|
35
|
+
return (_jsx("g", { role: "img", tabIndex: 0, ...shared, className: "group/event outline-none", children: circles }));
|
|
36
|
+
}
|
|
37
|
+
function handleKeyDown(keyEvent) {
|
|
38
|
+
if (keyEvent.key === "Enter" || keyEvent.key === " ") {
|
|
39
|
+
keyEvent.preventDefault();
|
|
40
|
+
onSelect?.(event);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return (_jsx("g", { role: "button", tabIndex: 0, ...shared, onClick: () => onSelect(event), onKeyDown: handleKeyDown, children: circles }));
|
|
44
|
+
}
|
|
45
|
+
/** The dark card over a dot: its label, title, value and, with an `href`, an "Open plan" link. */
|
|
46
|
+
export function ForecastEventCard(props) {
|
|
47
|
+
const { event, id, onSelect, onEnter, onLeave, onBlur } = props;
|
|
48
|
+
const link = isPresent(event.href) ? (_jsxs("a", { href: event.href, onClick: (clickEvent) => {
|
|
49
|
+
if (onSelect) {
|
|
50
|
+
clickEvent.preventDefault();
|
|
51
|
+
onSelect(event);
|
|
52
|
+
}
|
|
53
|
+
}, className: "mt-1 inline-flex items-center gap-1 self-start typography-small underline underline-offset-2", children: [event.linkLabel ?? "Open plan", _jsx(ArrowUpRight, { className: "size-3.5", "aria-hidden": "true" })] })) : null;
|
|
54
|
+
return (_jsxs(PopoverContent, { id: id, role: isPresent(event.href) ? undefined : "tooltip", side: "top", sideOffset: 12, collisionPadding: 8, onOpenAutoFocus: (focusEvent) => focusEvent.preventDefault(), onCloseAutoFocus: (focusEvent) => focusEvent.preventDefault(), className: cn("flex w-max min-w-50 max-w-65 flex-col gap-1 rounded-md-v4 border-0 px-3.5 pt-2.5 pb-3", "bg-inverse text-inverse-foreground shadow-xl ring-1 ring-inverse-foreground/10", !isPresent(event.href) && "pointer-events-none"), onMouseEnter: onEnter, onMouseLeave: onLeave, onBlur: (focusEvent) => onBlur(focusEvent.relatedTarget), children: [_jsx("span", { className: "typography-tiny opacity-70", children: eventLabel(event) }), _jsx("strong", { className: "typography-body-medium", children: event.title }), isPresent(event.value) ? (_jsxs("span", { className: "typography-small-semibold tabular-nums", style: { color: "color-mix(in srgb, var(--color-accent-foreground) 55%, var(--color-inverse-foreground))" }, children: [event.value, isPresent(event.valueNote) ? (_jsx("small", { className: "ml-1 typography-tiny opacity-70", children: event.valueNote })) : null] })) : null, link, _jsx(PopoverArrow, { className: "fill-inverse", width: 12, height: 6 })] }));
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=ForecastEventCard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ForecastEventCard.js","sourceRoot":"","sources":["../../../src/components/chart/ForecastEventCard.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type ForecastPlanShare } from "./forecast.js";
|
|
2
|
+
export type ForecastHoverMetric = {
|
|
3
|
+
key: string;
|
|
4
|
+
label: string;
|
|
5
|
+
withoutKey?: string;
|
|
6
|
+
lowerIsBetter: boolean;
|
|
7
|
+
};
|
|
8
|
+
type ForecastHoverCardProps = {
|
|
9
|
+
metric: ForecastHoverMetric | undefined;
|
|
10
|
+
formatDetail: (value: number) => string;
|
|
11
|
+
changeLabel: string;
|
|
12
|
+
projectedLabel: string;
|
|
13
|
+
planShares: readonly ForecastPlanShare[];
|
|
14
|
+
active?: boolean;
|
|
15
|
+
label?: string | number;
|
|
16
|
+
payload?: {
|
|
17
|
+
payload?: Record<string, unknown>;
|
|
18
|
+
}[];
|
|
19
|
+
};
|
|
20
|
+
/** The card for the line under the pointer: its figure and, when projected, the gap and the plans behind it. */
|
|
21
|
+
export declare function ForecastHoverCard(props: ForecastHoverCardProps): import("react/jsx-runtime").JSX.Element | null;
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=ForecastHoverCard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ForecastHoverCard.d.ts","sourceRoot":"","sources":["../../../src/components/chart/ForecastHoverCard.tsx"],"names":[],"mappings":"AACA,OAAO,EAAuC,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAGzF,MAAM,MAAM,mBAAmB,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,OAAO,CAAA;CAAE,CAAC;AAE9G,KAAK,sBAAsB,GAAG;IAC5B,MAAM,EAAE,mBAAmB,GAAG,SAAS,CAAC;IACxC,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACxC,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACzC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,EAAE,CAAC;CACnD,CAAC;AAEF,gHAAgH;AAChH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,kDAsD9D"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { isPresent } from "@manta-eu/lib/present";
|
|
3
|
+
import { plansAt, projectedKey, signedChange } from "./forecast.js";
|
|
4
|
+
import { cn } from "#style";
|
|
5
|
+
/** The card for the line under the pointer: its figure and, when projected, the gap and the plans behind it. */
|
|
6
|
+
export function ForecastHoverCard(props) {
|
|
7
|
+
const { metric, formatDetail, changeLabel, projectedLabel, planShares, active, label, payload } = props;
|
|
8
|
+
const row = payload?.[0]?.payload;
|
|
9
|
+
const value = metric === undefined ? undefined : row?.[metric.key];
|
|
10
|
+
if (active !== true || row === undefined || metric === undefined || typeof value !== "number") {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
const projected = row[projectedKey] === true;
|
|
14
|
+
const without = isPresent(metric.withoutKey) ? row[metric.withoutKey] : undefined;
|
|
15
|
+
const x = row.x;
|
|
16
|
+
function helps(change) {
|
|
17
|
+
return metric?.lowerIsBetter === true ? change <= 0 : change >= 0;
|
|
18
|
+
}
|
|
19
|
+
const plans = projected && (typeof x === "string" || typeof x === "number") ? plansAt(planShares, x, metric.key).slice(0, 2) : [];
|
|
20
|
+
return (_jsxs("div", { className: "min-w-50 max-w-75 rounded-md-v4 border border-default-border bg-card px-3 py-2.5 text-default-foreground shadow-xl", children: [_jsxs("p", { className: "mb-1.5 typography-tiny text-muted-foreground", children: [label, projected ? ` · ${projectedLabel}` : ""] }), _jsxs("p", { className: "flex items-baseline justify-between gap-4 typography-small text-muted-foreground", children: [_jsx("span", { children: metric.label }), _jsx("strong", { className: "typography-body-semibold tabular-nums text-default-foreground", children: formatDetail(value) })] }), projected && typeof without === "number" ? (_jsxs("p", { className: cn("typography-small-medium tabular-nums", helps(value - without) ? "text-accent-foreground" : "text-muted-foreground"), children: [signedChange(value, without, formatDetail), " ", changeLabel] })) : null, isPresent(plans) ? (_jsx("div", { className: "mt-2 grid gap-0.5 border-t border-default-border pt-2", children: plans.map((plan) => (_jsxs("p", { className: "flex items-baseline justify-between gap-3 typography-tiny", children: [_jsx("span", { className: "min-w-0", children: plan.label }), _jsx("strong", { className: cn("flex-none typography-tiny-semibold tabular-nums", helps(plan.value) ? "text-accent-foreground" : "text-muted-foreground"), children: signedChange(plan.value, 0, formatDetail) })] }, plan.label))) })) : null] }));
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=ForecastHoverCard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ForecastHoverCard.js","sourceRoot":"","sources":["../../../src/components/chart/ForecastHoverCard.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export type ForecastLegendItem = {
|
|
2
|
+
label: string;
|
|
3
|
+
color: string;
|
|
4
|
+
kind: "line" | "dotted-line" | "thin-line" | "fill" | "faint-fill";
|
|
5
|
+
};
|
|
6
|
+
type LegendSource = {
|
|
7
|
+
metrics: {
|
|
8
|
+
label: string;
|
|
9
|
+
color: string;
|
|
10
|
+
}[];
|
|
11
|
+
withoutLabels: string[];
|
|
12
|
+
/** The metrics with a `withoutPlans` line and the color their gain is shaded in. */
|
|
13
|
+
gains: {
|
|
14
|
+
metric: string;
|
|
15
|
+
color: string;
|
|
16
|
+
}[];
|
|
17
|
+
gainLabel: string;
|
|
18
|
+
betweenLabels: string[];
|
|
19
|
+
firstColor: string;
|
|
20
|
+
withoutColor: string;
|
|
21
|
+
hasProjection: boolean;
|
|
22
|
+
legendLabels?: {
|
|
23
|
+
historic?: string;
|
|
24
|
+
projected?: string;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
/** Two metrics are named per line; a single metric is split into its historic and projected parts instead. */
|
|
28
|
+
export declare function forecastLegendItems(source: LegendSource): ForecastLegendItem[];
|
|
29
|
+
export declare function ForecastLegend(props: {
|
|
30
|
+
items: ForecastLegendItem[];
|
|
31
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
32
|
+
export {};
|
|
33
|
+
//# sourceMappingURL=ForecastLegend.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ForecastLegend.d.ts","sourceRoot":"","sources":["../../../src/components/chart/ForecastLegend.tsx"],"names":[],"mappings":"AAEA,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,WAAW,GAAG,MAAM,GAAG,YAAY,CAAC;CACpE,CAAC;AAEF,KAAK,YAAY,GAAG;IAClB,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC5C,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,oFAAoF;IACpF,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1D,CAAC;AAEF,8GAA8G;AAC9G,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,YAAY,GAAG,kBAAkB,EAAE,CA2C9E;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE;IAAE,KAAK,EAAE,kBAAkB,EAAE,CAAA;CAAE,2CA6BpE"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "#style";
|
|
3
|
+
/** Two metrics are named per line; a single metric is split into its historic and projected parts instead. */
|
|
4
|
+
export function forecastLegendItems(source) {
|
|
5
|
+
const { metrics, withoutLabels, gains, gainLabel, betweenLabels, firstColor, withoutColor, hasProjection, legendLabels, } = source;
|
|
6
|
+
const withoutItems = [...new Set(withoutLabels)].map((label) => ({ label, color: withoutColor, kind: "thin-line" }));
|
|
7
|
+
const oneGainColor = new Set(gains.map((gain) => gain.color)).size === 1;
|
|
8
|
+
const gainItems = (oneGainColor ? gains.slice(0, 1) : gains).map((gain) => ({
|
|
9
|
+
label: oneGainColor ? gainLabel : `${gainLabel} · ${gain.metric}`,
|
|
10
|
+
color: gain.color,
|
|
11
|
+
kind: "fill",
|
|
12
|
+
}));
|
|
13
|
+
const betweenItems = betweenLabels.map((label) => ({ label, color: firstColor, kind: "faint-fill" }));
|
|
14
|
+
if (metrics.length > 1) {
|
|
15
|
+
return [
|
|
16
|
+
...metrics.map((metric) => ({ label: metric.label, color: metric.color, kind: "line" })),
|
|
17
|
+
...betweenItems,
|
|
18
|
+
...gainItems,
|
|
19
|
+
...withoutItems,
|
|
20
|
+
];
|
|
21
|
+
}
|
|
22
|
+
return [
|
|
23
|
+
{ label: legendLabels?.historic ?? "Historic results", color: firstColor, kind: "line" },
|
|
24
|
+
...(hasProjection
|
|
25
|
+
? [{ label: legendLabels?.projected ?? "Projected results", color: firstColor, kind: "dotted-line" }]
|
|
26
|
+
: []),
|
|
27
|
+
...withoutItems,
|
|
28
|
+
...gainItems,
|
|
29
|
+
...betweenItems,
|
|
30
|
+
];
|
|
31
|
+
}
|
|
32
|
+
export function ForecastLegend(props) {
|
|
33
|
+
const { items } = props;
|
|
34
|
+
return (_jsx("ul", { className: "m-0 mb-3 flex list-none flex-wrap gap-x-6 gap-y-2 p-0 typography-small text-muted-foreground", children: items.map((item) => (_jsxs("li", { className: "inline-flex items-center gap-2", children: [item.kind === "fill" || item.kind === "faint-fill" ? (_jsx("span", { className: "h-2.5 w-4 rounded-xs-v4", style: {
|
|
35
|
+
background: `color-mix(in srgb, ${item.color} ${item.kind === "fill" ? 42 : 10}%, transparent)`,
|
|
36
|
+
} })) : (_jsx("span", { className: cn("w-5 rounded-sm", item.kind === "line" && "border-t-[2.5px]", item.kind === "dotted-line" && "border-t-[3px] border-dotted", item.kind === "thin-line" && "border-t-2"), style: { borderColor: item.color } })), item.label] }, item.label))) }));
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=ForecastLegend.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ForecastLegend.js","sourceRoot":"","sources":["../../../src/components/chart/ForecastLegend.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { ForecastHoverMetric } from "./ForecastHoverCard.js";
|
|
2
|
+
export type ForecastMetric = {
|
|
3
|
+
key: string;
|
|
4
|
+
label: string;
|
|
5
|
+
color?: string;
|
|
6
|
+
/** For costs: a drop with the plans shows as a gain in the hover card. */
|
|
7
|
+
lowerIsBetter?: boolean;
|
|
8
|
+
/** The same metric if the plans are not approved; the gap between the two is shaded as what the plans add. */
|
|
9
|
+
withoutPlans?: {
|
|
10
|
+
key: string;
|
|
11
|
+
label: string;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
export type ForecastBetween = {
|
|
15
|
+
from: string;
|
|
16
|
+
to: string;
|
|
17
|
+
label: string;
|
|
18
|
+
};
|
|
19
|
+
export declare const forecastParts: readonly ["past", "ahead"];
|
|
20
|
+
export declare const withoutColor = "color-mix(in srgb, var(--color-muted-foreground) 82%, var(--color-card))";
|
|
21
|
+
export declare function metricColor(metric: ForecastMetric, index: number): string;
|
|
22
|
+
export declare function gainName(index: number): string;
|
|
23
|
+
export declare function betweenName(index: number): string;
|
|
24
|
+
type ModelInput = {
|
|
25
|
+
data: Record<string, unknown>[];
|
|
26
|
+
today?: string | number;
|
|
27
|
+
metrics: ForecastMetric[];
|
|
28
|
+
between: ForecastBetween[];
|
|
29
|
+
goal?: {
|
|
30
|
+
value: number;
|
|
31
|
+
};
|
|
32
|
+
gainLabel: string;
|
|
33
|
+
legendLabels?: {
|
|
34
|
+
historic?: string;
|
|
35
|
+
projected?: string;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
/** Everything the chart draws, derived once from its props: split rows, axis, fades, legend and hover metrics. */
|
|
39
|
+
export declare function buildForecastModel(input: ModelInput): {
|
|
40
|
+
emptyKeys: string[];
|
|
41
|
+
todayMissing: boolean;
|
|
42
|
+
overlay: boolean;
|
|
43
|
+
todayIndex: number;
|
|
44
|
+
withPlans: {
|
|
45
|
+
metric: ForecastMetric;
|
|
46
|
+
index: number;
|
|
47
|
+
without: {
|
|
48
|
+
key: string;
|
|
49
|
+
label: string;
|
|
50
|
+
};
|
|
51
|
+
}[];
|
|
52
|
+
rows: Record<string, unknown>[];
|
|
53
|
+
domain: [number, number];
|
|
54
|
+
ticks: number[];
|
|
55
|
+
fadeKeys: {
|
|
56
|
+
part: "past" | "ahead";
|
|
57
|
+
key: string;
|
|
58
|
+
}[];
|
|
59
|
+
fadeColor: string;
|
|
60
|
+
firstColor: string;
|
|
61
|
+
config: {
|
|
62
|
+
[k: string]: {
|
|
63
|
+
label: string;
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
hoverMetrics: ForecastHoverMetric[];
|
|
67
|
+
legendItems: import("./ForecastLegend.js").ForecastLegendItem[];
|
|
68
|
+
};
|
|
69
|
+
export {};
|
|
70
|
+
//# sourceMappingURL=forecast-model.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forecast-model.d.ts","sourceRoot":"","sources":["../../../src/components/chart/forecast-model.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAG/D,MAAM,MAAM,cAAc,GAAG;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0EAA0E;IAC1E,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,8GAA8G;IAC9G,YAAY,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/C,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1E,eAAO,MAAM,aAAa,4BAA6B,CAAC;AACxD,eAAO,MAAM,YAAY,6EAA6E,CAAC;AAMvG,wBAAgB,WAAW,CAAC,MAAM,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEzE;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,KAAK,UAAU,GAAG;IAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAChC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,IAAI,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1D,CAAC;AAEF,kHAAkH;AAClH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU;;;;;;;;;iBAnC5B,MAAM;mBAAS,MAAM;;;;;;;;;;;;;;;;;;;EAmH5C"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { isPresent } from "@manta-eu/lib/present";
|
|
2
|
+
import { chartColorAt } from "./chart-colors.js";
|
|
3
|
+
import { forecastDomain, partKey, splitAtToday } from "./forecast.js";
|
|
4
|
+
import { forecastLegendItems } from "./ForecastLegend.js";
|
|
5
|
+
export const forecastParts = ["past", "ahead"];
|
|
6
|
+
export const withoutColor = "color-mix(in srgb, var(--color-muted-foreground) 82%, var(--color-card))";
|
|
7
|
+
const metricColors = [
|
|
8
|
+
"var(--color-accent-foreground)",
|
|
9
|
+
"color-mix(in srgb, var(--color-accent-foreground) 45%, var(--color-muted-foreground))",
|
|
10
|
+
];
|
|
11
|
+
export function metricColor(metric, index) {
|
|
12
|
+
return metric.color ?? metricColors[index] ?? chartColorAt(index);
|
|
13
|
+
}
|
|
14
|
+
export function gainName(index) {
|
|
15
|
+
return `gain-${index}`;
|
|
16
|
+
}
|
|
17
|
+
export function betweenName(index) {
|
|
18
|
+
return `between-${index}`;
|
|
19
|
+
}
|
|
20
|
+
/** Everything the chart draws, derived once from its props: split rows, axis, fades, legend and hover metrics. */
|
|
21
|
+
export function buildForecastModel(input) {
|
|
22
|
+
const { data, today, metrics, between, goal, gainLabel, legendLabels } = input;
|
|
23
|
+
const overlay = metrics.length > 1;
|
|
24
|
+
const todayIndex = today === undefined ? -1 : data.findIndex((row) => row.x === today);
|
|
25
|
+
const withPlans = metrics.flatMap((metric, index) => isPresent(metric.withoutPlans) ? [{ metric, index, without: metric.withoutPlans }] : []);
|
|
26
|
+
const ranges = {
|
|
27
|
+
...Object.fromEntries(withPlans.map((entry) => [gainName(entry.index), { from: entry.without.key, to: entry.metric.key }])),
|
|
28
|
+
...Object.fromEntries(between.map((range, index) => [betweenName(index), range])),
|
|
29
|
+
};
|
|
30
|
+
const lineKeys = [...metrics.map((metric) => metric.key), ...withPlans.map((entry) => entry.without.key)];
|
|
31
|
+
const emptyKeys = lineKeys.filter((key) => !data.some((row) => typeof row[key] === "number"));
|
|
32
|
+
const rows = splitAtToday(data, todayIndex, lineKeys, ranges);
|
|
33
|
+
const values = data.flatMap((row) => lineKeys.map((key) => row[key])).filter((value) => typeof value === "number");
|
|
34
|
+
const { domain, ticks } = forecastDomain(isPresent(goal) ? [...values, goal.value] : values);
|
|
35
|
+
function meanOf(key) {
|
|
36
|
+
const numbers = data.map((row) => row[key]).filter((value) => typeof value === "number");
|
|
37
|
+
return numbers.reduce((sum, value) => sum + value, 0) / Math.max(numbers.length, 1);
|
|
38
|
+
}
|
|
39
|
+
const lowestIndex = metrics.reduce((lowest, metric, index) => (meanOf(metric.key) < meanOf(metrics[lowest]?.key ?? "") ? index : lowest), 0);
|
|
40
|
+
const lowestMetric = metrics[lowestIndex];
|
|
41
|
+
const onlyWithout = withPlans[0]?.without;
|
|
42
|
+
function drawsIn(key, part) {
|
|
43
|
+
return rows.filter((row) => typeof row[partKey(key, part)] === "number").length > 1;
|
|
44
|
+
}
|
|
45
|
+
const fadeKeys = forecastParts.flatMap((part) => {
|
|
46
|
+
const key = overlay
|
|
47
|
+
? lowestMetric?.key
|
|
48
|
+
: onlyWithout && drawsIn(onlyWithout.key, part)
|
|
49
|
+
? onlyWithout.key
|
|
50
|
+
: metrics[0]?.key;
|
|
51
|
+
return key === undefined ? [] : [{ part, key }];
|
|
52
|
+
});
|
|
53
|
+
const firstColor = metrics[0] ? metricColor(metrics[0], 0) : withoutColor;
|
|
54
|
+
return {
|
|
55
|
+
emptyKeys,
|
|
56
|
+
todayMissing: today !== undefined && todayIndex < 0 && isPresent(data),
|
|
57
|
+
overlay,
|
|
58
|
+
todayIndex,
|
|
59
|
+
withPlans,
|
|
60
|
+
rows,
|
|
61
|
+
domain,
|
|
62
|
+
ticks,
|
|
63
|
+
fadeKeys,
|
|
64
|
+
fadeColor: overlay && lowestMetric ? metricColor(lowestMetric, lowestIndex) : withoutColor,
|
|
65
|
+
firstColor,
|
|
66
|
+
config: Object.fromEntries([...metrics, ...withPlans.map((entry) => entry.without)].map((line) => [line.key, { label: line.label }])),
|
|
67
|
+
hoverMetrics: metrics.map((metric) => ({
|
|
68
|
+
key: metric.key,
|
|
69
|
+
label: metric.label,
|
|
70
|
+
lowerIsBetter: metric.lowerIsBetter === true,
|
|
71
|
+
...(isPresent(metric.withoutPlans) ? { withoutKey: metric.withoutPlans.key } : {}),
|
|
72
|
+
})),
|
|
73
|
+
legendItems: forecastLegendItems({
|
|
74
|
+
metrics: metrics.map((metric, index) => ({ label: metric.label, color: metricColor(metric, index) })),
|
|
75
|
+
withoutLabels: withPlans.map((entry) => entry.without.label),
|
|
76
|
+
gains: withPlans.map((entry) => ({
|
|
77
|
+
metric: entry.metric.label,
|
|
78
|
+
color: metricColor(entry.metric, entry.index),
|
|
79
|
+
})),
|
|
80
|
+
gainLabel,
|
|
81
|
+
betweenLabels: between.map((range) => range.label),
|
|
82
|
+
firstColor,
|
|
83
|
+
withoutColor,
|
|
84
|
+
hasProjection: todayIndex >= 0,
|
|
85
|
+
...(legendLabels ? { legendLabels } : {}),
|
|
86
|
+
}),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=forecast-model.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forecast-model.js","sourceRoot":"","sources":["../../../src/components/chart/forecast-model.ts"],"names":[],"mappings":"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"}
|