@epilot/spark-ui 0.20.0 → 0.20.1
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/accordion.cjs +2 -2
- package/dist/components/accordion.d.ts +1 -1
- package/dist/components/accordion.js +1 -1
- package/dist/components/alert-dialog.cjs +1 -1
- package/dist/components/alert-dialog.js +1 -1
- package/dist/components/autocomplete.cjs +1 -1
- package/dist/components/autocomplete.js +1 -1
- package/dist/components/bar-chart-with-total.d.cts +1 -1
- package/dist/components/bar-chart-with-total.d.ts +1 -1
- package/dist/components/bar-chart.cjs +1 -1
- package/dist/components/bar-chart.js +2 -2
- package/dist/components/calendar.cjs +1 -1
- package/dist/components/calendar.js +1 -1
- package/dist/components/callout.cjs +1 -1
- package/dist/components/callout.d.cts +1 -1
- package/dist/components/callout.d.ts +2 -2
- package/dist/components/callout.js +1 -1
- package/dist/components/dialog.cjs +1 -1
- package/dist/components/dialog.js +1 -1
- package/dist/components/dropdown-menu.cjs +1 -1
- package/dist/components/dropdown-menu.js +1 -1
- package/dist/components/empty-state.d.ts +1 -1
- package/dist/components/energy-breakdown.cjs +80 -0
- package/dist/components/energy-breakdown.cjs.map +1 -0
- package/dist/components/energy-breakdown.d.cts +24 -0
- package/dist/components/energy-breakdown.d.ts +24 -0
- package/dist/components/energy-breakdown.js +79 -0
- package/dist/components/energy-breakdown.js.map +1 -0
- package/dist/components/energy-history-chart.cjs +63 -0
- package/dist/components/energy-history-chart.cjs.map +1 -0
- package/dist/components/energy-history-chart.d.cts +64 -0
- package/dist/components/energy-history-chart.d.ts +64 -0
- package/dist/components/energy-history-chart.js +62 -0
- package/dist/components/energy-history-chart.js.map +1 -0
- package/dist/components/entity-card.d.ts +1 -1
- package/dist/components/input-date.cjs +1 -1
- package/dist/components/input-date.js +1 -1
- package/dist/components/input-group.d.cts +1 -1
- package/dist/components/input-group.d.ts +1 -1
- package/dist/components/line-chart.cjs +3 -3
- package/dist/components/line-chart.js +4 -4
- package/dist/components/message-scroller.cjs +2 -2
- package/dist/components/message-scroller.js +2 -2
- package/dist/components/number-flow.d.cts +2 -12
- package/dist/components/number-flow.d.ts +2 -12
- package/dist/components/page-header.cjs +1 -1
- package/dist/components/page-header.js +1 -1
- package/dist/components/pill.cjs +1 -1
- package/dist/components/pill.js +1 -1
- package/dist/components/power-history-chart.cjs +498 -0
- package/dist/components/power-history-chart.cjs.map +1 -0
- package/dist/components/power-history-chart.d.cts +71 -0
- package/dist/components/power-history-chart.d.ts +71 -0
- package/dist/components/power-history-chart.js +496 -0
- package/dist/components/power-history-chart.js.map +1 -0
- package/dist/components/power-network.cjs +559 -0
- package/dist/components/power-network.cjs.map +1 -0
- package/dist/components/power-network.d.cts +80 -0
- package/dist/components/power-network.d.ts +80 -0
- package/dist/components/power-network.js +553 -0
- package/dist/components/power-network.js.map +1 -0
- package/dist/components/sankey-chart.cjs +11 -1
- package/dist/components/sankey-chart.cjs.map +1 -1
- package/dist/components/sankey-chart.d.cts +3 -2
- package/dist/components/sankey-chart.d.ts +3 -2
- package/dist/components/sankey-chart.js +11 -2
- package/dist/components/sankey-chart.js.map +1 -1
- package/dist/components/schedule-list.cjs +1 -1
- package/dist/components/schedule-list.js +1 -1
- package/dist/components/select.cjs +1 -1
- package/dist/components/select.js +1 -1
- package/dist/components/sheet.cjs +1 -1
- package/dist/components/sheet.js +1 -1
- package/dist/components/solar-forecast-chart.cjs +108 -0
- package/dist/components/solar-forecast-chart.cjs.map +1 -0
- package/dist/components/solar-forecast-chart.d.cts +77 -0
- package/dist/components/solar-forecast-chart.d.ts +77 -0
- package/dist/components/solar-forecast-chart.js +103 -0
- package/dist/components/solar-forecast-chart.js.map +1 -0
- package/dist/components/stepper.cjs +1 -1
- package/dist/components/stepper.js +1 -1
- package/dist/components/table.cjs +1 -1
- package/dist/components/table.js +1 -1
- package/dist/components/tabs.cjs +1 -1
- package/dist/components/tabs.js +1 -1
- package/dist/components/toast.cjs +1 -1
- package/dist/components/toast.js +1 -1
- package/dist/components/tooltip.cjs +1 -1
- package/dist/components/tooltip.js +1 -1
- package/dist/number-flow-Bch81ixZ.d.cts +14 -0
- package/dist/number-flow-Bch81ixZ.d.ts +14 -0
- package/dist/utils/build-sankey-nodes.cjs +72 -0
- package/dist/utils/build-sankey-nodes.cjs.map +1 -0
- package/dist/utils/build-sankey-nodes.d.cts +27 -0
- package/dist/utils/build-sankey-nodes.d.ts +27 -0
- package/dist/utils/build-sankey-nodes.js +71 -0
- package/dist/utils/build-sankey-nodes.js.map +1 -0
- package/dist/utils/format.cjs +13 -0
- package/dist/utils/format.cjs.map +1 -1
- package/dist/utils/format.d.cts +7 -1
- package/dist/utils/format.d.ts +7 -1
- package/dist/utils/format.js +12 -1
- package/dist/utils/format.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../utils/cn.js";
|
|
3
|
+
import "../utils/chars.js";
|
|
4
|
+
import { oneDecimalFormat } from "../utils/format.js";
|
|
5
|
+
import { LineChart } from "./line-chart.js";
|
|
6
|
+
import { useEffect, useRef, useState } from "react";
|
|
7
|
+
import { jsx } from "react/jsx-runtime";
|
|
8
|
+
//#region src/components/solar-forecast-chart.tsx
|
|
9
|
+
const DEFAULT_HEIGHT = 220;
|
|
10
|
+
const BASE_MARGIN = {
|
|
11
|
+
top: 8,
|
|
12
|
+
right: 8,
|
|
13
|
+
bottom: 28,
|
|
14
|
+
left: 34
|
|
15
|
+
};
|
|
16
|
+
/** Extra headroom for the weather icon row pinned above the plot. */
|
|
17
|
+
const WEATHER_ROW_HEIGHT = 24;
|
|
18
|
+
function defaultFormatValue(value) {
|
|
19
|
+
return `${oneDecimalFormat.format(value)} kW`;
|
|
20
|
+
}
|
|
21
|
+
function defaultFormatTime(date) {
|
|
22
|
+
return date.getHours().toString().padStart(2, "0");
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Responsive line plot of measured production (solid) against a forecast
|
|
26
|
+
* (dashed) over a day. Optionally overlays hourly weather icons and
|
|
27
|
+
* sunrise/sunset markers, all pinned to the same time axis. Sizes itself to its
|
|
28
|
+
* container; compose a title and any summary around it.
|
|
29
|
+
*/
|
|
30
|
+
function SolarForecastChart({ produced, forecast, producedLabel = "Produced", forecastLabel = "Forecast", formatValue = defaultFormatValue, yAxisUnit = "kW", formatTime = defaultFormatTime, formatTooltipTime, weather, sunrise, sunset, formatMarkerTime, curve = "monotone", height = DEFAULT_HEIGHT, className, zoomable, zoomResetLabel, zoomDomain, onZoomDomainChange }) {
|
|
31
|
+
const containerRef = useRef(null);
|
|
32
|
+
const [width, setWidth] = useState(0);
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
const el = containerRef.current;
|
|
35
|
+
if (!el) return;
|
|
36
|
+
const ro = new ResizeObserver((entries) => {
|
|
37
|
+
const entry = entries[0];
|
|
38
|
+
if (entry) setWidth(entry.contentRect.width);
|
|
39
|
+
});
|
|
40
|
+
ro.observe(el);
|
|
41
|
+
return () => ro.disconnect();
|
|
42
|
+
}, []);
|
|
43
|
+
const hasWeather = weather != null && weather.length > 0;
|
|
44
|
+
const margin = {
|
|
45
|
+
...BASE_MARGIN,
|
|
46
|
+
top: hasWeather ? BASE_MARGIN.top + WEATHER_ROW_HEIGHT : BASE_MARGIN.top
|
|
47
|
+
};
|
|
48
|
+
const formatMarker = formatMarkerTime ?? formatTooltipTime ?? formatTime;
|
|
49
|
+
const topContent = hasWeather ? weather.map((point, i) => {
|
|
50
|
+
const WeatherGlyph = point.icon;
|
|
51
|
+
return {
|
|
52
|
+
key: `weather-${point.date.valueOf()}-${i}`,
|
|
53
|
+
date: point.date,
|
|
54
|
+
content: /* @__PURE__ */ jsx(WeatherGlyph, { className: "text-gray-light [--spark-icon-size:18px]" })
|
|
55
|
+
};
|
|
56
|
+
}) : void 0;
|
|
57
|
+
const referenceLines = [sunrise && {
|
|
58
|
+
key: "sunrise",
|
|
59
|
+
date: sunrise,
|
|
60
|
+
label: formatMarker(sunrise)
|
|
61
|
+
}, sunset && {
|
|
62
|
+
key: "sunset",
|
|
63
|
+
date: sunset,
|
|
64
|
+
label: formatMarker(sunset)
|
|
65
|
+
}].filter((x) => Boolean(x));
|
|
66
|
+
return /* @__PURE__ */ jsx("div", {
|
|
67
|
+
ref: containerRef,
|
|
68
|
+
className: cn("w-full", className),
|
|
69
|
+
children: width > 0 && /* @__PURE__ */ jsx(LineChart, {
|
|
70
|
+
width,
|
|
71
|
+
height,
|
|
72
|
+
margin,
|
|
73
|
+
curve,
|
|
74
|
+
series: [{
|
|
75
|
+
id: "produced",
|
|
76
|
+
data: produced,
|
|
77
|
+
label: producedLabel
|
|
78
|
+
}, {
|
|
79
|
+
id: "forecast",
|
|
80
|
+
data: forecast,
|
|
81
|
+
label: forecastLabel,
|
|
82
|
+
dashed: true
|
|
83
|
+
}],
|
|
84
|
+
showGrid: true,
|
|
85
|
+
xTickCount: 6,
|
|
86
|
+
yTickCount: 4,
|
|
87
|
+
yAxisUnit,
|
|
88
|
+
formatDate: formatTime,
|
|
89
|
+
formatTooltipDate: formatTooltipTime ?? formatTime,
|
|
90
|
+
formatValue,
|
|
91
|
+
referenceLines: referenceLines.length > 0 ? referenceLines : void 0,
|
|
92
|
+
topContent,
|
|
93
|
+
zoomable,
|
|
94
|
+
zoomResetLabel,
|
|
95
|
+
zoomDomain,
|
|
96
|
+
onZoomDomainChange
|
|
97
|
+
})
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
//#endregion
|
|
101
|
+
export { SolarForecastChart, SolarForecastChart as default };
|
|
102
|
+
|
|
103
|
+
//# sourceMappingURL=solar-forecast-chart.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"solar-forecast-chart.js","names":[],"sources":["../../src/components/solar-forecast-chart.tsx"],"sourcesContent":["import type { SparkIcon } from '@epilot/spark-icons'\nimport { type JSX, type ReactNode, useEffect, useRef, useState } from 'react'\nimport { NARROW_NBSP } from '../utils/chars'\nimport { cn } from '../utils/cn'\nimport { oneDecimalFormat } from '../utils/format'\nimport {\n LineChart,\n type LineChartCurve,\n type LineChartDatum,\n} from './line-chart'\n\nconst DEFAULT_HEIGHT = 220\n// `left` leaves room for the y-axis tick labels + unit (matches the 34px gutter\n// used by BarChart / PowerHistoryChart).\nconst BASE_MARGIN = { top: 8, right: 8, bottom: 28, left: 34 }\n/** Extra headroom for the weather icon row pinned above the plot. */\nconst WEATHER_ROW_HEIGHT = 24\n\nfunction defaultFormatValue(value: number): string {\n return `${oneDecimalFormat.format(value)}${NARROW_NBSP}kW`\n}\n\nfunction defaultFormatTime(date: Date): string {\n return date.getHours().toString().padStart(2, '0')\n}\n\nexport interface SolarForecastWeatherPoint {\n date: Date\n icon: SparkIcon\n}\n\nexport interface SolarForecastChartProps {\n /** Measured production, drawn as the solid line. */\n produced: LineChartDatum[]\n /** Predicted production, drawn as the dashed line. */\n forecast: LineChartDatum[]\n /** Tooltip label for the produced series. */\n producedLabel?: ReactNode\n /** Tooltip label for the forecast series. */\n forecastLabel?: ReactNode\n /** Tooltip value formatter. Defaults to one-decimal kW (power). */\n formatValue?: (value: number) => string\n /** Unit shown once atop the y-axis; ticks render as plain numbers. Defaults to \"kW\". */\n yAxisUnit?: string\n /** X-axis tick formatter. Defaults to the zero-padded hour. */\n formatTime?: (date: Date) => string\n /** Tooltip time formatter. Defaults to `formatTime`. */\n formatTooltipTime?: (date: Date) => string\n /**\n * Hourly weather icons drawn along the top of the plot, aligned to the time\n * axis. Their dates must fall within the plotted day.\n */\n weather?: SolarForecastWeatherPoint[]\n /** Sunrise time, drawn as a labelled vertical marker on the plot. */\n sunrise?: Date\n /** Sunset time, drawn as a labelled vertical marker on the plot. */\n sunset?: Date\n /** Label formatter for the sunrise/sunset markers. Defaults to `formatTime`. */\n formatMarkerTime?: (date: Date) => string\n curve?: LineChartCurve\n height?: number\n className?: string\n zoomable?: boolean\n zoomResetLabel?: string\n zoomDomain?: [Date, Date] | null\n onZoomDomainChange?: (domain: [Date, Date] | null) => void\n}\n\n/**\n * Responsive line plot of measured production (solid) against a forecast\n * (dashed) over a day. Optionally overlays hourly weather icons and\n * sunrise/sunset markers, all pinned to the same time axis. Sizes itself to its\n * container; compose a title and any summary around it.\n */\nexport function SolarForecastChart({\n produced,\n forecast,\n producedLabel = 'Produced',\n forecastLabel = 'Forecast',\n formatValue = defaultFormatValue,\n yAxisUnit = 'kW',\n formatTime = defaultFormatTime,\n formatTooltipTime,\n weather,\n sunrise,\n sunset,\n formatMarkerTime,\n curve = 'monotone',\n height = DEFAULT_HEIGHT,\n className,\n zoomable,\n zoomResetLabel,\n zoomDomain,\n onZoomDomainChange,\n}: SolarForecastChartProps): JSX.Element {\n const containerRef = useRef<HTMLDivElement>(null)\n const [width, setWidth] = useState(0)\n\n useEffect(() => {\n const el = containerRef.current\n if (!el) return\n const ro = new ResizeObserver((entries) => {\n const entry = entries[0]\n if (entry) setWidth(entry.contentRect.width)\n })\n ro.observe(el)\n return () => ro.disconnect()\n }, [])\n\n const hasWeather = weather != null && weather.length > 0\n const margin = {\n ...BASE_MARGIN,\n top: hasWeather ? BASE_MARGIN.top + WEATHER_ROW_HEIGHT : BASE_MARGIN.top,\n }\n const formatMarker = formatMarkerTime ?? formatTooltipTime ?? formatTime\n\n const topContent = hasWeather\n ? weather.map((point, i) => {\n const WeatherGlyph = point.icon\n return {\n key: `weather-${point.date.valueOf()}-${i}`,\n date: point.date,\n content: (\n <WeatherGlyph className=\"text-gray-light [--spark-icon-size:18px]\" />\n ),\n }\n })\n : undefined\n\n const referenceLines = [\n sunrise && { key: 'sunrise', date: sunrise, label: formatMarker(sunrise) },\n sunset && { key: 'sunset', date: sunset, label: formatMarker(sunset) },\n ].filter((x): x is { key: string; date: Date; label: string } => Boolean(x))\n\n return (\n <div ref={containerRef} className={cn('w-full', className)}>\n {width > 0 && (\n <LineChart\n width={width}\n height={height}\n margin={margin}\n curve={curve}\n series={[\n { id: 'produced', data: produced, label: producedLabel },\n {\n id: 'forecast',\n data: forecast,\n label: forecastLabel,\n dashed: true,\n },\n ]}\n showGrid\n xTickCount={6}\n yTickCount={4}\n yAxisUnit={yAxisUnit}\n formatDate={formatTime}\n formatTooltipDate={formatTooltipTime ?? formatTime}\n formatValue={formatValue}\n referenceLines={\n referenceLines.length > 0 ? referenceLines : undefined\n }\n topContent={topContent}\n zoomable={zoomable}\n zoomResetLabel={zoomResetLabel}\n zoomDomain={zoomDomain}\n onZoomDomainChange={onZoomDomainChange}\n />\n )}\n </div>\n )\n}\n\nexport default SolarForecastChart\n"],"mappings":";;;;;;;;AAWA,MAAM,iBAAiB;AAGvB,MAAM,cAAc;CAAE,KAAK;CAAG,OAAO;CAAG,QAAQ;CAAI,MAAM;AAAG;;AAE7D,MAAM,qBAAqB;AAE3B,SAAS,mBAAmB,OAAuB;CACjD,OAAO,GAAG,iBAAiB,OAAO,KAAK;AACzC;AAEA,SAAS,kBAAkB,MAAoB;CAC7C,OAAO,KAAK,SAAS,EAAE,SAAS,EAAE,SAAS,GAAG,GAAG;AACnD;;;;;;;AAkDA,SAAgB,mBAAmB,EACjC,UACA,UACA,gBAAgB,YAChB,gBAAgB,YAChB,cAAc,oBACd,YAAY,MACZ,aAAa,mBACb,mBACA,SACA,SACA,QACA,kBACA,QAAQ,YACR,SAAS,gBACT,WACA,UACA,gBACA,YACA,sBACuC;CACvC,MAAM,eAAe,OAAuB,IAAI;CAChD,MAAM,CAAC,OAAO,YAAY,SAAS,CAAC;CAEpC,gBAAgB;EACd,MAAM,KAAK,aAAa;EACxB,IAAI,CAAC,IAAI;EACT,MAAM,KAAK,IAAI,gBAAgB,YAAY;GACzC,MAAM,QAAQ,QAAQ;GACtB,IAAI,OAAO,SAAS,MAAM,YAAY,KAAK;EAC7C,CAAC;EACD,GAAG,QAAQ,EAAE;EACb,aAAa,GAAG,WAAW;CAC7B,GAAG,CAAC,CAAC;CAEL,MAAM,aAAa,WAAW,QAAQ,QAAQ,SAAS;CACvD,MAAM,SAAS;EACb,GAAG;EACH,KAAK,aAAa,YAAY,MAAM,qBAAqB,YAAY;CACvE;CACA,MAAM,eAAe,oBAAoB,qBAAqB;CAE9D,MAAM,aAAa,aACf,QAAQ,KAAK,OAAO,MAAM;EACxB,MAAM,eAAe,MAAM;EAC3B,OAAO;GACL,KAAK,WAAW,MAAM,KAAK,QAAQ,EAAE,GAAG;GACxC,MAAM,MAAM;GACZ,SACE,oBAAC,cAAD,EAAc,WAAU,2CAA4C,CAAA;EAExE;CACF,CAAC,IACD,KAAA;CAEJ,MAAM,iBAAiB,CACrB,WAAW;EAAE,KAAK;EAAW,MAAM;EAAS,OAAO,aAAa,OAAO;CAAE,GACzE,UAAU;EAAE,KAAK;EAAU,MAAM;EAAQ,OAAO,aAAa,MAAM;CAAE,CACvE,EAAE,QAAQ,MAAuD,QAAQ,CAAC,CAAC;CAE3E,OACE,oBAAC,OAAD;EAAK,KAAK;EAAc,WAAW,GAAG,UAAU,SAAS;YACtD,QAAQ,KACP,oBAAC,WAAD;GACS;GACC;GACA;GACD;GACP,QAAQ,CACN;IAAE,IAAI;IAAY,MAAM;IAAU,OAAO;GAAc,GACvD;IACE,IAAI;IACJ,MAAM;IACN,OAAO;IACP,QAAQ;GACV,CACF;GACA,UAAA;GACA,YAAY;GACZ,YAAY;GACD;GACX,YAAY;GACZ,mBAAmB,qBAAqB;GAC3B;GACb,gBACE,eAAe,SAAS,IAAI,iBAAiB,KAAA;GAEnC;GACF;GACM;GACJ;GACQ;EACrB,CAAA;CAEA,CAAA;AAET"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const require_chunk = require("../chunk-DY84GLCh.cjs");
|
|
4
|
-
let _epilot_spark_icons = require("@epilot/spark-icons");
|
|
5
4
|
let react = require("react");
|
|
6
5
|
react = require_chunk.__toESM(react);
|
|
6
|
+
let _epilot_spark_icons = require("@epilot/spark-icons");
|
|
7
7
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
8
8
|
let cnfast = require("cnfast");
|
|
9
9
|
//#region src/components/stepper.tsx
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn } from "../utils/cn.js";
|
|
3
|
-
import { ChevronLeft, ChevronRight } from "@epilot/spark-icons";
|
|
4
3
|
import * as React$1 from "react";
|
|
4
|
+
import { ChevronLeft, ChevronRight } from "@epilot/spark-icons";
|
|
5
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
6
|
//#region src/components/stepper.tsx
|
|
7
7
|
const Stepper = React$1.forwardRef(({ value, onValueChange, onValueCommit, min = 0, max = 100, step = 1, formatValue = (v) => String(v), disabled, className, commitDelayMs = 400, "aria-label": ariaLabel, decreaseLabel, increaseLabel }, ref) => {
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const require_chunk = require("../chunk-DY84GLCh.cjs");
|
|
4
4
|
const require_components_skeleton = require("./skeleton.cjs");
|
|
5
|
-
let _epilot_spark_icons = require("@epilot/spark-icons");
|
|
6
5
|
let react = require("react");
|
|
7
6
|
react = require_chunk.__toESM(react);
|
|
7
|
+
let _epilot_spark_icons = require("@epilot/spark-icons");
|
|
8
8
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
9
9
|
let cnfast = require("cnfast");
|
|
10
10
|
//#region src/components/table.tsx
|
package/dist/components/table.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn } from "../utils/cn.js";
|
|
3
3
|
import { Skeleton } from "./skeleton.js";
|
|
4
|
-
import { ArrowDownward, ArrowUpward, SwapVert } from "@epilot/spark-icons";
|
|
5
4
|
import * as React$1 from "react";
|
|
5
|
+
import { ArrowDownward, ArrowUpward, SwapVert } from "@epilot/spark-icons";
|
|
6
6
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
7
|
//#region src/components/table.tsx
|
|
8
8
|
const TableContext = React$1.createContext({
|
package/dist/components/tabs.cjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const require_chunk = require("../chunk-DY84GLCh.cjs");
|
|
4
|
-
let _epilot_spark_icons = require("@epilot/spark-icons");
|
|
5
4
|
let react = require("react");
|
|
6
5
|
react = require_chunk.__toESM(react);
|
|
6
|
+
let _epilot_spark_icons = require("@epilot/spark-icons");
|
|
7
7
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
8
8
|
let _base_ui_react_tabs = require("@base-ui/react/tabs");
|
|
9
9
|
let cnfast = require("cnfast");
|
package/dist/components/tabs.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn } from "../utils/cn.js";
|
|
3
|
-
import { ChevronLeft, ChevronRight } from "@epilot/spark-icons";
|
|
4
3
|
import * as React$1 from "react";
|
|
4
|
+
import { ChevronLeft, ChevronRight } from "@epilot/spark-icons";
|
|
5
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
6
|
import { Tabs as Tabs$1 } from "@base-ui/react/tabs";
|
|
7
7
|
//#region src/components/tabs.tsx
|
|
@@ -4,9 +4,9 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
4
4
|
const require_chunk = require("../chunk-DY84GLCh.cjs");
|
|
5
5
|
const require_components_button = require("./button.cjs");
|
|
6
6
|
const require_components_spinner = require("./spinner.cjs");
|
|
7
|
-
let _epilot_spark_icons = require("@epilot/spark-icons");
|
|
8
7
|
let react = require("react");
|
|
9
8
|
react = require_chunk.__toESM(react);
|
|
9
|
+
let _epilot_spark_icons = require("@epilot/spark-icons");
|
|
10
10
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
11
11
|
let _base_ui_react_toast = require("@base-ui/react/toast");
|
|
12
12
|
let cnfast = require("cnfast");
|
package/dist/components/toast.js
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
import { cn } from "../utils/cn.js";
|
|
4
4
|
import { buttonVariants } from "./button.js";
|
|
5
5
|
import { Spinner } from "./spinner.js";
|
|
6
|
-
import { Cancel, CheckCircle, Close, Info, Warning } from "@epilot/spark-icons";
|
|
7
6
|
import "react";
|
|
7
|
+
import { Cancel, CheckCircle, Close, Info, Warning } from "@epilot/spark-icons";
|
|
8
8
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
9
|
import { Toast } from "@base-ui/react/toast";
|
|
10
10
|
//#region src/components/toast.tsx
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const require_chunk = require("../chunk-DY84GLCh.cjs");
|
|
4
|
-
let _epilot_spark_icons = require("@epilot/spark-icons");
|
|
5
4
|
let react = require("react");
|
|
6
5
|
react = require_chunk.__toESM(react);
|
|
6
|
+
let _epilot_spark_icons = require("@epilot/spark-icons");
|
|
7
7
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
8
8
|
let _base_ui_react_tooltip = require("@base-ui/react/tooltip");
|
|
9
9
|
let cnfast = require("cnfast");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn } from "../utils/cn.js";
|
|
3
|
-
import { Info } from "@epilot/spark-icons";
|
|
4
3
|
import "react";
|
|
4
|
+
import { Info } from "@epilot/spark-icons";
|
|
5
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
6
|
import { Tooltip as Tooltip$1 } from "@base-ui/react/tooltip";
|
|
7
7
|
//#region src/components/tooltip.tsx
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Format, NumberFlowProps, NumberFlowProps as NumberFlowProps$1 } from "@number-flow/react";
|
|
4
|
+
|
|
5
|
+
//#region src/components/number-flow.d.ts
|
|
6
|
+
declare function NumberFlow({
|
|
7
|
+
locales,
|
|
8
|
+
prefix,
|
|
9
|
+
suffix,
|
|
10
|
+
...props
|
|
11
|
+
}: NumberFlowProps): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { NumberFlow as n, NumberFlowProps$1 as r, Format as t };
|
|
14
|
+
//# sourceMappingURL=number-flow-Bch81ixZ.d.cts.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Format, NumberFlowProps, NumberFlowProps as NumberFlowProps$1 } from "@number-flow/react";
|
|
4
|
+
|
|
5
|
+
//#region src/components/number-flow.d.ts
|
|
6
|
+
declare function NumberFlow({
|
|
7
|
+
locales,
|
|
8
|
+
prefix,
|
|
9
|
+
suffix,
|
|
10
|
+
...props
|
|
11
|
+
}: NumberFlowProps): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { NumberFlow as n, NumberFlowProps$1 as r, Format as t };
|
|
14
|
+
//# sourceMappingURL=number-flow-Bch81ixZ.d.ts.map
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
//#region src/utils/build-sankey-nodes.ts
|
|
4
|
+
function buildSankeyNodes({ solarPower, batteryPower, gridPower, floorShares, deviceSharesByFloor }) {
|
|
5
|
+
const solar = Math.max(0, solarPower);
|
|
6
|
+
const gridImport = Math.max(0, gridPower);
|
|
7
|
+
const gridExport = Math.max(0, -gridPower);
|
|
8
|
+
const batteryDischarge = Math.max(0, batteryPower);
|
|
9
|
+
const batteryCharge = Math.max(0, -batteryPower);
|
|
10
|
+
const solarToBattery = Math.min(solar, batteryCharge);
|
|
11
|
+
const gridToBattery = Math.min(gridImport, batteryCharge - solarToBattery);
|
|
12
|
+
const solarToFeedIn = Math.min(solar - solarToBattery, gridExport);
|
|
13
|
+
const batteryToFeedIn = Math.min(batteryDischarge, gridExport - solarToFeedIn);
|
|
14
|
+
const links = [
|
|
15
|
+
{
|
|
16
|
+
source: "grid",
|
|
17
|
+
target: "home",
|
|
18
|
+
value: gridImport - gridToBattery
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
source: "solar",
|
|
22
|
+
target: "home",
|
|
23
|
+
value: solar - solarToBattery - solarToFeedIn
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
source: "battery",
|
|
27
|
+
target: "home",
|
|
28
|
+
value: batteryDischarge - batteryToFeedIn
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
source: "solar",
|
|
32
|
+
target: "battery",
|
|
33
|
+
value: solarToBattery
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
source: "grid",
|
|
37
|
+
target: "battery",
|
|
38
|
+
value: gridToBattery
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
source: "solar",
|
|
42
|
+
target: "gridFeedIn",
|
|
43
|
+
value: solarToFeedIn
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
source: "battery",
|
|
47
|
+
target: "gridFeedIn",
|
|
48
|
+
value: batteryToFeedIn
|
|
49
|
+
}
|
|
50
|
+
];
|
|
51
|
+
if (!floorShares) return links;
|
|
52
|
+
const homeWatts = solar - solarToBattery - solarToFeedIn + (gridImport - gridToBattery) + (batteryDischarge - batteryToFeedIn);
|
|
53
|
+
for (const [floorId, share] of Object.entries(floorShares)) {
|
|
54
|
+
const floorWatts = homeWatts * share;
|
|
55
|
+
links.push({
|
|
56
|
+
source: "home",
|
|
57
|
+
target: floorId,
|
|
58
|
+
value: floorWatts
|
|
59
|
+
});
|
|
60
|
+
const deviceShares = deviceSharesByFloor?.[floorId] ?? {};
|
|
61
|
+
for (const [deviceId, deviceShare] of Object.entries(deviceShares)) links.push({
|
|
62
|
+
source: floorId,
|
|
63
|
+
target: deviceId,
|
|
64
|
+
value: floorWatts * deviceShare
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
return links;
|
|
68
|
+
}
|
|
69
|
+
//#endregion
|
|
70
|
+
exports.buildSankeyNodes = buildSankeyNodes;
|
|
71
|
+
|
|
72
|
+
//# sourceMappingURL=build-sankey-nodes.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-sankey-nodes.cjs","names":[],"sources":["../../src/utils/build-sankey-nodes.ts"],"sourcesContent":["import type { SankeyChartLink } from '../components/sankey-chart'\n\ntype SankeyNodesArgs = {\n solarPower: number\n /**\n * Signed storage power: positive = discharging into the home, negative =\n * charging from solar/grid. Charging power is routed into the `battery`\n * node so it isn't mistakenly attributed to home consumption.\n */\n batteryPower: number\n gridPower: number\n floorShares?: Record<string, number>\n deviceSharesByFloor?: Record<string, Record<string, number>>\n}\n\nfunction buildSankeyNodes({\n solarPower,\n batteryPower,\n gridPower,\n floorShares,\n deviceSharesByFloor,\n}: SankeyNodesArgs): SankeyChartLink[] {\n const solar = Math.max(0, solarPower)\n const gridImport = Math.max(0, gridPower)\n const gridExport = Math.max(0, -gridPower)\n const batteryDischarge = Math.max(0, batteryPower)\n const batteryCharge = Math.max(0, -batteryPower)\n\n // Charge the battery from solar surplus first, then from the grid. Routing\n // the charge flow into the `battery` node (a sink while charging) keeps it\n // out of the `home` node, which should reflect actual consumption only.\n const solarToBattery = Math.min(solar, batteryCharge)\n const gridToBattery = Math.min(gridImport, batteryCharge - solarToBattery)\n\n // Grid feed-in (export). Cover it from the solar surplus first, then fall\n // back to battery discharge. Like battery charging, this must not land in the\n // `home` node — it's power leaving the house, not consumption.\n const solarToFeedIn = Math.min(solar - solarToBattery, gridExport)\n const batteryToFeedIn = Math.min(batteryDischarge, gridExport - solarToFeedIn)\n\n const links: SankeyChartLink[] = [\n { source: 'grid', target: 'home', value: gridImport - gridToBattery },\n {\n source: 'solar',\n target: 'home',\n value: solar - solarToBattery - solarToFeedIn,\n },\n {\n source: 'battery',\n target: 'home',\n value: batteryDischarge - batteryToFeedIn,\n },\n { source: 'solar', target: 'battery', value: solarToBattery },\n { source: 'grid', target: 'battery', value: gridToBattery },\n { source: 'solar', target: 'gridFeedIn', value: solarToFeedIn },\n { source: 'battery', target: 'gridFeedIn', value: batteryToFeedIn },\n ]\n\n if (!floorShares) return links\n\n const homeWatts =\n solar -\n solarToBattery -\n solarToFeedIn +\n (gridImport - gridToBattery) +\n (batteryDischarge - batteryToFeedIn)\n\n for (const [floorId, share] of Object.entries(floorShares)) {\n const floorWatts = homeWatts * share\n links.push({ source: 'home', target: floorId, value: floorWatts })\n\n const deviceShares = deviceSharesByFloor?.[floorId] ?? {}\n for (const [deviceId, deviceShare] of Object.entries(deviceShares)) {\n links.push({\n source: floorId,\n target: deviceId,\n value: floorWatts * deviceShare,\n })\n }\n }\n\n return links\n}\n\nexport { buildSankeyNodes }\n"],"mappings":";;;AAeA,SAAS,iBAAiB,EACxB,YACA,cACA,WACA,aACA,uBACqC;CACrC,MAAM,QAAQ,KAAK,IAAI,GAAG,UAAU;CACpC,MAAM,aAAa,KAAK,IAAI,GAAG,SAAS;CACxC,MAAM,aAAa,KAAK,IAAI,GAAG,CAAC,SAAS;CACzC,MAAM,mBAAmB,KAAK,IAAI,GAAG,YAAY;CACjD,MAAM,gBAAgB,KAAK,IAAI,GAAG,CAAC,YAAY;CAK/C,MAAM,iBAAiB,KAAK,IAAI,OAAO,aAAa;CACpD,MAAM,gBAAgB,KAAK,IAAI,YAAY,gBAAgB,cAAc;CAKzE,MAAM,gBAAgB,KAAK,IAAI,QAAQ,gBAAgB,UAAU;CACjE,MAAM,kBAAkB,KAAK,IAAI,kBAAkB,aAAa,aAAa;CAE7E,MAAM,QAA2B;EAC/B;GAAE,QAAQ;GAAQ,QAAQ;GAAQ,OAAO,aAAa;EAAc;EACpE;GACE,QAAQ;GACR,QAAQ;GACR,OAAO,QAAQ,iBAAiB;EAClC;EACA;GACE,QAAQ;GACR,QAAQ;GACR,OAAO,mBAAmB;EAC5B;EACA;GAAE,QAAQ;GAAS,QAAQ;GAAW,OAAO;EAAe;EAC5D;GAAE,QAAQ;GAAQ,QAAQ;GAAW,OAAO;EAAc;EAC1D;GAAE,QAAQ;GAAS,QAAQ;GAAc,OAAO;EAAc;EAC9D;GAAE,QAAQ;GAAW,QAAQ;GAAc,OAAO;EAAgB;CACpE;CAEA,IAAI,CAAC,aAAa,OAAO;CAEzB,MAAM,YACJ,QACA,iBACA,iBACC,aAAa,kBACb,mBAAmB;CAEtB,KAAK,MAAM,CAAC,SAAS,UAAU,OAAO,QAAQ,WAAW,GAAG;EAC1D,MAAM,aAAa,YAAY;EAC/B,MAAM,KAAK;GAAE,QAAQ;GAAQ,QAAQ;GAAS,OAAO;EAAW,CAAC;EAEjE,MAAM,eAAe,sBAAsB,YAAY,CAAC;EACxD,KAAK,MAAM,CAAC,UAAU,gBAAgB,OAAO,QAAQ,YAAY,GAC/D,MAAM,KAAK;GACT,QAAQ;GACR,QAAQ;GACR,OAAO,aAAa;EACtB,CAAC;CAEL;CAEA,OAAO;AACT"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { SankeyChartLink } from "../components/sankey-chart.cjs";
|
|
4
|
+
|
|
5
|
+
//#region src/utils/build-sankey-nodes.d.ts
|
|
6
|
+
type SankeyNodesArgs = {
|
|
7
|
+
solarPower: number;
|
|
8
|
+
/**
|
|
9
|
+
* Signed storage power: positive = discharging into the home, negative =
|
|
10
|
+
* charging from solar/grid. Charging power is routed into the `battery`
|
|
11
|
+
* node so it isn't mistakenly attributed to home consumption.
|
|
12
|
+
*/
|
|
13
|
+
batteryPower: number;
|
|
14
|
+
gridPower: number;
|
|
15
|
+
floorShares?: Record<string, number>;
|
|
16
|
+
deviceSharesByFloor?: Record<string, Record<string, number>>;
|
|
17
|
+
};
|
|
18
|
+
declare function buildSankeyNodes({
|
|
19
|
+
solarPower,
|
|
20
|
+
batteryPower,
|
|
21
|
+
gridPower,
|
|
22
|
+
floorShares,
|
|
23
|
+
deviceSharesByFloor
|
|
24
|
+
}: SankeyNodesArgs): SankeyChartLink[];
|
|
25
|
+
//#endregion
|
|
26
|
+
export { buildSankeyNodes };
|
|
27
|
+
//# sourceMappingURL=build-sankey-nodes.d.cts.map
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { SankeyChartLink } from "../components/sankey-chart.js";
|
|
4
|
+
|
|
5
|
+
//#region src/utils/build-sankey-nodes.d.ts
|
|
6
|
+
type SankeyNodesArgs = {
|
|
7
|
+
solarPower: number;
|
|
8
|
+
/**
|
|
9
|
+
* Signed storage power: positive = discharging into the home, negative =
|
|
10
|
+
* charging from solar/grid. Charging power is routed into the `battery`
|
|
11
|
+
* node so it isn't mistakenly attributed to home consumption.
|
|
12
|
+
*/
|
|
13
|
+
batteryPower: number;
|
|
14
|
+
gridPower: number;
|
|
15
|
+
floorShares?: Record<string, number>;
|
|
16
|
+
deviceSharesByFloor?: Record<string, Record<string, number>>;
|
|
17
|
+
};
|
|
18
|
+
declare function buildSankeyNodes({
|
|
19
|
+
solarPower,
|
|
20
|
+
batteryPower,
|
|
21
|
+
gridPower,
|
|
22
|
+
floorShares,
|
|
23
|
+
deviceSharesByFloor
|
|
24
|
+
}: SankeyNodesArgs): SankeyChartLink[];
|
|
25
|
+
//#endregion
|
|
26
|
+
export { buildSankeyNodes };
|
|
27
|
+
//# sourceMappingURL=build-sankey-nodes.d.ts.map
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
//#region src/utils/build-sankey-nodes.ts
|
|
3
|
+
function buildSankeyNodes({ solarPower, batteryPower, gridPower, floorShares, deviceSharesByFloor }) {
|
|
4
|
+
const solar = Math.max(0, solarPower);
|
|
5
|
+
const gridImport = Math.max(0, gridPower);
|
|
6
|
+
const gridExport = Math.max(0, -gridPower);
|
|
7
|
+
const batteryDischarge = Math.max(0, batteryPower);
|
|
8
|
+
const batteryCharge = Math.max(0, -batteryPower);
|
|
9
|
+
const solarToBattery = Math.min(solar, batteryCharge);
|
|
10
|
+
const gridToBattery = Math.min(gridImport, batteryCharge - solarToBattery);
|
|
11
|
+
const solarToFeedIn = Math.min(solar - solarToBattery, gridExport);
|
|
12
|
+
const batteryToFeedIn = Math.min(batteryDischarge, gridExport - solarToFeedIn);
|
|
13
|
+
const links = [
|
|
14
|
+
{
|
|
15
|
+
source: "grid",
|
|
16
|
+
target: "home",
|
|
17
|
+
value: gridImport - gridToBattery
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
source: "solar",
|
|
21
|
+
target: "home",
|
|
22
|
+
value: solar - solarToBattery - solarToFeedIn
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
source: "battery",
|
|
26
|
+
target: "home",
|
|
27
|
+
value: batteryDischarge - batteryToFeedIn
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
source: "solar",
|
|
31
|
+
target: "battery",
|
|
32
|
+
value: solarToBattery
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
source: "grid",
|
|
36
|
+
target: "battery",
|
|
37
|
+
value: gridToBattery
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
source: "solar",
|
|
41
|
+
target: "gridFeedIn",
|
|
42
|
+
value: solarToFeedIn
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
source: "battery",
|
|
46
|
+
target: "gridFeedIn",
|
|
47
|
+
value: batteryToFeedIn
|
|
48
|
+
}
|
|
49
|
+
];
|
|
50
|
+
if (!floorShares) return links;
|
|
51
|
+
const homeWatts = solar - solarToBattery - solarToFeedIn + (gridImport - gridToBattery) + (batteryDischarge - batteryToFeedIn);
|
|
52
|
+
for (const [floorId, share] of Object.entries(floorShares)) {
|
|
53
|
+
const floorWatts = homeWatts * share;
|
|
54
|
+
links.push({
|
|
55
|
+
source: "home",
|
|
56
|
+
target: floorId,
|
|
57
|
+
value: floorWatts
|
|
58
|
+
});
|
|
59
|
+
const deviceShares = deviceSharesByFloor?.[floorId] ?? {};
|
|
60
|
+
for (const [deviceId, deviceShare] of Object.entries(deviceShares)) links.push({
|
|
61
|
+
source: floorId,
|
|
62
|
+
target: deviceId,
|
|
63
|
+
value: floorWatts * deviceShare
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
return links;
|
|
67
|
+
}
|
|
68
|
+
//#endregion
|
|
69
|
+
export { buildSankeyNodes };
|
|
70
|
+
|
|
71
|
+
//# sourceMappingURL=build-sankey-nodes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-sankey-nodes.js","names":[],"sources":["../../src/utils/build-sankey-nodes.ts"],"sourcesContent":["import type { SankeyChartLink } from '../components/sankey-chart'\n\ntype SankeyNodesArgs = {\n solarPower: number\n /**\n * Signed storage power: positive = discharging into the home, negative =\n * charging from solar/grid. Charging power is routed into the `battery`\n * node so it isn't mistakenly attributed to home consumption.\n */\n batteryPower: number\n gridPower: number\n floorShares?: Record<string, number>\n deviceSharesByFloor?: Record<string, Record<string, number>>\n}\n\nfunction buildSankeyNodes({\n solarPower,\n batteryPower,\n gridPower,\n floorShares,\n deviceSharesByFloor,\n}: SankeyNodesArgs): SankeyChartLink[] {\n const solar = Math.max(0, solarPower)\n const gridImport = Math.max(0, gridPower)\n const gridExport = Math.max(0, -gridPower)\n const batteryDischarge = Math.max(0, batteryPower)\n const batteryCharge = Math.max(0, -batteryPower)\n\n // Charge the battery from solar surplus first, then from the grid. Routing\n // the charge flow into the `battery` node (a sink while charging) keeps it\n // out of the `home` node, which should reflect actual consumption only.\n const solarToBattery = Math.min(solar, batteryCharge)\n const gridToBattery = Math.min(gridImport, batteryCharge - solarToBattery)\n\n // Grid feed-in (export). Cover it from the solar surplus first, then fall\n // back to battery discharge. Like battery charging, this must not land in the\n // `home` node — it's power leaving the house, not consumption.\n const solarToFeedIn = Math.min(solar - solarToBattery, gridExport)\n const batteryToFeedIn = Math.min(batteryDischarge, gridExport - solarToFeedIn)\n\n const links: SankeyChartLink[] = [\n { source: 'grid', target: 'home', value: gridImport - gridToBattery },\n {\n source: 'solar',\n target: 'home',\n value: solar - solarToBattery - solarToFeedIn,\n },\n {\n source: 'battery',\n target: 'home',\n value: batteryDischarge - batteryToFeedIn,\n },\n { source: 'solar', target: 'battery', value: solarToBattery },\n { source: 'grid', target: 'battery', value: gridToBattery },\n { source: 'solar', target: 'gridFeedIn', value: solarToFeedIn },\n { source: 'battery', target: 'gridFeedIn', value: batteryToFeedIn },\n ]\n\n if (!floorShares) return links\n\n const homeWatts =\n solar -\n solarToBattery -\n solarToFeedIn +\n (gridImport - gridToBattery) +\n (batteryDischarge - batteryToFeedIn)\n\n for (const [floorId, share] of Object.entries(floorShares)) {\n const floorWatts = homeWatts * share\n links.push({ source: 'home', target: floorId, value: floorWatts })\n\n const deviceShares = deviceSharesByFloor?.[floorId] ?? {}\n for (const [deviceId, deviceShare] of Object.entries(deviceShares)) {\n links.push({\n source: floorId,\n target: deviceId,\n value: floorWatts * deviceShare,\n })\n }\n }\n\n return links\n}\n\nexport { buildSankeyNodes }\n"],"mappings":";;AAeA,SAAS,iBAAiB,EACxB,YACA,cACA,WACA,aACA,uBACqC;CACrC,MAAM,QAAQ,KAAK,IAAI,GAAG,UAAU;CACpC,MAAM,aAAa,KAAK,IAAI,GAAG,SAAS;CACxC,MAAM,aAAa,KAAK,IAAI,GAAG,CAAC,SAAS;CACzC,MAAM,mBAAmB,KAAK,IAAI,GAAG,YAAY;CACjD,MAAM,gBAAgB,KAAK,IAAI,GAAG,CAAC,YAAY;CAK/C,MAAM,iBAAiB,KAAK,IAAI,OAAO,aAAa;CACpD,MAAM,gBAAgB,KAAK,IAAI,YAAY,gBAAgB,cAAc;CAKzE,MAAM,gBAAgB,KAAK,IAAI,QAAQ,gBAAgB,UAAU;CACjE,MAAM,kBAAkB,KAAK,IAAI,kBAAkB,aAAa,aAAa;CAE7E,MAAM,QAA2B;EAC/B;GAAE,QAAQ;GAAQ,QAAQ;GAAQ,OAAO,aAAa;EAAc;EACpE;GACE,QAAQ;GACR,QAAQ;GACR,OAAO,QAAQ,iBAAiB;EAClC;EACA;GACE,QAAQ;GACR,QAAQ;GACR,OAAO,mBAAmB;EAC5B;EACA;GAAE,QAAQ;GAAS,QAAQ;GAAW,OAAO;EAAe;EAC5D;GAAE,QAAQ;GAAQ,QAAQ;GAAW,OAAO;EAAc;EAC1D;GAAE,QAAQ;GAAS,QAAQ;GAAc,OAAO;EAAc;EAC9D;GAAE,QAAQ;GAAW,QAAQ;GAAc,OAAO;EAAgB;CACpE;CAEA,IAAI,CAAC,aAAa,OAAO;CAEzB,MAAM,YACJ,QACA,iBACA,iBACC,aAAa,kBACb,mBAAmB;CAEtB,KAAK,MAAM,CAAC,SAAS,UAAU,OAAO,QAAQ,WAAW,GAAG;EAC1D,MAAM,aAAa,YAAY;EAC/B,MAAM,KAAK;GAAE,QAAQ;GAAQ,QAAQ;GAAS,OAAO;EAAW,CAAC;EAEjE,MAAM,eAAe,sBAAsB,YAAY,CAAC;EACxD,KAAK,MAAM,CAAC,UAAU,gBAAgB,OAAO,QAAQ,YAAY,GAC/D,MAAM,KAAK;GACT,QAAQ;GACR,QAAQ;GACR,OAAO,aAAa;EACtB,CAAC;CAEL;CAEA,OAAO;AACT"}
|
package/dist/utils/format.cjs
CHANGED
|
@@ -23,6 +23,17 @@ const integerFormat = decimalsFormat(0);
|
|
|
23
23
|
const oneDecimalFormat = decimalsFormat(1);
|
|
24
24
|
const twoDecimalFormat = decimalsFormat(2);
|
|
25
25
|
const formatThousands = (n) => integerFormat.format(n);
|
|
26
|
+
const formatEnergy = (v) => {
|
|
27
|
+
if (v >= 1e6) return `${twoDecimalFormat.format(v / 1e3)} MWh`;
|
|
28
|
+
if (v >= 1e3) return `${integerFormat.format(v)} kWh`;
|
|
29
|
+
if (v >= 10) return `${oneDecimalFormat.format(v)} kWh`;
|
|
30
|
+
return `${twoDecimalFormat.format(v)} kWh`;
|
|
31
|
+
};
|
|
32
|
+
const formatPower = (value, { signed = false } = {}) => {
|
|
33
|
+
if (value == null) return "—";
|
|
34
|
+
const rounded = Math.round(value);
|
|
35
|
+
return `${signed && rounded > 0 ? "+" : ""}${integerFormat.format(rounded)} W`;
|
|
36
|
+
};
|
|
26
37
|
const formatPercent = (value) => {
|
|
27
38
|
if (value == null) return "—";
|
|
28
39
|
return `${integerFormat.format(value)} %`;
|
|
@@ -33,7 +44,9 @@ const formatRatio = (value) => {
|
|
|
33
44
|
};
|
|
34
45
|
//#endregion
|
|
35
46
|
exports.decimalsFormat = decimalsFormat;
|
|
47
|
+
exports.formatEnergy = formatEnergy;
|
|
36
48
|
exports.formatPercent = formatPercent;
|
|
49
|
+
exports.formatPower = formatPower;
|
|
37
50
|
exports.formatRatio = formatRatio;
|
|
38
51
|
exports.formatThousands = formatThousands;
|
|
39
52
|
exports.integerFormat = integerFormat;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format.cjs","names":[],"sources":["../../src/utils/format.ts"],"sourcesContent":["import { EM_DASH, NARROW_NBSP } from './chars'\n\ninterface LocaleNumberFormat {\n format: (value: number) => string\n}\n\nfunction getDocumentLang(): string | undefined {\n return typeof document === 'undefined'\n ? undefined\n : document.documentElement.lang || undefined\n}\n\nconst localeNumberFormat = (\n options?: Intl.NumberFormatOptions,\n): LocaleNumberFormat => {\n const cache = new Map<string, Intl.NumberFormat>()\n return {\n format: (value) => {\n const locale = getDocumentLang()\n const key = locale ?? ''\n let formatter = cache.get(key)\n if (!formatter) {\n formatter = new Intl.NumberFormat(locale, options)\n cache.set(key, formatter)\n }\n return formatter.format(value)\n },\n }\n}\n\nconst decimalsFormat = (decimals: number) =>\n localeNumberFormat({ maximumFractionDigits: decimals })\n\nconst integerFormat = decimalsFormat(0)\nconst oneDecimalFormat = decimalsFormat(1)\nconst twoDecimalFormat = decimalsFormat(2)\n\nconst formatThousands = (n: number) => integerFormat.format(n)\n\nconst formatPercent = (value: number | null): string => {\n if (value == null) return EM_DASH\n return `${integerFormat.format(value)}${NARROW_NBSP}%`\n}\n\nconst formatRatio = (value: number | null): string => {\n if (value == null) return EM_DASH\n return `${integerFormat.format(value * 100)}${NARROW_NBSP}%`\n}\n\nexport {\n formatThousands,\n formatPercent,\n formatRatio,\n localeNumberFormat,\n decimalsFormat,\n integerFormat,\n oneDecimalFormat,\n twoDecimalFormat,\n}\n"],"mappings":";;;;AAMA,SAAS,kBAAsC;CAC7C,OAAO,OAAO,aAAa,cACvB,KAAA,IACA,SAAS,gBAAgB,QAAQ,KAAA;AACvC;AAEA,MAAM,sBACJ,YACuB;CACvB,MAAM,wBAAQ,IAAI,IAA+B;CACjD,OAAO,EACL,SAAS,UAAU;EACjB,MAAM,SAAS,gBAAgB;EAC/B,MAAM,MAAM,UAAU;EACtB,IAAI,YAAY,MAAM,IAAI,GAAG;EAC7B,IAAI,CAAC,WAAW;GACd,YAAY,IAAI,KAAK,aAAa,QAAQ,OAAO;GACjD,MAAM,IAAI,KAAK,SAAS;EAC1B;EACA,OAAO,UAAU,OAAO,KAAK;CAC/B,EACF;AACF;AAEA,MAAM,kBAAkB,aACtB,mBAAmB,EAAE,uBAAuB,SAAS,CAAC;AAExD,MAAM,gBAAgB,eAAe,CAAC;AACtC,MAAM,mBAAmB,eAAe,CAAC;AACzC,MAAM,mBAAmB,eAAe,CAAC;AAEzC,MAAM,mBAAmB,MAAc,cAAc,OAAO,CAAC;AAE7D,MAAM,iBAAiB,UAAiC;CACtD,IAAI,SAAS,MAAM,OAAA;CACnB,OAAO,GAAG,cAAc,OAAO,KAAK;AACtC;AAEA,MAAM,eAAe,UAAiC;CACpD,IAAI,SAAS,MAAM,OAAA;CACnB,OAAO,GAAG,cAAc,OAAO,QAAQ,GAAG;AAC5C"}
|
|
1
|
+
{"version":3,"file":"format.cjs","names":[],"sources":["../../src/utils/format.ts"],"sourcesContent":["import { EM_DASH, NARROW_NBSP } from './chars'\n\ninterface LocaleNumberFormat {\n format: (value: number) => string\n}\n\nfunction getDocumentLang(): string | undefined {\n return typeof document === 'undefined'\n ? undefined\n : document.documentElement.lang || undefined\n}\n\nconst localeNumberFormat = (\n options?: Intl.NumberFormatOptions,\n): LocaleNumberFormat => {\n const cache = new Map<string, Intl.NumberFormat>()\n return {\n format: (value) => {\n const locale = getDocumentLang()\n const key = locale ?? ''\n let formatter = cache.get(key)\n if (!formatter) {\n formatter = new Intl.NumberFormat(locale, options)\n cache.set(key, formatter)\n }\n return formatter.format(value)\n },\n }\n}\n\nconst decimalsFormat = (decimals: number) =>\n localeNumberFormat({ maximumFractionDigits: decimals })\n\nconst integerFormat = decimalsFormat(0)\nconst oneDecimalFormat = decimalsFormat(1)\nconst twoDecimalFormat = decimalsFormat(2)\n\nconst formatThousands = (n: number) => integerFormat.format(n)\n\nconst formatEnergy = (v: number) => {\n if (v >= 1_000_000) {\n return `${twoDecimalFormat.format(v / 1000)}${NARROW_NBSP}MWh`\n }\n if (v >= 1_000) return `${integerFormat.format(v)}${NARROW_NBSP}kWh`\n if (v >= 10) return `${oneDecimalFormat.format(v)}${NARROW_NBSP}kWh`\n return `${twoDecimalFormat.format(v)}${NARROW_NBSP}kWh`\n}\n\nconst formatPower = (\n value: number | null,\n { signed = false }: { signed?: boolean } = {},\n): string => {\n if (value == null) return EM_DASH\n const rounded = Math.round(value)\n const sign = signed && rounded > 0 ? '+' : ''\n return `${sign}${integerFormat.format(rounded)}${NARROW_NBSP}W`\n}\n\nconst formatPercent = (value: number | null): string => {\n if (value == null) return EM_DASH\n return `${integerFormat.format(value)}${NARROW_NBSP}%`\n}\n\nconst formatRatio = (value: number | null): string => {\n if (value == null) return EM_DASH\n return `${integerFormat.format(value * 100)}${NARROW_NBSP}%`\n}\n\nexport {\n formatThousands,\n formatEnergy,\n formatPower,\n formatPercent,\n formatRatio,\n localeNumberFormat,\n decimalsFormat,\n integerFormat,\n oneDecimalFormat,\n twoDecimalFormat,\n}\n"],"mappings":";;;;AAMA,SAAS,kBAAsC;CAC7C,OAAO,OAAO,aAAa,cACvB,KAAA,IACA,SAAS,gBAAgB,QAAQ,KAAA;AACvC;AAEA,MAAM,sBACJ,YACuB;CACvB,MAAM,wBAAQ,IAAI,IAA+B;CACjD,OAAO,EACL,SAAS,UAAU;EACjB,MAAM,SAAS,gBAAgB;EAC/B,MAAM,MAAM,UAAU;EACtB,IAAI,YAAY,MAAM,IAAI,GAAG;EAC7B,IAAI,CAAC,WAAW;GACd,YAAY,IAAI,KAAK,aAAa,QAAQ,OAAO;GACjD,MAAM,IAAI,KAAK,SAAS;EAC1B;EACA,OAAO,UAAU,OAAO,KAAK;CAC/B,EACF;AACF;AAEA,MAAM,kBAAkB,aACtB,mBAAmB,EAAE,uBAAuB,SAAS,CAAC;AAExD,MAAM,gBAAgB,eAAe,CAAC;AACtC,MAAM,mBAAmB,eAAe,CAAC;AACzC,MAAM,mBAAmB,eAAe,CAAC;AAEzC,MAAM,mBAAmB,MAAc,cAAc,OAAO,CAAC;AAE7D,MAAM,gBAAgB,MAAc;CAClC,IAAI,KAAK,KACP,OAAO,GAAG,iBAAiB,OAAO,IAAI,GAAI;CAE5C,IAAI,KAAK,KAAO,OAAO,GAAG,cAAc,OAAO,CAAC;CAChD,IAAI,KAAK,IAAI,OAAO,GAAG,iBAAiB,OAAO,CAAC;CAChD,OAAO,GAAG,iBAAiB,OAAO,CAAC;AACrC;AAEA,MAAM,eACJ,OACA,EAAE,SAAS,UAAgC,CAAC,MACjC;CACX,IAAI,SAAS,MAAM,OAAA;CACnB,MAAM,UAAU,KAAK,MAAM,KAAK;CAEhC,OAAO,GADM,UAAU,UAAU,IAAI,MAAM,KAC1B,cAAc,OAAO,OAAO;AAC/C;AAEA,MAAM,iBAAiB,UAAiC;CACtD,IAAI,SAAS,MAAM,OAAA;CACnB,OAAO,GAAG,cAAc,OAAO,KAAK;AACtC;AAEA,MAAM,eAAe,UAAiC;CACpD,IAAI,SAAS,MAAM,OAAA;CACnB,OAAO,GAAG,cAAc,OAAO,QAAQ,GAAG;AAC5C"}
|
package/dist/utils/format.d.cts
CHANGED
|
@@ -10,8 +10,14 @@ declare const integerFormat: LocaleNumberFormat;
|
|
|
10
10
|
declare const oneDecimalFormat: LocaleNumberFormat;
|
|
11
11
|
declare const twoDecimalFormat: LocaleNumberFormat;
|
|
12
12
|
declare const formatThousands: (n: number) => string;
|
|
13
|
+
declare const formatEnergy: (v: number) => string;
|
|
14
|
+
declare const formatPower: (value: number | null, {
|
|
15
|
+
signed
|
|
16
|
+
}?: {
|
|
17
|
+
signed?: boolean;
|
|
18
|
+
}) => string;
|
|
13
19
|
declare const formatPercent: (value: number | null) => string;
|
|
14
20
|
declare const formatRatio: (value: number | null) => string;
|
|
15
21
|
//#endregion
|
|
16
|
-
export { decimalsFormat, formatPercent, formatRatio, formatThousands, integerFormat, localeNumberFormat, oneDecimalFormat, twoDecimalFormat };
|
|
22
|
+
export { decimalsFormat, formatEnergy, formatPercent, formatPower, formatRatio, formatThousands, integerFormat, localeNumberFormat, oneDecimalFormat, twoDecimalFormat };
|
|
17
23
|
//# sourceMappingURL=format.d.cts.map
|
package/dist/utils/format.d.ts
CHANGED
|
@@ -10,8 +10,14 @@ declare const integerFormat: LocaleNumberFormat;
|
|
|
10
10
|
declare const oneDecimalFormat: LocaleNumberFormat;
|
|
11
11
|
declare const twoDecimalFormat: LocaleNumberFormat;
|
|
12
12
|
declare const formatThousands: (n: number) => string;
|
|
13
|
+
declare const formatEnergy: (v: number) => string;
|
|
14
|
+
declare const formatPower: (value: number | null, {
|
|
15
|
+
signed
|
|
16
|
+
}?: {
|
|
17
|
+
signed?: boolean;
|
|
18
|
+
}) => string;
|
|
13
19
|
declare const formatPercent: (value: number | null) => string;
|
|
14
20
|
declare const formatRatio: (value: number | null) => string;
|
|
15
21
|
//#endregion
|
|
16
|
-
export { decimalsFormat, formatPercent, formatRatio, formatThousands, integerFormat, localeNumberFormat, oneDecimalFormat, twoDecimalFormat };
|
|
22
|
+
export { decimalsFormat, formatEnergy, formatPercent, formatPower, formatRatio, formatThousands, integerFormat, localeNumberFormat, oneDecimalFormat, twoDecimalFormat };
|
|
17
23
|
//# sourceMappingURL=format.d.ts.map
|
package/dist/utils/format.js
CHANGED
|
@@ -22,6 +22,17 @@ const integerFormat = decimalsFormat(0);
|
|
|
22
22
|
const oneDecimalFormat = decimalsFormat(1);
|
|
23
23
|
const twoDecimalFormat = decimalsFormat(2);
|
|
24
24
|
const formatThousands = (n) => integerFormat.format(n);
|
|
25
|
+
const formatEnergy = (v) => {
|
|
26
|
+
if (v >= 1e6) return `${twoDecimalFormat.format(v / 1e3)} MWh`;
|
|
27
|
+
if (v >= 1e3) return `${integerFormat.format(v)} kWh`;
|
|
28
|
+
if (v >= 10) return `${oneDecimalFormat.format(v)} kWh`;
|
|
29
|
+
return `${twoDecimalFormat.format(v)} kWh`;
|
|
30
|
+
};
|
|
31
|
+
const formatPower = (value, { signed = false } = {}) => {
|
|
32
|
+
if (value == null) return "—";
|
|
33
|
+
const rounded = Math.round(value);
|
|
34
|
+
return `${signed && rounded > 0 ? "+" : ""}${integerFormat.format(rounded)} W`;
|
|
35
|
+
};
|
|
25
36
|
const formatPercent = (value) => {
|
|
26
37
|
if (value == null) return "—";
|
|
27
38
|
return `${integerFormat.format(value)} %`;
|
|
@@ -31,6 +42,6 @@ const formatRatio = (value) => {
|
|
|
31
42
|
return `${integerFormat.format(value * 100)} %`;
|
|
32
43
|
};
|
|
33
44
|
//#endregion
|
|
34
|
-
export { decimalsFormat, formatPercent, formatRatio, formatThousands, integerFormat, localeNumberFormat, oneDecimalFormat, twoDecimalFormat };
|
|
45
|
+
export { decimalsFormat, formatEnergy, formatPercent, formatPower, formatRatio, formatThousands, integerFormat, localeNumberFormat, oneDecimalFormat, twoDecimalFormat };
|
|
35
46
|
|
|
36
47
|
//# sourceMappingURL=format.js.map
|
package/dist/utils/format.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format.js","names":[],"sources":["../../src/utils/format.ts"],"sourcesContent":["import { EM_DASH, NARROW_NBSP } from './chars'\n\ninterface LocaleNumberFormat {\n format: (value: number) => string\n}\n\nfunction getDocumentLang(): string | undefined {\n return typeof document === 'undefined'\n ? undefined\n : document.documentElement.lang || undefined\n}\n\nconst localeNumberFormat = (\n options?: Intl.NumberFormatOptions,\n): LocaleNumberFormat => {\n const cache = new Map<string, Intl.NumberFormat>()\n return {\n format: (value) => {\n const locale = getDocumentLang()\n const key = locale ?? ''\n let formatter = cache.get(key)\n if (!formatter) {\n formatter = new Intl.NumberFormat(locale, options)\n cache.set(key, formatter)\n }\n return formatter.format(value)\n },\n }\n}\n\nconst decimalsFormat = (decimals: number) =>\n localeNumberFormat({ maximumFractionDigits: decimals })\n\nconst integerFormat = decimalsFormat(0)\nconst oneDecimalFormat = decimalsFormat(1)\nconst twoDecimalFormat = decimalsFormat(2)\n\nconst formatThousands = (n: number) => integerFormat.format(n)\n\nconst formatPercent = (value: number | null): string => {\n if (value == null) return EM_DASH\n return `${integerFormat.format(value)}${NARROW_NBSP}%`\n}\n\nconst formatRatio = (value: number | null): string => {\n if (value == null) return EM_DASH\n return `${integerFormat.format(value * 100)}${NARROW_NBSP}%`\n}\n\nexport {\n formatThousands,\n formatPercent,\n formatRatio,\n localeNumberFormat,\n decimalsFormat,\n integerFormat,\n oneDecimalFormat,\n twoDecimalFormat,\n}\n"],"mappings":";;;AAMA,SAAS,kBAAsC;CAC7C,OAAO,OAAO,aAAa,cACvB,KAAA,IACA,SAAS,gBAAgB,QAAQ,KAAA;AACvC;AAEA,MAAM,sBACJ,YACuB;CACvB,MAAM,wBAAQ,IAAI,IAA+B;CACjD,OAAO,EACL,SAAS,UAAU;EACjB,MAAM,SAAS,gBAAgB;EAC/B,MAAM,MAAM,UAAU;EACtB,IAAI,YAAY,MAAM,IAAI,GAAG;EAC7B,IAAI,CAAC,WAAW;GACd,YAAY,IAAI,KAAK,aAAa,QAAQ,OAAO;GACjD,MAAM,IAAI,KAAK,SAAS;EAC1B;EACA,OAAO,UAAU,OAAO,KAAK;CAC/B,EACF;AACF;AAEA,MAAM,kBAAkB,aACtB,mBAAmB,EAAE,uBAAuB,SAAS,CAAC;AAExD,MAAM,gBAAgB,eAAe,CAAC;AACtC,MAAM,mBAAmB,eAAe,CAAC;AACzC,MAAM,mBAAmB,eAAe,CAAC;AAEzC,MAAM,mBAAmB,MAAc,cAAc,OAAO,CAAC;AAE7D,MAAM,iBAAiB,UAAiC;CACtD,IAAI,SAAS,MAAM,OAAA;CACnB,OAAO,GAAG,cAAc,OAAO,KAAK;AACtC;AAEA,MAAM,eAAe,UAAiC;CACpD,IAAI,SAAS,MAAM,OAAA;CACnB,OAAO,GAAG,cAAc,OAAO,QAAQ,GAAG;AAC5C"}
|
|
1
|
+
{"version":3,"file":"format.js","names":[],"sources":["../../src/utils/format.ts"],"sourcesContent":["import { EM_DASH, NARROW_NBSP } from './chars'\n\ninterface LocaleNumberFormat {\n format: (value: number) => string\n}\n\nfunction getDocumentLang(): string | undefined {\n return typeof document === 'undefined'\n ? undefined\n : document.documentElement.lang || undefined\n}\n\nconst localeNumberFormat = (\n options?: Intl.NumberFormatOptions,\n): LocaleNumberFormat => {\n const cache = new Map<string, Intl.NumberFormat>()\n return {\n format: (value) => {\n const locale = getDocumentLang()\n const key = locale ?? ''\n let formatter = cache.get(key)\n if (!formatter) {\n formatter = new Intl.NumberFormat(locale, options)\n cache.set(key, formatter)\n }\n return formatter.format(value)\n },\n }\n}\n\nconst decimalsFormat = (decimals: number) =>\n localeNumberFormat({ maximumFractionDigits: decimals })\n\nconst integerFormat = decimalsFormat(0)\nconst oneDecimalFormat = decimalsFormat(1)\nconst twoDecimalFormat = decimalsFormat(2)\n\nconst formatThousands = (n: number) => integerFormat.format(n)\n\nconst formatEnergy = (v: number) => {\n if (v >= 1_000_000) {\n return `${twoDecimalFormat.format(v / 1000)}${NARROW_NBSP}MWh`\n }\n if (v >= 1_000) return `${integerFormat.format(v)}${NARROW_NBSP}kWh`\n if (v >= 10) return `${oneDecimalFormat.format(v)}${NARROW_NBSP}kWh`\n return `${twoDecimalFormat.format(v)}${NARROW_NBSP}kWh`\n}\n\nconst formatPower = (\n value: number | null,\n { signed = false }: { signed?: boolean } = {},\n): string => {\n if (value == null) return EM_DASH\n const rounded = Math.round(value)\n const sign = signed && rounded > 0 ? '+' : ''\n return `${sign}${integerFormat.format(rounded)}${NARROW_NBSP}W`\n}\n\nconst formatPercent = (value: number | null): string => {\n if (value == null) return EM_DASH\n return `${integerFormat.format(value)}${NARROW_NBSP}%`\n}\n\nconst formatRatio = (value: number | null): string => {\n if (value == null) return EM_DASH\n return `${integerFormat.format(value * 100)}${NARROW_NBSP}%`\n}\n\nexport {\n formatThousands,\n formatEnergy,\n formatPower,\n formatPercent,\n formatRatio,\n localeNumberFormat,\n decimalsFormat,\n integerFormat,\n oneDecimalFormat,\n twoDecimalFormat,\n}\n"],"mappings":";;;AAMA,SAAS,kBAAsC;CAC7C,OAAO,OAAO,aAAa,cACvB,KAAA,IACA,SAAS,gBAAgB,QAAQ,KAAA;AACvC;AAEA,MAAM,sBACJ,YACuB;CACvB,MAAM,wBAAQ,IAAI,IAA+B;CACjD,OAAO,EACL,SAAS,UAAU;EACjB,MAAM,SAAS,gBAAgB;EAC/B,MAAM,MAAM,UAAU;EACtB,IAAI,YAAY,MAAM,IAAI,GAAG;EAC7B,IAAI,CAAC,WAAW;GACd,YAAY,IAAI,KAAK,aAAa,QAAQ,OAAO;GACjD,MAAM,IAAI,KAAK,SAAS;EAC1B;EACA,OAAO,UAAU,OAAO,KAAK;CAC/B,EACF;AACF;AAEA,MAAM,kBAAkB,aACtB,mBAAmB,EAAE,uBAAuB,SAAS,CAAC;AAExD,MAAM,gBAAgB,eAAe,CAAC;AACtC,MAAM,mBAAmB,eAAe,CAAC;AACzC,MAAM,mBAAmB,eAAe,CAAC;AAEzC,MAAM,mBAAmB,MAAc,cAAc,OAAO,CAAC;AAE7D,MAAM,gBAAgB,MAAc;CAClC,IAAI,KAAK,KACP,OAAO,GAAG,iBAAiB,OAAO,IAAI,GAAI;CAE5C,IAAI,KAAK,KAAO,OAAO,GAAG,cAAc,OAAO,CAAC;CAChD,IAAI,KAAK,IAAI,OAAO,GAAG,iBAAiB,OAAO,CAAC;CAChD,OAAO,GAAG,iBAAiB,OAAO,CAAC;AACrC;AAEA,MAAM,eACJ,OACA,EAAE,SAAS,UAAgC,CAAC,MACjC;CACX,IAAI,SAAS,MAAM,OAAA;CACnB,MAAM,UAAU,KAAK,MAAM,KAAK;CAEhC,OAAO,GADM,UAAU,UAAU,IAAI,MAAM,KAC1B,cAAc,OAAO,OAAO;AAC/C;AAEA,MAAM,iBAAiB,UAAiC;CACtD,IAAI,SAAS,MAAM,OAAA;CACnB,OAAO,GAAG,cAAc,OAAO,KAAK;AACtC;AAEA,MAAM,eAAe,UAAiC;CACpD,IAAI,SAAS,MAAM,OAAA;CACnB,OAAO,GAAG,cAAc,OAAO,QAAQ,GAAG;AAC5C"}
|