@epilot/spark-ui 1.0.0-alpha.4 → 1.0.0-alpha.6
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/accent-colors-Ch2J0EEY.js +13 -0
- package/dist/accent-colors-Ch2J0EEY.js.map +1 -0
- package/dist/accent-colors-CjHCf8fH.cjs +18 -0
- package/dist/accent-colors-CjHCf8fH.cjs.map +1 -0
- package/dist/components/accordion.cjs +3 -3
- package/dist/components/accordion.cjs.map +1 -1
- package/dist/components/accordion.d.ts +1 -1
- package/dist/components/accordion.js +3 -3
- package/dist/components/accordion.js.map +1 -1
- package/dist/components/attachment.d.cts +1 -1
- package/dist/components/attachment.d.ts +1 -1
- package/dist/components/badge.cjs +12 -7
- package/dist/components/badge.cjs.map +1 -1
- package/dist/components/badge.d.cts +5 -1
- package/dist/components/badge.d.ts +5 -1
- package/dist/components/badge.js +12 -7
- package/dist/components/badge.js.map +1 -1
- package/dist/components/bar-chart.cjs +12 -9
- package/dist/components/bar-chart.cjs.map +1 -1
- package/dist/components/bar-chart.js +12 -9
- package/dist/components/bar-chart.js.map +1 -1
- package/dist/components/battery-progress-row.cjs +10 -16
- package/dist/components/battery-progress-row.cjs.map +1 -1
- package/dist/components/battery-progress-row.d.cts +1 -1
- package/dist/components/battery-progress-row.d.ts +2 -2
- package/dist/components/battery-progress-row.js +10 -16
- package/dist/components/battery-progress-row.js.map +1 -1
- package/dist/components/breadcrumbs.cjs +1 -1
- package/dist/components/breadcrumbs.cjs.map +1 -1
- package/dist/components/breadcrumbs.js +1 -1
- package/dist/components/breadcrumbs.js.map +1 -1
- package/dist/components/bubble.d.cts +1 -1
- package/dist/components/bubble.d.ts +1 -1
- package/dist/components/button.cjs +5 -2
- package/dist/components/button.cjs.map +1 -1
- package/dist/components/button.d.cts +7 -6
- package/dist/components/button.d.ts +7 -6
- package/dist/components/button.js +5 -2
- package/dist/components/button.js.map +1 -1
- package/dist/components/calendar.cjs +3 -2
- package/dist/components/calendar.cjs.map +1 -1
- package/dist/components/calendar.d.cts +5 -1
- package/dist/components/calendar.d.ts +5 -1
- package/dist/components/calendar.js +3 -2
- package/dist/components/calendar.js.map +1 -1
- package/dist/components/callout.d.cts +1 -1
- package/dist/components/callout.d.ts +1 -1
- package/dist/components/card.d.cts +1 -1
- package/dist/components/card.d.ts +1 -1
- package/dist/components/chart.cjs +1 -1
- package/dist/components/chart.cjs.map +1 -1
- package/dist/components/chart.js +1 -1
- package/dist/components/chart.js.map +1 -1
- package/dist/components/checkbox.cjs +30 -23
- package/dist/components/checkbox.cjs.map +1 -1
- package/dist/components/checkbox.d.cts +5 -1
- package/dist/components/checkbox.d.ts +5 -1
- package/dist/components/checkbox.js +30 -23
- package/dist/components/checkbox.js.map +1 -1
- package/dist/components/circular-gauge.d.ts +1 -1
- package/dist/components/day-of-week-picker.cjs +2 -2
- package/dist/components/day-of-week-picker.cjs.map +1 -1
- package/dist/components/day-of-week-picker.js +2 -2
- package/dist/components/day-of-week-picker.js.map +1 -1
- package/dist/components/device-card.d.ts +1 -1
- package/dist/components/donut-chart.cjs +3 -3
- package/dist/components/donut-chart.cjs.map +1 -1
- package/dist/components/donut-chart.js +3 -3
- package/dist/components/donut-chart.js.map +1 -1
- package/dist/components/energy-bar-chart.d.ts +1 -1
- package/dist/components/energy-breakdown.cjs +1 -1
- package/dist/components/energy-breakdown.cjs.map +1 -1
- package/dist/components/energy-breakdown.js +1 -1
- package/dist/components/energy-breakdown.js.map +1 -1
- package/dist/components/feed-in-hero.d.ts +1 -1
- package/dist/components/field.cjs +1 -1
- package/dist/components/field.d.cts +1 -1
- package/dist/components/field.d.ts +1 -1
- package/dist/components/field.js +1 -1
- package/dist/components/info-block.d.cts +1 -1
- package/dist/components/info-block.d.ts +1 -1
- package/dist/components/input-group.cjs +1 -1
- package/dist/components/input-group.js +1 -1
- package/dist/components/input-otp.cjs +1 -1
- package/dist/components/input-otp.js +1 -1
- package/dist/components/input.cjs +1 -1
- package/dist/components/input.d.cts +1 -1
- package/dist/components/input.d.ts +1 -1
- package/dist/components/input.js +1 -1
- package/dist/components/line-chart.cjs +11 -9
- package/dist/components/line-chart.cjs.map +1 -1
- package/dist/components/line-chart.js +11 -9
- package/dist/components/line-chart.js.map +1 -1
- package/dist/components/list.cjs +1 -1
- package/dist/components/list.cjs.map +1 -1
- package/dist/components/list.js +1 -1
- package/dist/components/list.js.map +1 -1
- package/dist/components/metering-row.d.ts +1 -1
- package/dist/components/money-saved-block.cjs +1 -1
- package/dist/components/money-saved-block.cjs.map +1 -1
- package/dist/components/money-saved-block.js +1 -1
- package/dist/components/money-saved-block.js.map +1 -1
- package/dist/components/number-flow.d.ts +1 -1
- package/dist/components/power-history-chart.cjs +9 -7
- package/dist/components/power-history-chart.cjs.map +1 -1
- package/dist/components/power-history-chart.js +9 -7
- package/dist/components/power-history-chart.js.map +1 -1
- package/dist/components/power-history.cjs +1 -1
- package/dist/components/power-history.cjs.map +1 -1
- package/dist/components/power-history.js +1 -1
- package/dist/components/power-history.js.map +1 -1
- package/dist/components/power-network.cjs +36 -11
- package/dist/components/power-network.cjs.map +1 -1
- package/dist/components/power-network.js +36 -11
- package/dist/components/power-network.js.map +1 -1
- package/dist/components/progress.cjs +1 -1
- package/dist/components/progress.cjs.map +1 -1
- package/dist/components/progress.js +1 -1
- package/dist/components/progress.js.map +1 -1
- package/dist/components/radio-card-group.cjs +26 -1
- package/dist/components/radio-card-group.cjs.map +1 -1
- package/dist/components/radio-card-group.js +26 -1
- package/dist/components/radio-card-group.js.map +1 -1
- package/dist/components/radio.cjs +11 -4
- package/dist/components/radio.cjs.map +1 -1
- package/dist/components/radio.d.cts +15 -3
- package/dist/components/radio.d.ts +15 -3
- package/dist/components/radio.js +11 -4
- package/dist/components/radio.js.map +1 -1
- package/dist/components/sankey-chart.cjs +4 -4
- package/dist/components/sankey-chart.cjs.map +1 -1
- package/dist/components/sankey-chart.d.ts +1 -1
- package/dist/components/sankey-chart.js +4 -4
- package/dist/components/sankey-chart.js.map +1 -1
- package/dist/components/schedule-list.cjs +3 -3
- package/dist/components/schedule-list.cjs.map +1 -1
- package/dist/components/schedule-list.js +3 -3
- package/dist/components/schedule-list.js.map +1 -1
- package/dist/components/segmented-control.cjs +2 -2
- package/dist/components/segmented-control.cjs.map +1 -1
- package/dist/components/segmented-control.d.cts +1 -1
- package/dist/components/segmented-control.d.ts +1 -1
- package/dist/components/segmented-control.js +2 -2
- package/dist/components/segmented-control.js.map +1 -1
- package/dist/components/select.cjs +1 -1
- package/dist/components/select.d.cts +1 -1
- package/dist/components/select.d.ts +1 -1
- package/dist/components/select.js +1 -1
- package/dist/components/series-legend.cjs +1 -1
- package/dist/components/series-legend.cjs.map +1 -1
- package/dist/components/series-legend.js +1 -1
- package/dist/components/series-legend.js.map +1 -1
- package/dist/components/slider.cjs +6 -19
- package/dist/components/slider.cjs.map +1 -1
- package/dist/components/slider.d.cts +0 -13
- package/dist/components/slider.d.ts +0 -13
- package/dist/components/slider.js +6 -19
- package/dist/components/slider.js.map +1 -1
- package/dist/components/stepper.cjs +2 -2
- package/dist/components/stepper.cjs.map +1 -1
- package/dist/components/stepper.js +2 -2
- package/dist/components/stepper.js.map +1 -1
- package/dist/components/switch.cjs +8 -3
- package/dist/components/switch.cjs.map +1 -1
- package/dist/components/switch.d.cts +9 -4
- package/dist/components/switch.d.ts +9 -4
- package/dist/components/switch.js +8 -3
- package/dist/components/switch.js.map +1 -1
- package/dist/components/tabs.cjs +4 -4
- package/dist/components/tabs.cjs.map +1 -1
- package/dist/components/tabs.js +4 -4
- package/dist/components/tabs.js.map +1 -1
- package/dist/components/theme.cjs +1 -1
- package/dist/components/theme.d.cts +1 -1
- package/dist/components/theme.d.ts +1 -1
- package/dist/components/theme.js +1 -1
- package/dist/components/time-picker.cjs +1 -1
- package/dist/components/time-picker.cjs.map +1 -1
- package/dist/components/time-picker.js +1 -1
- package/dist/components/time-picker.js.map +1 -1
- package/dist/hooks/use-reduced-motion.cjs +22 -0
- package/dist/hooks/use-reduced-motion.cjs.map +1 -0
- package/dist/hooks/use-reduced-motion.d.cts +7 -0
- package/dist/hooks/use-reduced-motion.d.ts +7 -0
- package/dist/hooks/use-reduced-motion.js +20 -0
- package/dist/hooks/use-reduced-motion.js.map +1 -0
- package/dist/{input-box-variants-Dr1K7uYE.js → input-box-variants-DcajYXvo.js} +1 -1
- package/dist/{input-box-variants-Dr1K7uYE.js.map → input-box-variants-DcajYXvo.js.map} +1 -1
- package/dist/{input-box-variants-BMDdwvqg.cjs → input-box-variants-ZCtgs-1S.cjs} +1 -1
- package/dist/{input-box-variants-BMDdwvqg.cjs.map → input-box-variants-ZCtgs-1S.cjs.map} +1 -1
- package/dist/{number-flow-DSbucQ_K.d.ts → number-flow-D9zsxH0-.d.ts} +1 -1
- package/dist/styles/index.css +4 -2
- package/dist/styles/spark-default.css +78 -0
- package/dist/{theme-C19BbKfO.js → theme-8PDO9E0S.js} +1 -1
- package/dist/{theme-C19BbKfO.js.map → theme-8PDO9E0S.js.map} +1 -1
- package/dist/{theme-CfFWrMEF.cjs → theme-ClRJhexF.cjs} +1 -1
- package/dist/{theme-CfFWrMEF.cjs.map → theme-ClRJhexF.cjs.map} +1 -1
- package/dist/{theme-types-DoROIXpi.d.ts → theme-types-BDdoRxXa.d.ts} +2 -3
- package/dist/{theme-types-r20EJfEC.d.cts → theme-types-BwSJKdsB.d.cts} +2 -3
- package/dist/{tones-DyCkL71h.d.ts → tones-PXJGlSpe.d.ts} +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"energy-breakdown.js","names":[],"sources":["../../src/components/energy-breakdown.tsx"],"sourcesContent":["import { useMemo } from 'react'\nimport { NARROW_NBSP } from '../utils/chars'\nimport {\n formatEnergy,\n formatThousands,\n integerFormat,\n oneDecimalFormat,\n twoDecimalFormat,\n} from '../utils/format'\nimport { DonutChart } from './donut-chart'\n\nexport type BreakdownItem = {\n label: string\n value: number\n color: string\n excludeFromCenterTotal?: boolean\n}\n\nexport type EnergyBreakdownProps = {\n title: string\n subtitle: string\n items: BreakdownItem[]\n centerSub?: string\n}\n\nfunction formatBreakdownCenter(v: number) {\n if (v >= 1000) return formatThousands(v)\n if (v >= 100) return integerFormat.format(v)\n if (v >= 10) return oneDecimalFormat.format(v)\n return twoDecimalFormat.format(v)\n}\n\nexport function EnergyBreakdown({\n title,\n subtitle,\n items,\n centerSub = 'kWh',\n}: EnergyBreakdownProps) {\n const sortedItems = useMemo(\n () => [...items].sort((a, b) => b.value - a.value),\n [items],\n )\n\n const total = items.reduce((s, i) => s + i.value, 0)\n const centerTotal = items\n .filter((i) => !i.excludeFromCenterTotal)\n .reduce((s, i) => s + i.value, 0)\n\n const dataEmpty = total === 0\n\n if (dataEmpty) return null\n\n return (\n <div className=\"flex flex-col gap-4 pt-3 pb-5\">\n <div className=\"flex flex-col gap-0.5\">\n <span className=\"text-sm font-semibold text-gray\">{title}</span>\n <span className=\"text-xs text-gray-light\">{subtitle}</span>\n </div>\n\n <div className=\"flex items-center gap-6\">\n <DonutChart\n centerLabel={formatBreakdownCenter(centerTotal)}\n centerSub={centerSub}\n segments={sortedItems.map(({ value, color }) => ({ value, color }))}\n />\n\n <div className=\"flex flex-1 flex-col gap-3\">\n {sortedItems.map(({ label, value, color }) => {\n const pct = (value / total) * 100\n return (\n <div key={label} className=\"flex flex-col gap-1.5\">\n <div className=\"flex items-baseline justify-between gap-2\">\n <span className=\"min-w-0 truncate text-sm font-medium text-gray\">\n {label}\n </span>\n <span className=\"flex shrink-0 items-baseline gap-1.5 text-xs tabular-nums\">\n <span className=\"text-gray-light\">\n {formatEnergy(value)}\n </span>\n <span className=\"font-semibold text-gray\">\n {`${integerFormat.format(pct)}${NARROW_NBSP}%`}\n </span>\n </span>\n </div>\n <div className=\"h-1 w-full overflow-hidden rounded-full bg-
|
|
1
|
+
{"version":3,"file":"energy-breakdown.js","names":[],"sources":["../../src/components/energy-breakdown.tsx"],"sourcesContent":["import { useMemo } from 'react'\nimport { NARROW_NBSP } from '../utils/chars'\nimport {\n formatEnergy,\n formatThousands,\n integerFormat,\n oneDecimalFormat,\n twoDecimalFormat,\n} from '../utils/format'\nimport { DonutChart } from './donut-chart'\n\nexport type BreakdownItem = {\n label: string\n value: number\n color: string\n excludeFromCenterTotal?: boolean\n}\n\nexport type EnergyBreakdownProps = {\n title: string\n subtitle: string\n items: BreakdownItem[]\n centerSub?: string\n}\n\nfunction formatBreakdownCenter(v: number) {\n if (v >= 1000) return formatThousands(v)\n if (v >= 100) return integerFormat.format(v)\n if (v >= 10) return oneDecimalFormat.format(v)\n return twoDecimalFormat.format(v)\n}\n\nexport function EnergyBreakdown({\n title,\n subtitle,\n items,\n centerSub = 'kWh',\n}: EnergyBreakdownProps) {\n const sortedItems = useMemo(\n () => [...items].sort((a, b) => b.value - a.value),\n [items],\n )\n\n const total = items.reduce((s, i) => s + i.value, 0)\n const centerTotal = items\n .filter((i) => !i.excludeFromCenterTotal)\n .reduce((s, i) => s + i.value, 0)\n\n const dataEmpty = total === 0\n\n if (dataEmpty) return null\n\n return (\n <div className=\"flex flex-col gap-4 pt-3 pb-5\">\n <div className=\"flex flex-col gap-0.5\">\n <span className=\"text-sm font-semibold text-gray\">{title}</span>\n <span className=\"text-xs text-gray-light\">{subtitle}</span>\n </div>\n\n <div className=\"flex items-center gap-6\">\n <DonutChart\n centerLabel={formatBreakdownCenter(centerTotal)}\n centerSub={centerSub}\n segments={sortedItems.map(({ value, color }) => ({ value, color }))}\n />\n\n <div className=\"flex flex-1 flex-col gap-3\">\n {sortedItems.map(({ label, value, color }) => {\n const pct = (value / total) * 100\n return (\n <div key={label} className=\"flex flex-col gap-1.5\">\n <div className=\"flex items-baseline justify-between gap-2\">\n <span className=\"min-w-0 truncate text-sm font-medium text-gray\">\n {label}\n </span>\n <span className=\"flex shrink-0 items-baseline gap-1.5 text-xs tabular-nums\">\n <span className=\"text-gray-light\">\n {formatEnergy(value)}\n </span>\n <span className=\"font-semibold text-gray\">\n {`${integerFormat.format(pct)}${NARROW_NBSP}%`}\n </span>\n </span>\n </div>\n <div className=\"h-1 w-full overflow-hidden rounded-full bg-gray-a4\">\n <div\n className=\"h-full rounded-full\"\n style={{ width: `${pct}%`, background: color }}\n />\n </div>\n </div>\n )\n })}\n </div>\n </div>\n </div>\n )\n}\n"],"mappings":";;;;;;;AAyBA,SAAS,sBAAsB,GAAW;AACxC,KAAI,KAAK,IAAM,QAAO,gBAAgB,EAAE;AACxC,KAAI,KAAK,IAAK,QAAO,cAAc,OAAO,EAAE;AAC5C,KAAI,KAAK,GAAI,QAAO,iBAAiB,OAAO,EAAE;AAC9C,QAAO,iBAAiB,OAAO,EAAE;;AAGnC,SAAgB,gBAAgB,EAC9B,OACA,UACA,OACA,YAAY,SACW;CACvB,MAAM,cAAc,cACZ,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,MAAM,EAClD,CAAC,MAAM,CACR;CAED,MAAM,QAAQ,MAAM,QAAQ,GAAG,MAAM,IAAI,EAAE,OAAO,EAAE;CACpD,MAAM,cAAc,MACjB,QAAQ,MAAM,CAAC,EAAE,uBAAuB,CACxC,QAAQ,GAAG,MAAM,IAAI,EAAE,OAAO,EAAE;AAInC,KAFkB,UAAU,EAEb,QAAO;AAEtB,QACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,oBAAC,QAAD;IAAM,WAAU;cAAmC;IAAa,CAAA,EAChE,oBAAC,QAAD;IAAM,WAAU;cAA2B;IAAgB,CAAA,CACvD;MAEN,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,oBAAC,YAAD;IACE,aAAa,sBAAsB,YAAY;IACpC;IACX,UAAU,YAAY,KAAK,EAAE,OAAO,aAAa;KAAE;KAAO;KAAO,EAAE;IACnE,CAAA,EAEF,oBAAC,OAAD;IAAK,WAAU;cACZ,YAAY,KAAK,EAAE,OAAO,OAAO,YAAY;KAC5C,MAAM,MAAO,QAAQ,QAAS;AAC9B,YACE,qBAAC,OAAD;MAAiB,WAAU;gBAA3B,CACE,qBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,oBAAC,QAAD;QAAM,WAAU;kBACb;QACI,CAAA,EACP,qBAAC,QAAD;QAAM,WAAU;kBAAhB,CACE,oBAAC,QAAD;SAAM,WAAU;mBACb,aAAa,MAAM;SACf,CAAA,EACP,oBAAC,QAAD;SAAM,WAAU;mBACb,GAAG,cAAc,OAAO,IAAI;SACxB,CAAA,CACF;UACH;UACN,oBAAC,OAAD;OAAK,WAAU;iBACb,oBAAC,OAAD;QACE,WAAU;QACV,OAAO;SAAE,OAAO,GAAG,IAAI;SAAI,YAAY;SAAO;QAC9C,CAAA;OACE,CAAA,CACF;QApBI,MAoBJ;MAER;IACE,CAAA,CACF;KACF"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
4
4
|
const require_chunk = require("../chunk-aJGBMT86.cjs");
|
|
5
5
|
const require_components_separator = require("./separator.cjs");
|
|
6
|
-
const require_theme = require("../theme-
|
|
6
|
+
const require_theme = require("../theme-ClRJhexF.cjs");
|
|
7
7
|
let react = require("react");
|
|
8
8
|
react = require_chunk.__toESM(react);
|
|
9
9
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import { a as
|
|
3
|
+
import { a as SparkLabelPosition, i as SparkInputStyle, r as SparkInputColor } from "../theme-types-BwSJKdsB.cjs";
|
|
4
4
|
import * as _$react_jsx_runtime0 from "react/jsx-runtime";
|
|
5
5
|
import * as React$1 from "react";
|
|
6
6
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import { a as
|
|
3
|
+
import { a as SparkLabelPosition, i as SparkInputStyle, r as SparkInputColor } from "../theme-types-BDdoRxXa.js";
|
|
4
4
|
import * as React$1 from "react";
|
|
5
5
|
import * as _$react_jsx_runtime0 from "react/jsx-runtime";
|
|
6
6
|
|
package/dist/components/field.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"use client";
|
|
3
3
|
import { cn } from "../utils/cn.js";
|
|
4
4
|
import { Separator } from "./separator.js";
|
|
5
|
-
import { n as useTheme } from "../theme-
|
|
5
|
+
import { n as useTheme } from "../theme-8PDO9E0S.js";
|
|
6
6
|
import * as React$1 from "react";
|
|
7
7
|
import { useId } from "react";
|
|
8
8
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -6,7 +6,7 @@ import { VariantProps } from "class-variance-authority";
|
|
|
6
6
|
|
|
7
7
|
//#region src/components/info-block.d.ts
|
|
8
8
|
declare const InfoBlock: React$1.ForwardRefExoticComponent<React$1.HTMLAttributes<HTMLDivElement> & VariantProps<(props?: ({
|
|
9
|
-
variant?: "
|
|
9
|
+
variant?: "default" | "bare" | null | undefined;
|
|
10
10
|
} & _$class_variance_authority_types0.ClassProp) | undefined) => string> & React$1.RefAttributes<HTMLDivElement>>;
|
|
11
11
|
declare const InfoBlockIcon: React$1.ForwardRefExoticComponent<React$1.HTMLAttributes<HTMLDivElement> & React$1.RefAttributes<HTMLDivElement>>;
|
|
12
12
|
declare const InfoBlockContent: React$1.ForwardRefExoticComponent<React$1.HTMLAttributes<HTMLDivElement> & React$1.RefAttributes<HTMLDivElement>>;
|
|
@@ -6,7 +6,7 @@ import * as _$class_variance_authority_types0 from "class-variance-authority/typ
|
|
|
6
6
|
|
|
7
7
|
//#region src/components/info-block.d.ts
|
|
8
8
|
declare const InfoBlock: React$1.ForwardRefExoticComponent<React$1.HTMLAttributes<HTMLDivElement> & VariantProps<(props?: ({
|
|
9
|
-
variant?: "
|
|
9
|
+
variant?: "default" | "bare" | null | undefined;
|
|
10
10
|
} & _$class_variance_authority_types0.ClassProp) | undefined) => string> & React$1.RefAttributes<HTMLDivElement>>;
|
|
11
11
|
declare const InfoBlockIcon: React$1.ForwardRefExoticComponent<React$1.HTMLAttributes<HTMLDivElement> & React$1.RefAttributes<HTMLDivElement>>;
|
|
12
12
|
declare const InfoBlockContent: React$1.ForwardRefExoticComponent<React$1.HTMLAttributes<HTMLDivElement> & React$1.RefAttributes<HTMLDivElement>>;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"use client";
|
|
3
3
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
4
4
|
const require_chunk = require("../chunk-aJGBMT86.cjs");
|
|
5
|
-
const require_theme = require("../theme-
|
|
5
|
+
const require_theme = require("../theme-ClRJhexF.cjs");
|
|
6
6
|
const require_components_field = require("./field.cjs");
|
|
7
7
|
const require_components_input = require("./input.cjs");
|
|
8
8
|
let react = require("react");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
"use client";
|
|
3
3
|
import { cn } from "../utils/cn.js";
|
|
4
|
-
import { n as useTheme } from "../theme-
|
|
4
|
+
import { n as useTheme } from "../theme-8PDO9E0S.js";
|
|
5
5
|
import { useFieldContext } from "./field.js";
|
|
6
6
|
import { Input } from "./input.js";
|
|
7
7
|
import "react";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
require("../chunk-aJGBMT86.cjs");
|
|
4
4
|
const require_components_field = require("./field.cjs");
|
|
5
|
-
const require_input_box_variants = require("../input-box-variants-
|
|
5
|
+
const require_input_box_variants = require("../input-box-variants-ZCtgs-1S.cjs");
|
|
6
6
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
7
7
|
let class_variance_authority = require("class-variance-authority");
|
|
8
8
|
let _base_ui_react_otp_field = require("@base-ui/react/otp-field");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn } from "../utils/cn.js";
|
|
3
3
|
import { useFieldControl } from "./field.js";
|
|
4
|
-
import { n as boxChrome, t as GHOST_UNDERLINE } from "../input-box-variants-
|
|
4
|
+
import { n as boxChrome, t as GHOST_UNDERLINE } from "../input-box-variants-DcajYXvo.js";
|
|
5
5
|
import { jsx } from "react/jsx-runtime";
|
|
6
6
|
import { cva } from "class-variance-authority";
|
|
7
7
|
import { OTPField } from "@base-ui/react/otp-field";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const require_chunk = require("../chunk-aJGBMT86.cjs");
|
|
4
4
|
const require_components_field = require("./field.cjs");
|
|
5
|
-
const require_input_box_variants = require("../input-box-variants-
|
|
5
|
+
const require_input_box_variants = require("../input-box-variants-ZCtgs-1S.cjs");
|
|
6
6
|
let react = require("react");
|
|
7
7
|
react = require_chunk.__toESM(react);
|
|
8
8
|
let react_jsx_runtime = require("react/jsx-runtime");
|
package/dist/components/input.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn } from "../utils/cn.js";
|
|
3
3
|
import { useFieldControl } from "./field.js";
|
|
4
|
-
import { n as boxChrome, t as GHOST_UNDERLINE } from "../input-box-variants-
|
|
4
|
+
import { n as boxChrome, t as GHOST_UNDERLINE } from "../input-box-variants-DcajYXvo.js";
|
|
5
5
|
import "react";
|
|
6
6
|
import { jsx } from "react/jsx-runtime";
|
|
7
7
|
import { cva } from "class-variance-authority";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const require_chunk = require("../chunk-aJGBMT86.cjs");
|
|
4
|
+
const require_hooks_use_reduced_motion = require("../hooks/use-reduced-motion.cjs");
|
|
4
5
|
const require_utils_format = require("../utils/format.cjs");
|
|
5
6
|
const require_utils_chart_scale = require("../utils/chart-scale.cjs");
|
|
6
7
|
const require_components_chart = require("./chart.cjs");
|
|
@@ -162,6 +163,7 @@ const LineChart = ({ series, width, height, margin = DEFAULT_MARGIN, curve: defa
|
|
|
162
163
|
value: formatValue(d.value)
|
|
163
164
|
}];
|
|
164
165
|
}) : [];
|
|
166
|
+
const reducedMotion = require_hooks_use_reduced_motion.useReducedMotion();
|
|
165
167
|
const [tooltipRef, tooltipSize] = require_components_chart.useMeasuredSize();
|
|
166
168
|
const tooltipPos = require_components_chart.clampTooltipPosition({
|
|
167
169
|
anchorX: tooltipLeft ?? 0,
|
|
@@ -185,7 +187,7 @@ const LineChart = ({ series, width, height, margin = DEFAULT_MARGIN, curve: defa
|
|
|
185
187
|
top: margin.top,
|
|
186
188
|
children: [
|
|
187
189
|
showGrid && yTicks.map((tick) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("line", {
|
|
188
|
-
className: "stroke-
|
|
190
|
+
className: "stroke-gray-a4",
|
|
189
191
|
strokeDasharray: "4,4",
|
|
190
192
|
x1: 0,
|
|
191
193
|
x2: innerWidth,
|
|
@@ -193,7 +195,7 @@ const LineChart = ({ series, width, height, margin = DEFAULT_MARGIN, curve: defa
|
|
|
193
195
|
y2: yScale(tick)
|
|
194
196
|
}, `grid-y-${tick}`)),
|
|
195
197
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("line", {
|
|
196
|
-
className: "stroke-
|
|
198
|
+
className: "stroke-gray-a6",
|
|
197
199
|
x1: 0,
|
|
198
200
|
x2: innerWidth,
|
|
199
201
|
y1: innerHeight,
|
|
@@ -224,7 +226,7 @@ const LineChart = ({ series, width, height, margin = DEFAULT_MARGIN, curve: defa
|
|
|
224
226
|
}),
|
|
225
227
|
xTicks.map((tick) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("text", {
|
|
226
228
|
dy: "1em",
|
|
227
|
-
fill: "var(--
|
|
229
|
+
fill: "var(--neutral-a11)",
|
|
228
230
|
fontSize: 10,
|
|
229
231
|
textAnchor: "middle",
|
|
230
232
|
x: xScale(tick),
|
|
@@ -232,7 +234,7 @@ const LineChart = ({ series, width, height, margin = DEFAULT_MARGIN, curve: defa
|
|
|
232
234
|
children: formatDate(tick)
|
|
233
235
|
}, `x-${tick.valueOf()}`)),
|
|
234
236
|
yAxisUnit !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("line", {
|
|
235
|
-
stroke: "var(--
|
|
237
|
+
stroke: "var(--neutral-a6)",
|
|
236
238
|
strokeWidth: 1,
|
|
237
239
|
x1: 0,
|
|
238
240
|
x2: 0,
|
|
@@ -242,7 +244,7 @@ const LineChart = ({ series, width, height, margin = DEFAULT_MARGIN, curve: defa
|
|
|
242
244
|
yTicks.map((tick) => {
|
|
243
245
|
const y = yScale(tick);
|
|
244
246
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", { children: [yAxisUnit !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("line", {
|
|
245
|
-
stroke: "var(--
|
|
247
|
+
stroke: "var(--neutral-a8)",
|
|
246
248
|
strokeWidth: 1,
|
|
247
249
|
x1: -4,
|
|
248
250
|
x2: 0,
|
|
@@ -250,7 +252,7 @@ const LineChart = ({ series, width, height, margin = DEFAULT_MARGIN, curve: defa
|
|
|
250
252
|
y2: y
|
|
251
253
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("text", {
|
|
252
254
|
dy: "0.32em",
|
|
253
|
-
fill: "var(--
|
|
255
|
+
fill: "var(--neutral-a11)",
|
|
254
256
|
fontSize: 10,
|
|
255
257
|
textAnchor: "end",
|
|
256
258
|
x: yAxisUnit !== void 0 ? -7 : -4,
|
|
@@ -259,7 +261,7 @@ const LineChart = ({ series, width, height, margin = DEFAULT_MARGIN, curve: defa
|
|
|
259
261
|
})] }, `y-${tick}`);
|
|
260
262
|
}),
|
|
261
263
|
yAxisUnit !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("text", {
|
|
262
|
-
fill: "var(--
|
|
264
|
+
fill: "var(--neutral-a11)",
|
|
263
265
|
fontSize: 10,
|
|
264
266
|
fontWeight: 600,
|
|
265
267
|
textAnchor: "start",
|
|
@@ -289,7 +291,7 @@ const LineChart = ({ series, width, height, margin = DEFAULT_MARGIN, curve: defa
|
|
|
289
291
|
y: 0
|
|
290
292
|
}),
|
|
291
293
|
tooltipOpen && tooltipData && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("line", {
|
|
292
|
-
className: "stroke-
|
|
294
|
+
className: "stroke-gray-a6",
|
|
293
295
|
pointerEvents: "none",
|
|
294
296
|
strokeDasharray: "4,4",
|
|
295
297
|
x1: xScale(tooltipData.date),
|
|
@@ -334,7 +336,7 @@ const LineChart = ({ series, width, height, margin = DEFAULT_MARGIN, curve: defa
|
|
|
334
336
|
left: tooltipPos.left,
|
|
335
337
|
top: tooltipPos.top,
|
|
336
338
|
opacity: tooltipOpen && tooltipData ? 1 : 0,
|
|
337
|
-
transition: "left 140ms ease-out, top 140ms ease-out, opacity 140ms ease-out"
|
|
339
|
+
transition: reducedMotion ? "opacity 140ms ease-out" : "left 140ms ease-out, top 140ms ease-out, opacity 140ms ease-out"
|
|
338
340
|
},
|
|
339
341
|
children: tooltipData && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_components_chart.ChartTooltipCard, {
|
|
340
342
|
label: (formatTooltipDate ?? formatDate)(tooltipData.date),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"line-chart.cjs","names":["curveMonotoneX","curveStep","curveStepAfter","curveStepBefore","curveLinear","localeNumberFormat","buildYAxisScale","useMeasuredSize","clampTooltipPosition","Group","formatYAxisTick","LinePath","ChartTooltipCard"],"sources":["../../src/components/line-chart.tsx"],"sourcesContent":["import {\n curveLinear,\n curveMonotoneX,\n curveStep,\n curveStepAfter,\n curveStepBefore,\n} from '@visx/curve'\nimport { localPoint } from '@visx/event'\nimport { Group } from '@visx/group'\nimport { scaleLinear, scaleTime } from '@visx/scale'\nimport { LinePath } from '@visx/shape'\nimport { useTooltip } from '@visx/tooltip'\nimport { bisector, extent } from '@visx/vendor/d3-array'\nimport * as React from 'react'\nimport { useCallback, useMemo } from 'react'\nimport { buildYAxisScale, formatYAxisTick } from '../utils/chart-scale'\nimport { cn } from '../utils/cn'\nimport { localeNumberFormat } from '../utils/format'\nimport {\n ChartTooltipCard,\n type ChartTooltipRow,\n clampTooltipPosition,\n useMeasuredSize,\n} from './chart'\n\nexport interface LineChartDatum {\n date: Date\n value: number\n}\n\nexport type LineChartCurve =\n | 'monotone'\n | 'step'\n | 'step-after'\n | 'step-before'\n | 'linear'\n\nexport interface LineChartSeries {\n id: string\n data: LineChartDatum[]\n /** Label shown in the hover tooltip. Defaults to `id`. */\n label?: React.ReactNode\n className?: string\n /** Curve interpolation type. Default: inherits from LineChartProps.curve */\n curve?: LineChartCurve\n /** Render as a dashed line */\n dashed?: boolean\n /** Custom dash pattern (e.g. \"8,4\" or \"4,2,1,2\"). Only applies when dashed is true. */\n dashPattern?: string\n}\n\nexport interface LineChartProps {\n series: LineChartSeries[]\n width: number\n height: number\n margin?: { top: number; right: number; bottom: number; left: number }\n /** Default curve for all series. Default: 'monotone' */\n curve?: LineChartCurve\n showGrid?: boolean\n showTooltip?: boolean\n className?: string\n xTickCount?: number\n yTickCount?: number\n /** Fixes the y-axis to an explicit `[min, max]`. Defaults to the data extent. */\n yDomain?: [number, number]\n /** Formats the x-axis tick labels. */\n formatDate?: (date: Date) => string\n /** Formats the tooltip title. Defaults to `formatDate`. */\n formatTooltipDate?: (date: Date) => string\n formatValue?: (value: number) => string\n /**\n * Unit shown once at the top of the y-axis (e.g. \"kW\"). When set, y-axis tick\n * labels render as plain numbers (matching BarChart / PowerHistoryChart)\n * instead of repeating `formatValue` on every tick. `formatValue` still feeds\n * the tooltip. Omit to keep the per-tick `formatValue` labels.\n */\n yAxisUnit?: string\n /**\n * Vertical reference markers positioned on the time axis (e.g. sunrise /\n * sunset). Each renders a dashed line across the plot with an optional label.\n */\n referenceLines?: Array<{ key: string; date: Date; label?: React.ReactNode }>\n /**\n * HTML content pinned to the top of the plot at a given time (e.g. an hourly\n * weather icon). Positioned by the same time scale as the series, so it lines\n * up with the curve below it.\n */\n topContent?: Array<{ key: string; date: Date; content: React.ReactNode }>\n}\n\nconst DEFAULT_MARGIN = { top: 16, right: 16, bottom: 40, left: 48 }\n\nconst CURVE_MAP = {\n monotone: curveMonotoneX,\n step: curveStep,\n 'step-after': curveStepAfter,\n 'step-before': curveStepBefore,\n linear: curveLinear,\n} as const\n\nconst resolveCurve = (type: LineChartCurve) => CURVE_MAP[type]\n\nconst dateBisector = bisector<LineChartDatum, Date>((d) => d.date)\nconst bisectDate = (data: LineChartDatum[], x: Date, lo?: number) =>\n dateBisector.left(data, x, lo)\n\n/** Whether `date` falls within a series' own x-range (data is sorted ascending). */\nfunction withinDomain(data: LineChartDatum[], date: Date): boolean {\n const first = data[0]\n const last = data[data.length - 1]\n if (!first || !last) return false\n const t = date.valueOf()\n return t >= first.date.valueOf() && t <= last.date.valueOf()\n}\n\n/**\n * y-domain padded 10% beyond the data extent. The baseline is pinned to 0 so\n * all-positive series render from the axis up; a series that dips below 0\n * (signed grid / battery power) extends the domain downward to keep the zero\n * crossing visible.\n */\nfunction computeYDomain(data: LineChartDatum[]): [number, number] {\n let min = 0\n let max = 0\n for (const d of data) {\n if (d.value < min) min = d.value\n if (d.value > max) max = d.value\n }\n if (min === max) return [min, min + 1]\n return [min * 1.1, max * 1.1]\n}\n\nfunction nearestDatum(\n data: LineChartDatum[],\n date: Date,\n): LineChartDatum | undefined {\n if (data.length === 0) return undefined\n const index = bisectDate(data, date, 1)\n const d0 = data[index - 1]\n const d1 = data[index]\n if (!d0) return d1\n if (!d1) return d0\n return date.valueOf() - d0.date.valueOf() > d1.date.valueOf() - date.valueOf()\n ? d1\n : d0\n}\n\nconst defaultFormatDate = (date: Date) =>\n date.toLocaleDateString(undefined, { month: 'short', day: 'numeric' })\n\nconst defaultValueFormat = localeNumberFormat()\nconst defaultFormatValue = (value: number) => defaultValueFormat.format(value)\n\nconst LINE_COLORS = [\n 'stroke-spark-9',\n 'stroke-green-9',\n 'stroke-blue-9',\n 'stroke-orange-9',\n 'stroke-red-9',\n]\n\nconst DOT_COLORS = [\n 'fill-spark-9',\n 'fill-green-9',\n 'fill-blue-9',\n 'fill-orange-9',\n 'fill-red-9',\n]\n\n// CSS-var colours matching LINE_COLORS, used for the tooltip legend dots.\nconst LEGEND_COLORS = [\n 'var(--spark-9)',\n 'var(--green-9)',\n 'var(--blue-9)',\n 'var(--orange-9)',\n 'var(--red-9)',\n]\n\nconst LineChart: React.FC<LineChartProps> = ({\n series,\n width,\n height,\n margin = DEFAULT_MARGIN,\n curve: defaultCurve = 'monotone',\n showGrid = true,\n showTooltip: enableTooltip = true,\n className,\n xTickCount = 5,\n yTickCount = 4,\n formatDate = defaultFormatDate,\n formatTooltipDate,\n formatValue = defaultFormatValue,\n yAxisUnit,\n yDomain,\n referenceLines,\n topContent,\n}) => {\n const {\n showTooltip,\n hideTooltip,\n tooltipData,\n tooltipLeft,\n tooltipTop,\n tooltipOpen,\n } = useTooltip<{ date: Date }>()\n\n const innerWidth = Math.max(0, width - margin.left - margin.right)\n const innerHeight = Math.max(0, height - margin.top - margin.bottom)\n\n const allData = useMemo(() => series.flatMap((s) => s.data), [series])\n\n const xScale = useMemo(\n () =>\n scaleTime({\n range: [0, innerWidth],\n domain: extent(allData, (d) => d.date) as [Date, Date],\n }),\n [allData, innerWidth],\n )\n\n // With a unit, the y-axis is generated by the shared scale util (nice ticks\n // + rounded bounds) so it matches BarChart / PowerHistoryChart exactly.\n const yAxisScale = useMemo(() => {\n if (yAxisUnit === undefined) return null\n let min = 0\n let max = 0\n for (const d of allData) {\n if (d.value < min) min = d.value\n if (d.value > max) max = d.value\n }\n return buildYAxisScale(min, max)\n }, [allData, yAxisUnit])\n\n const yScale = useMemo(\n () =>\n scaleLinear({\n range: [innerHeight, 0],\n domain:\n yDomain ??\n (yAxisScale\n ? [yAxisScale.min, yAxisScale.max]\n : computeYDomain(allData)),\n nice: !yDomain && !yAxisScale,\n }),\n [allData, innerHeight, yDomain, yAxisScale],\n )\n\n const xTicks = xScale.ticks(xTickCount)\n const yTicks = yAxisScale ? yAxisScale.ticks : yScale.ticks(yTickCount)\n\n const handleTooltip = useCallback(\n (\n event:\n | React.TouchEvent<SVGRectElement>\n | React.MouseEvent<SVGRectElement>,\n ) => {\n if (!enableTooltip) return\n\n const point = localPoint(event)\n if (!point) return\n\n const x0 = xScale.invert(point.x - margin.left)\n\n // Snap to the data point closest to the cursor across all series, so the\n // cursor line + tooltip line up with real values.\n let anchorDate: Date | null = null\n let bestDistance = Infinity\n for (const s of series) {\n const d = nearestDatum(s.data, x0)\n if (!d) continue\n const distance = Math.abs(d.date.valueOf() - x0.valueOf())\n if (distance < bestDistance) {\n bestDistance = distance\n anchorDate = d.date\n }\n }\n\n if (!anchorDate) return\n\n showTooltip({\n tooltipData: { date: anchorDate },\n tooltipLeft: xScale(anchorDate) + margin.left,\n tooltipTop: margin.top,\n })\n },\n [enableTooltip, margin, series, showTooltip, xScale],\n )\n\n const tooltipRows: ChartTooltipRow[] = tooltipData\n ? series.flatMap((s, i) => {\n const d = nearestDatum(s.data, tooltipData.date)\n if (!d || !withinDomain(s.data, tooltipData.date)) return []\n return [\n {\n key: s.id,\n label: s.label ?? s.id,\n color: LEGEND_COLORS[i % LEGEND_COLORS.length] as string,\n value: formatValue(d.value),\n },\n ]\n })\n : []\n\n const [tooltipRef, tooltipSize] = useMeasuredSize<HTMLDivElement>()\n const tooltipPos = clampTooltipPosition({\n anchorX: tooltipLeft ?? 0,\n anchorY: tooltipTop ?? margin.top,\n width,\n height,\n tipWidth: tooltipSize.width,\n tipHeight: tooltipSize.height,\n placement: 'beside',\n })\n\n if (width < 10 || height < 10) return null\n\n return (\n <div className={cn('relative', className)}>\n <svg className=\"block\" height={height} width={width}>\n <Group left={margin.left} top={margin.top}>\n {/* Grid lines */}\n {showGrid &&\n yTicks.map((tick) => (\n <line\n className=\"stroke-slate-a4\"\n key={`grid-y-${tick}`}\n strokeDasharray=\"4,4\"\n x1={0}\n x2={innerWidth}\n y1={yScale(tick)}\n y2={yScale(tick)}\n />\n ))}\n\n {/* X axis */}\n <line\n className=\"stroke-slate-a6\"\n x1={0}\n x2={innerWidth}\n y1={innerHeight}\n y2={innerHeight}\n />\n\n {/* Reference markers (e.g. sunrise / sunset) */}\n {referenceLines?.map((ref) => {\n const x = xScale(ref.date)\n if (!Number.isFinite(x)) return null\n // Sit the label beside the line, on whichever side keeps it in\n // frame: right of a left-half marker, left of a right-half one.\n const anchorEnd = x > innerWidth / 2\n return (\n <g key={ref.key} pointerEvents=\"none\">\n <line\n className=\"stroke-orange-8\"\n strokeDasharray=\"3,3\"\n x1={x}\n x2={x}\n y1={0}\n y2={innerHeight}\n />\n {ref.label != null && (\n <text\n className=\"fill-orange-11 text-[10px]\"\n dy=\"0.9em\"\n textAnchor={anchorEnd ? 'end' : 'start'}\n x={x + (anchorEnd ? -4 : 4)}\n y={0}\n >\n {ref.label}\n </text>\n )}\n </g>\n )\n })}\n\n {/* X axis labels */}\n {xTicks.map((tick) => (\n <text\n dy=\"1em\"\n fill=\"var(--gray-a11)\"\n fontSize={10}\n key={`x-${tick.valueOf()}`}\n textAnchor=\"middle\"\n x={xScale(tick)}\n y={innerHeight + 8}\n >\n {formatDate(tick)}\n </text>\n ))}\n\n {/* Y axis. With `yAxisUnit`, matches BarChart: a vertical axis line,\n short tick marks, plain numeric ticks, and the unit as a bold\n top-left header (top tick hidden). Without it, ticks repeat\n `formatValue` and no axis line/marks are drawn. */}\n {yAxisUnit !== undefined && (\n <line\n stroke=\"var(--gray-a6)\"\n strokeWidth={1}\n x1={0}\n x2={0}\n y1={0}\n y2={innerHeight}\n />\n )}\n {yTicks.map((tick) => {\n const y = yScale(tick)\n return (\n <g key={`y-${tick}`}>\n {yAxisUnit !== undefined && (\n <line\n stroke=\"var(--gray-a8)\"\n strokeWidth={1}\n x1={-4}\n x2={0}\n y1={y}\n y2={y}\n />\n )}\n <text\n dy=\"0.32em\"\n fill=\"var(--gray-a11)\"\n fontSize={10}\n textAnchor=\"end\"\n x={yAxisUnit !== undefined ? -7 : -4}\n y={y}\n >\n {yAxisUnit !== undefined\n ? formatYAxisTick(tick)\n : formatValue(tick)}\n </text>\n </g>\n )\n })}\n {yAxisUnit !== undefined && (\n <text\n fill=\"var(--gray-a11)\"\n fontSize={10}\n fontWeight={600}\n textAnchor=\"start\"\n x={-margin.left}\n y={-6}\n >\n {yAxisUnit}\n </text>\n )}\n\n {/* Lines */}\n {series.map((s, i) => (\n <LinePath\n className={cn(LINE_COLORS[i % LINE_COLORS.length], s.className)}\n curve={resolveCurve(s.curve ?? defaultCurve)}\n data={s.data}\n fill=\"none\"\n key={s.id}\n strokeDasharray={s.dashed ? (s.dashPattern ?? '6,4') : undefined}\n strokeWidth={2}\n x={(d) => xScale(d.date)}\n y={(d) => yScale(d.value)}\n />\n ))}\n\n {/* Tooltip hover target */}\n {enableTooltip && (\n <rect\n fill=\"transparent\"\n height={innerHeight}\n onMouseLeave={hideTooltip}\n onMouseMove={handleTooltip}\n onTouchEnd={hideTooltip}\n onTouchMove={handleTooltip}\n width={innerWidth}\n x={0}\n y={0}\n />\n )}\n\n {/* Cursor line + a dot per series */}\n {tooltipOpen && tooltipData && (\n <>\n <line\n className=\"stroke-slate-a6\"\n pointerEvents=\"none\"\n strokeDasharray=\"4,4\"\n x1={xScale(tooltipData.date)}\n x2={xScale(tooltipData.date)}\n y1={0}\n y2={innerHeight}\n />\n {series.map((s, i) => {\n const d = nearestDatum(s.data, tooltipData.date)\n if (!d || !withinDomain(s.data, tooltipData.date)) return null\n return (\n <circle\n key={s.id}\n className={cn(DOT_COLORS[i % DOT_COLORS.length])}\n cx={xScale(d.date)}\n cy={yScale(d.value)}\n pointerEvents=\"none\"\n r={4}\n stroke=\"white\"\n strokeWidth={2}\n />\n )\n })}\n </>\n )}\n </Group>\n </svg>\n\n {topContent && topContent.length > 0 && (\n <div className=\"pointer-events-none absolute inset-0\">\n {topContent.map((item) => {\n const x = xScale(item.date)\n if (!Number.isFinite(x)) return null\n return (\n <div\n key={item.key}\n className=\"absolute -translate-x-1/2\"\n style={{ left: margin.left + x, top: 0 }}\n >\n {item.content}\n </div>\n )\n })}\n </div>\n )}\n\n <div\n ref={tooltipRef}\n className=\"pointer-events-none absolute z-10\"\n style={{\n left: tooltipPos.left,\n top: tooltipPos.top,\n opacity: tooltipOpen && tooltipData ? 1 : 0,\n transition:\n 'left 140ms ease-out, top 140ms ease-out, opacity 140ms ease-out',\n }}\n >\n {tooltipData && (\n <ChartTooltipCard\n label={(formatTooltipDate ?? formatDate)(tooltipData.date)}\n rows={tooltipRows}\n />\n )}\n </div>\n </div>\n )\n}\n\nexport { LineChart }\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"line-chart.cjs","names":["curveMonotoneX","curveStep","curveStepAfter","curveStepBefore","curveLinear","localeNumberFormat","buildYAxisScale","useReducedMotion","useMeasuredSize","clampTooltipPosition","Group","formatYAxisTick","LinePath","ChartTooltipCard"],"sources":["../../src/components/line-chart.tsx"],"sourcesContent":["import {\n curveLinear,\n curveMonotoneX,\n curveStep,\n curveStepAfter,\n curveStepBefore,\n} from '@visx/curve'\nimport { localPoint } from '@visx/event'\nimport { Group } from '@visx/group'\nimport { scaleLinear, scaleTime } from '@visx/scale'\nimport { LinePath } from '@visx/shape'\nimport { useTooltip } from '@visx/tooltip'\nimport { bisector, extent } from '@visx/vendor/d3-array'\nimport * as React from 'react'\nimport { useCallback, useMemo } from 'react'\nimport { useReducedMotion } from '../hooks/use-reduced-motion'\nimport { buildYAxisScale, formatYAxisTick } from '../utils/chart-scale'\nimport { cn } from '../utils/cn'\nimport { localeNumberFormat } from '../utils/format'\nimport {\n ChartTooltipCard,\n type ChartTooltipRow,\n clampTooltipPosition,\n useMeasuredSize,\n} from './chart'\n\nexport interface LineChartDatum {\n date: Date\n value: number\n}\n\nexport type LineChartCurve =\n | 'monotone'\n | 'step'\n | 'step-after'\n | 'step-before'\n | 'linear'\n\nexport interface LineChartSeries {\n id: string\n data: LineChartDatum[]\n /** Label shown in the hover tooltip. Defaults to `id`. */\n label?: React.ReactNode\n className?: string\n /** Curve interpolation type. Default: inherits from LineChartProps.curve */\n curve?: LineChartCurve\n /** Render as a dashed line */\n dashed?: boolean\n /** Custom dash pattern (e.g. \"8,4\" or \"4,2,1,2\"). Only applies when dashed is true. */\n dashPattern?: string\n}\n\nexport interface LineChartProps {\n series: LineChartSeries[]\n width: number\n height: number\n margin?: { top: number; right: number; bottom: number; left: number }\n /** Default curve for all series. Default: 'monotone' */\n curve?: LineChartCurve\n showGrid?: boolean\n showTooltip?: boolean\n className?: string\n xTickCount?: number\n yTickCount?: number\n /** Fixes the y-axis to an explicit `[min, max]`. Defaults to the data extent. */\n yDomain?: [number, number]\n /** Formats the x-axis tick labels. */\n formatDate?: (date: Date) => string\n /** Formats the tooltip title. Defaults to `formatDate`. */\n formatTooltipDate?: (date: Date) => string\n formatValue?: (value: number) => string\n /**\n * Unit shown once at the top of the y-axis (e.g. \"kW\"). When set, y-axis tick\n * labels render as plain numbers (matching BarChart / PowerHistoryChart)\n * instead of repeating `formatValue` on every tick. `formatValue` still feeds\n * the tooltip. Omit to keep the per-tick `formatValue` labels.\n */\n yAxisUnit?: string\n /**\n * Vertical reference markers positioned on the time axis (e.g. sunrise /\n * sunset). Each renders a dashed line across the plot with an optional label.\n */\n referenceLines?: Array<{ key: string; date: Date; label?: React.ReactNode }>\n /**\n * HTML content pinned to the top of the plot at a given time (e.g. an hourly\n * weather icon). Positioned by the same time scale as the series, so it lines\n * up with the curve below it.\n */\n topContent?: Array<{ key: string; date: Date; content: React.ReactNode }>\n}\n\nconst DEFAULT_MARGIN = { top: 16, right: 16, bottom: 40, left: 48 }\n\nconst CURVE_MAP = {\n monotone: curveMonotoneX,\n step: curveStep,\n 'step-after': curveStepAfter,\n 'step-before': curveStepBefore,\n linear: curveLinear,\n} as const\n\nconst resolveCurve = (type: LineChartCurve) => CURVE_MAP[type]\n\nconst dateBisector = bisector<LineChartDatum, Date>((d) => d.date)\nconst bisectDate = (data: LineChartDatum[], x: Date, lo?: number) =>\n dateBisector.left(data, x, lo)\n\n/** Whether `date` falls within a series' own x-range (data is sorted ascending). */\nfunction withinDomain(data: LineChartDatum[], date: Date): boolean {\n const first = data[0]\n const last = data[data.length - 1]\n if (!first || !last) return false\n const t = date.valueOf()\n return t >= first.date.valueOf() && t <= last.date.valueOf()\n}\n\n/**\n * y-domain padded 10% beyond the data extent. The baseline is pinned to 0 so\n * all-positive series render from the axis up; a series that dips below 0\n * (signed grid / battery power) extends the domain downward to keep the zero\n * crossing visible.\n */\nfunction computeYDomain(data: LineChartDatum[]): [number, number] {\n let min = 0\n let max = 0\n for (const d of data) {\n if (d.value < min) min = d.value\n if (d.value > max) max = d.value\n }\n if (min === max) return [min, min + 1]\n return [min * 1.1, max * 1.1]\n}\n\nfunction nearestDatum(\n data: LineChartDatum[],\n date: Date,\n): LineChartDatum | undefined {\n if (data.length === 0) return undefined\n const index = bisectDate(data, date, 1)\n const d0 = data[index - 1]\n const d1 = data[index]\n if (!d0) return d1\n if (!d1) return d0\n return date.valueOf() - d0.date.valueOf() > d1.date.valueOf() - date.valueOf()\n ? d1\n : d0\n}\n\nconst defaultFormatDate = (date: Date) =>\n date.toLocaleDateString(undefined, { month: 'short', day: 'numeric' })\n\nconst defaultValueFormat = localeNumberFormat()\nconst defaultFormatValue = (value: number) => defaultValueFormat.format(value)\n\nconst LINE_COLORS = [\n 'stroke-spark-9',\n 'stroke-green-9',\n 'stroke-blue-9',\n 'stroke-orange-9',\n 'stroke-red-9',\n]\n\nconst DOT_COLORS = [\n 'fill-spark-9',\n 'fill-green-9',\n 'fill-blue-9',\n 'fill-orange-9',\n 'fill-red-9',\n]\n\n// CSS-var colours matching LINE_COLORS, used for the tooltip legend dots.\nconst LEGEND_COLORS = [\n 'var(--spark-9)',\n 'var(--green-9)',\n 'var(--blue-9)',\n 'var(--orange-9)',\n 'var(--red-9)',\n]\n\nconst LineChart: React.FC<LineChartProps> = ({\n series,\n width,\n height,\n margin = DEFAULT_MARGIN,\n curve: defaultCurve = 'monotone',\n showGrid = true,\n showTooltip: enableTooltip = true,\n className,\n xTickCount = 5,\n yTickCount = 4,\n formatDate = defaultFormatDate,\n formatTooltipDate,\n formatValue = defaultFormatValue,\n yAxisUnit,\n yDomain,\n referenceLines,\n topContent,\n}) => {\n const {\n showTooltip,\n hideTooltip,\n tooltipData,\n tooltipLeft,\n tooltipTop,\n tooltipOpen,\n } = useTooltip<{ date: Date }>()\n\n const innerWidth = Math.max(0, width - margin.left - margin.right)\n const innerHeight = Math.max(0, height - margin.top - margin.bottom)\n\n const allData = useMemo(() => series.flatMap((s) => s.data), [series])\n\n const xScale = useMemo(\n () =>\n scaleTime({\n range: [0, innerWidth],\n domain: extent(allData, (d) => d.date) as [Date, Date],\n }),\n [allData, innerWidth],\n )\n\n // With a unit, the y-axis is generated by the shared scale util (nice ticks\n // + rounded bounds) so it matches BarChart / PowerHistoryChart exactly.\n const yAxisScale = useMemo(() => {\n if (yAxisUnit === undefined) return null\n let min = 0\n let max = 0\n for (const d of allData) {\n if (d.value < min) min = d.value\n if (d.value > max) max = d.value\n }\n return buildYAxisScale(min, max)\n }, [allData, yAxisUnit])\n\n const yScale = useMemo(\n () =>\n scaleLinear({\n range: [innerHeight, 0],\n domain:\n yDomain ??\n (yAxisScale\n ? [yAxisScale.min, yAxisScale.max]\n : computeYDomain(allData)),\n nice: !yDomain && !yAxisScale,\n }),\n [allData, innerHeight, yDomain, yAxisScale],\n )\n\n const xTicks = xScale.ticks(xTickCount)\n const yTicks = yAxisScale ? yAxisScale.ticks : yScale.ticks(yTickCount)\n\n const handleTooltip = useCallback(\n (\n event:\n | React.TouchEvent<SVGRectElement>\n | React.MouseEvent<SVGRectElement>,\n ) => {\n if (!enableTooltip) return\n\n const point = localPoint(event)\n if (!point) return\n\n const x0 = xScale.invert(point.x - margin.left)\n\n // Snap to the data point closest to the cursor across all series, so the\n // cursor line + tooltip line up with real values.\n let anchorDate: Date | null = null\n let bestDistance = Infinity\n for (const s of series) {\n const d = nearestDatum(s.data, x0)\n if (!d) continue\n const distance = Math.abs(d.date.valueOf() - x0.valueOf())\n if (distance < bestDistance) {\n bestDistance = distance\n anchorDate = d.date\n }\n }\n\n if (!anchorDate) return\n\n showTooltip({\n tooltipData: { date: anchorDate },\n tooltipLeft: xScale(anchorDate) + margin.left,\n tooltipTop: margin.top,\n })\n },\n [enableTooltip, margin, series, showTooltip, xScale],\n )\n\n const tooltipRows: ChartTooltipRow[] = tooltipData\n ? series.flatMap((s, i) => {\n const d = nearestDatum(s.data, tooltipData.date)\n if (!d || !withinDomain(s.data, tooltipData.date)) return []\n return [\n {\n key: s.id,\n label: s.label ?? s.id,\n color: LEGEND_COLORS[i % LEGEND_COLORS.length] as string,\n value: formatValue(d.value),\n },\n ]\n })\n : []\n\n const reducedMotion = useReducedMotion()\n const [tooltipRef, tooltipSize] = useMeasuredSize<HTMLDivElement>()\n const tooltipPos = clampTooltipPosition({\n anchorX: tooltipLeft ?? 0,\n anchorY: tooltipTop ?? margin.top,\n width,\n height,\n tipWidth: tooltipSize.width,\n tipHeight: tooltipSize.height,\n placement: 'beside',\n })\n\n if (width < 10 || height < 10) return null\n\n return (\n <div className={cn('relative', className)}>\n <svg className=\"block\" height={height} width={width}>\n <Group left={margin.left} top={margin.top}>\n {/* Grid lines */}\n {showGrid &&\n yTicks.map((tick) => (\n <line\n className=\"stroke-gray-a4\"\n key={`grid-y-${tick}`}\n strokeDasharray=\"4,4\"\n x1={0}\n x2={innerWidth}\n y1={yScale(tick)}\n y2={yScale(tick)}\n />\n ))}\n\n {/* X axis */}\n <line\n className=\"stroke-gray-a6\"\n x1={0}\n x2={innerWidth}\n y1={innerHeight}\n y2={innerHeight}\n />\n\n {/* Reference markers (e.g. sunrise / sunset) */}\n {referenceLines?.map((ref) => {\n const x = xScale(ref.date)\n if (!Number.isFinite(x)) return null\n // Sit the label beside the line, on whichever side keeps it in\n // frame: right of a left-half marker, left of a right-half one.\n const anchorEnd = x > innerWidth / 2\n return (\n <g key={ref.key} pointerEvents=\"none\">\n <line\n className=\"stroke-orange-8\"\n strokeDasharray=\"3,3\"\n x1={x}\n x2={x}\n y1={0}\n y2={innerHeight}\n />\n {ref.label != null && (\n <text\n className=\"fill-orange-11 text-[10px]\"\n dy=\"0.9em\"\n textAnchor={anchorEnd ? 'end' : 'start'}\n x={x + (anchorEnd ? -4 : 4)}\n y={0}\n >\n {ref.label}\n </text>\n )}\n </g>\n )\n })}\n\n {/* X axis labels */}\n {xTicks.map((tick) => (\n <text\n dy=\"1em\"\n fill=\"var(--neutral-a11)\"\n fontSize={10}\n key={`x-${tick.valueOf()}`}\n textAnchor=\"middle\"\n x={xScale(tick)}\n y={innerHeight + 8}\n >\n {formatDate(tick)}\n </text>\n ))}\n\n {/* Y axis. With `yAxisUnit`, matches BarChart: a vertical axis line,\n short tick marks, plain numeric ticks, and the unit as a bold\n top-left header (top tick hidden). Without it, ticks repeat\n `formatValue` and no axis line/marks are drawn. */}\n {yAxisUnit !== undefined && (\n <line\n stroke=\"var(--neutral-a6)\"\n strokeWidth={1}\n x1={0}\n x2={0}\n y1={0}\n y2={innerHeight}\n />\n )}\n {yTicks.map((tick) => {\n const y = yScale(tick)\n return (\n <g key={`y-${tick}`}>\n {yAxisUnit !== undefined && (\n <line\n stroke=\"var(--neutral-a8)\"\n strokeWidth={1}\n x1={-4}\n x2={0}\n y1={y}\n y2={y}\n />\n )}\n <text\n dy=\"0.32em\"\n fill=\"var(--neutral-a11)\"\n fontSize={10}\n textAnchor=\"end\"\n x={yAxisUnit !== undefined ? -7 : -4}\n y={y}\n >\n {yAxisUnit !== undefined\n ? formatYAxisTick(tick)\n : formatValue(tick)}\n </text>\n </g>\n )\n })}\n {yAxisUnit !== undefined && (\n <text\n fill=\"var(--neutral-a11)\"\n fontSize={10}\n fontWeight={600}\n textAnchor=\"start\"\n x={-margin.left}\n y={-6}\n >\n {yAxisUnit}\n </text>\n )}\n\n {/* Lines */}\n {series.map((s, i) => (\n <LinePath\n className={cn(LINE_COLORS[i % LINE_COLORS.length], s.className)}\n curve={resolveCurve(s.curve ?? defaultCurve)}\n data={s.data}\n fill=\"none\"\n key={s.id}\n strokeDasharray={s.dashed ? (s.dashPattern ?? '6,4') : undefined}\n strokeWidth={2}\n x={(d) => xScale(d.date)}\n y={(d) => yScale(d.value)}\n />\n ))}\n\n {/* Tooltip hover target */}\n {enableTooltip && (\n <rect\n fill=\"transparent\"\n height={innerHeight}\n onMouseLeave={hideTooltip}\n onMouseMove={handleTooltip}\n onTouchEnd={hideTooltip}\n onTouchMove={handleTooltip}\n width={innerWidth}\n x={0}\n y={0}\n />\n )}\n\n {/* Cursor line + a dot per series */}\n {tooltipOpen && tooltipData && (\n <>\n <line\n className=\"stroke-gray-a6\"\n pointerEvents=\"none\"\n strokeDasharray=\"4,4\"\n x1={xScale(tooltipData.date)}\n x2={xScale(tooltipData.date)}\n y1={0}\n y2={innerHeight}\n />\n {series.map((s, i) => {\n const d = nearestDatum(s.data, tooltipData.date)\n if (!d || !withinDomain(s.data, tooltipData.date)) return null\n return (\n <circle\n key={s.id}\n className={cn(DOT_COLORS[i % DOT_COLORS.length])}\n cx={xScale(d.date)}\n cy={yScale(d.value)}\n pointerEvents=\"none\"\n r={4}\n stroke=\"white\"\n strokeWidth={2}\n />\n )\n })}\n </>\n )}\n </Group>\n </svg>\n\n {topContent && topContent.length > 0 && (\n <div className=\"pointer-events-none absolute inset-0\">\n {topContent.map((item) => {\n const x = xScale(item.date)\n if (!Number.isFinite(x)) return null\n return (\n <div\n key={item.key}\n className=\"absolute -translate-x-1/2\"\n style={{ left: margin.left + x, top: 0 }}\n >\n {item.content}\n </div>\n )\n })}\n </div>\n )}\n\n <div\n ref={tooltipRef}\n className=\"pointer-events-none absolute z-10\"\n style={{\n left: tooltipPos.left,\n top: tooltipPos.top,\n opacity: tooltipOpen && tooltipData ? 1 : 0,\n transition: reducedMotion\n ? 'opacity 140ms ease-out'\n : 'left 140ms ease-out, top 140ms ease-out, opacity 140ms ease-out',\n }}\n >\n {tooltipData && (\n <ChartTooltipCard\n label={(formatTooltipDate ?? formatDate)(tooltipData.date)}\n rows={tooltipRows}\n />\n )}\n </div>\n </div>\n )\n}\n\nexport { LineChart }\n"],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import { useReducedMotion } from "../hooks/use-reduced-motion.js";
|
|
2
3
|
import { cn } from "../utils/cn.js";
|
|
3
4
|
import { localeNumberFormat } from "../utils/format.js";
|
|
4
5
|
import { buildYAxisScale, formatYAxisTick } from "../utils/chart-scale.js";
|
|
@@ -159,6 +160,7 @@ const LineChart = ({ series, width, height, margin = DEFAULT_MARGIN, curve: defa
|
|
|
159
160
|
value: formatValue(d.value)
|
|
160
161
|
}];
|
|
161
162
|
}) : [];
|
|
163
|
+
const reducedMotion = useReducedMotion();
|
|
162
164
|
const [tooltipRef, tooltipSize] = useMeasuredSize();
|
|
163
165
|
const tooltipPos = clampTooltipPosition({
|
|
164
166
|
anchorX: tooltipLeft ?? 0,
|
|
@@ -182,7 +184,7 @@ const LineChart = ({ series, width, height, margin = DEFAULT_MARGIN, curve: defa
|
|
|
182
184
|
top: margin.top,
|
|
183
185
|
children: [
|
|
184
186
|
showGrid && yTicks.map((tick) => /* @__PURE__ */ jsx("line", {
|
|
185
|
-
className: "stroke-
|
|
187
|
+
className: "stroke-gray-a4",
|
|
186
188
|
strokeDasharray: "4,4",
|
|
187
189
|
x1: 0,
|
|
188
190
|
x2: innerWidth,
|
|
@@ -190,7 +192,7 @@ const LineChart = ({ series, width, height, margin = DEFAULT_MARGIN, curve: defa
|
|
|
190
192
|
y2: yScale(tick)
|
|
191
193
|
}, `grid-y-${tick}`)),
|
|
192
194
|
/* @__PURE__ */ jsx("line", {
|
|
193
|
-
className: "stroke-
|
|
195
|
+
className: "stroke-gray-a6",
|
|
194
196
|
x1: 0,
|
|
195
197
|
x2: innerWidth,
|
|
196
198
|
y1: innerHeight,
|
|
@@ -221,7 +223,7 @@ const LineChart = ({ series, width, height, margin = DEFAULT_MARGIN, curve: defa
|
|
|
221
223
|
}),
|
|
222
224
|
xTicks.map((tick) => /* @__PURE__ */ jsx("text", {
|
|
223
225
|
dy: "1em",
|
|
224
|
-
fill: "var(--
|
|
226
|
+
fill: "var(--neutral-a11)",
|
|
225
227
|
fontSize: 10,
|
|
226
228
|
textAnchor: "middle",
|
|
227
229
|
x: xScale(tick),
|
|
@@ -229,7 +231,7 @@ const LineChart = ({ series, width, height, margin = DEFAULT_MARGIN, curve: defa
|
|
|
229
231
|
children: formatDate(tick)
|
|
230
232
|
}, `x-${tick.valueOf()}`)),
|
|
231
233
|
yAxisUnit !== void 0 && /* @__PURE__ */ jsx("line", {
|
|
232
|
-
stroke: "var(--
|
|
234
|
+
stroke: "var(--neutral-a6)",
|
|
233
235
|
strokeWidth: 1,
|
|
234
236
|
x1: 0,
|
|
235
237
|
x2: 0,
|
|
@@ -239,7 +241,7 @@ const LineChart = ({ series, width, height, margin = DEFAULT_MARGIN, curve: defa
|
|
|
239
241
|
yTicks.map((tick) => {
|
|
240
242
|
const y = yScale(tick);
|
|
241
243
|
return /* @__PURE__ */ jsxs("g", { children: [yAxisUnit !== void 0 && /* @__PURE__ */ jsx("line", {
|
|
242
|
-
stroke: "var(--
|
|
244
|
+
stroke: "var(--neutral-a8)",
|
|
243
245
|
strokeWidth: 1,
|
|
244
246
|
x1: -4,
|
|
245
247
|
x2: 0,
|
|
@@ -247,7 +249,7 @@ const LineChart = ({ series, width, height, margin = DEFAULT_MARGIN, curve: defa
|
|
|
247
249
|
y2: y
|
|
248
250
|
}), /* @__PURE__ */ jsx("text", {
|
|
249
251
|
dy: "0.32em",
|
|
250
|
-
fill: "var(--
|
|
252
|
+
fill: "var(--neutral-a11)",
|
|
251
253
|
fontSize: 10,
|
|
252
254
|
textAnchor: "end",
|
|
253
255
|
x: yAxisUnit !== void 0 ? -7 : -4,
|
|
@@ -256,7 +258,7 @@ const LineChart = ({ series, width, height, margin = DEFAULT_MARGIN, curve: defa
|
|
|
256
258
|
})] }, `y-${tick}`);
|
|
257
259
|
}),
|
|
258
260
|
yAxisUnit !== void 0 && /* @__PURE__ */ jsx("text", {
|
|
259
|
-
fill: "var(--
|
|
261
|
+
fill: "var(--neutral-a11)",
|
|
260
262
|
fontSize: 10,
|
|
261
263
|
fontWeight: 600,
|
|
262
264
|
textAnchor: "start",
|
|
@@ -286,7 +288,7 @@ const LineChart = ({ series, width, height, margin = DEFAULT_MARGIN, curve: defa
|
|
|
286
288
|
y: 0
|
|
287
289
|
}),
|
|
288
290
|
tooltipOpen && tooltipData && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("line", {
|
|
289
|
-
className: "stroke-
|
|
291
|
+
className: "stroke-gray-a6",
|
|
290
292
|
pointerEvents: "none",
|
|
291
293
|
strokeDasharray: "4,4",
|
|
292
294
|
x1: xScale(tooltipData.date),
|
|
@@ -331,7 +333,7 @@ const LineChart = ({ series, width, height, margin = DEFAULT_MARGIN, curve: defa
|
|
|
331
333
|
left: tooltipPos.left,
|
|
332
334
|
top: tooltipPos.top,
|
|
333
335
|
opacity: tooltipOpen && tooltipData ? 1 : 0,
|
|
334
|
-
transition: "left 140ms ease-out, top 140ms ease-out, opacity 140ms ease-out"
|
|
336
|
+
transition: reducedMotion ? "opacity 140ms ease-out" : "left 140ms ease-out, top 140ms ease-out, opacity 140ms ease-out"
|
|
335
337
|
},
|
|
336
338
|
children: tooltipData && /* @__PURE__ */ jsx(ChartTooltipCard, {
|
|
337
339
|
label: (formatTooltipDate ?? formatDate)(tooltipData.date),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"line-chart.js","names":[],"sources":["../../src/components/line-chart.tsx"],"sourcesContent":["import {\n curveLinear,\n curveMonotoneX,\n curveStep,\n curveStepAfter,\n curveStepBefore,\n} from '@visx/curve'\nimport { localPoint } from '@visx/event'\nimport { Group } from '@visx/group'\nimport { scaleLinear, scaleTime } from '@visx/scale'\nimport { LinePath } from '@visx/shape'\nimport { useTooltip } from '@visx/tooltip'\nimport { bisector, extent } from '@visx/vendor/d3-array'\nimport * as React from 'react'\nimport { useCallback, useMemo } from 'react'\nimport { buildYAxisScale, formatYAxisTick } from '../utils/chart-scale'\nimport { cn } from '../utils/cn'\nimport { localeNumberFormat } from '../utils/format'\nimport {\n ChartTooltipCard,\n type ChartTooltipRow,\n clampTooltipPosition,\n useMeasuredSize,\n} from './chart'\n\nexport interface LineChartDatum {\n date: Date\n value: number\n}\n\nexport type LineChartCurve =\n | 'monotone'\n | 'step'\n | 'step-after'\n | 'step-before'\n | 'linear'\n\nexport interface LineChartSeries {\n id: string\n data: LineChartDatum[]\n /** Label shown in the hover tooltip. Defaults to `id`. */\n label?: React.ReactNode\n className?: string\n /** Curve interpolation type. Default: inherits from LineChartProps.curve */\n curve?: LineChartCurve\n /** Render as a dashed line */\n dashed?: boolean\n /** Custom dash pattern (e.g. \"8,4\" or \"4,2,1,2\"). Only applies when dashed is true. */\n dashPattern?: string\n}\n\nexport interface LineChartProps {\n series: LineChartSeries[]\n width: number\n height: number\n margin?: { top: number; right: number; bottom: number; left: number }\n /** Default curve for all series. Default: 'monotone' */\n curve?: LineChartCurve\n showGrid?: boolean\n showTooltip?: boolean\n className?: string\n xTickCount?: number\n yTickCount?: number\n /** Fixes the y-axis to an explicit `[min, max]`. Defaults to the data extent. */\n yDomain?: [number, number]\n /** Formats the x-axis tick labels. */\n formatDate?: (date: Date) => string\n /** Formats the tooltip title. Defaults to `formatDate`. */\n formatTooltipDate?: (date: Date) => string\n formatValue?: (value: number) => string\n /**\n * Unit shown once at the top of the y-axis (e.g. \"kW\"). When set, y-axis tick\n * labels render as plain numbers (matching BarChart / PowerHistoryChart)\n * instead of repeating `formatValue` on every tick. `formatValue` still feeds\n * the tooltip. Omit to keep the per-tick `formatValue` labels.\n */\n yAxisUnit?: string\n /**\n * Vertical reference markers positioned on the time axis (e.g. sunrise /\n * sunset). Each renders a dashed line across the plot with an optional label.\n */\n referenceLines?: Array<{ key: string; date: Date; label?: React.ReactNode }>\n /**\n * HTML content pinned to the top of the plot at a given time (e.g. an hourly\n * weather icon). Positioned by the same time scale as the series, so it lines\n * up with the curve below it.\n */\n topContent?: Array<{ key: string; date: Date; content: React.ReactNode }>\n}\n\nconst DEFAULT_MARGIN = { top: 16, right: 16, bottom: 40, left: 48 }\n\nconst CURVE_MAP = {\n monotone: curveMonotoneX,\n step: curveStep,\n 'step-after': curveStepAfter,\n 'step-before': curveStepBefore,\n linear: curveLinear,\n} as const\n\nconst resolveCurve = (type: LineChartCurve) => CURVE_MAP[type]\n\nconst dateBisector = bisector<LineChartDatum, Date>((d) => d.date)\nconst bisectDate = (data: LineChartDatum[], x: Date, lo?: number) =>\n dateBisector.left(data, x, lo)\n\n/** Whether `date` falls within a series' own x-range (data is sorted ascending). */\nfunction withinDomain(data: LineChartDatum[], date: Date): boolean {\n const first = data[0]\n const last = data[data.length - 1]\n if (!first || !last) return false\n const t = date.valueOf()\n return t >= first.date.valueOf() && t <= last.date.valueOf()\n}\n\n/**\n * y-domain padded 10% beyond the data extent. The baseline is pinned to 0 so\n * all-positive series render from the axis up; a series that dips below 0\n * (signed grid / battery power) extends the domain downward to keep the zero\n * crossing visible.\n */\nfunction computeYDomain(data: LineChartDatum[]): [number, number] {\n let min = 0\n let max = 0\n for (const d of data) {\n if (d.value < min) min = d.value\n if (d.value > max) max = d.value\n }\n if (min === max) return [min, min + 1]\n return [min * 1.1, max * 1.1]\n}\n\nfunction nearestDatum(\n data: LineChartDatum[],\n date: Date,\n): LineChartDatum | undefined {\n if (data.length === 0) return undefined\n const index = bisectDate(data, date, 1)\n const d0 = data[index - 1]\n const d1 = data[index]\n if (!d0) return d1\n if (!d1) return d0\n return date.valueOf() - d0.date.valueOf() > d1.date.valueOf() - date.valueOf()\n ? d1\n : d0\n}\n\nconst defaultFormatDate = (date: Date) =>\n date.toLocaleDateString(undefined, { month: 'short', day: 'numeric' })\n\nconst defaultValueFormat = localeNumberFormat()\nconst defaultFormatValue = (value: number) => defaultValueFormat.format(value)\n\nconst LINE_COLORS = [\n 'stroke-spark-9',\n 'stroke-green-9',\n 'stroke-blue-9',\n 'stroke-orange-9',\n 'stroke-red-9',\n]\n\nconst DOT_COLORS = [\n 'fill-spark-9',\n 'fill-green-9',\n 'fill-blue-9',\n 'fill-orange-9',\n 'fill-red-9',\n]\n\n// CSS-var colours matching LINE_COLORS, used for the tooltip legend dots.\nconst LEGEND_COLORS = [\n 'var(--spark-9)',\n 'var(--green-9)',\n 'var(--blue-9)',\n 'var(--orange-9)',\n 'var(--red-9)',\n]\n\nconst LineChart: React.FC<LineChartProps> = ({\n series,\n width,\n height,\n margin = DEFAULT_MARGIN,\n curve: defaultCurve = 'monotone',\n showGrid = true,\n showTooltip: enableTooltip = true,\n className,\n xTickCount = 5,\n yTickCount = 4,\n formatDate = defaultFormatDate,\n formatTooltipDate,\n formatValue = defaultFormatValue,\n yAxisUnit,\n yDomain,\n referenceLines,\n topContent,\n}) => {\n const {\n showTooltip,\n hideTooltip,\n tooltipData,\n tooltipLeft,\n tooltipTop,\n tooltipOpen,\n } = useTooltip<{ date: Date }>()\n\n const innerWidth = Math.max(0, width - margin.left - margin.right)\n const innerHeight = Math.max(0, height - margin.top - margin.bottom)\n\n const allData = useMemo(() => series.flatMap((s) => s.data), [series])\n\n const xScale = useMemo(\n () =>\n scaleTime({\n range: [0, innerWidth],\n domain: extent(allData, (d) => d.date) as [Date, Date],\n }),\n [allData, innerWidth],\n )\n\n // With a unit, the y-axis is generated by the shared scale util (nice ticks\n // + rounded bounds) so it matches BarChart / PowerHistoryChart exactly.\n const yAxisScale = useMemo(() => {\n if (yAxisUnit === undefined) return null\n let min = 0\n let max = 0\n for (const d of allData) {\n if (d.value < min) min = d.value\n if (d.value > max) max = d.value\n }\n return buildYAxisScale(min, max)\n }, [allData, yAxisUnit])\n\n const yScale = useMemo(\n () =>\n scaleLinear({\n range: [innerHeight, 0],\n domain:\n yDomain ??\n (yAxisScale\n ? [yAxisScale.min, yAxisScale.max]\n : computeYDomain(allData)),\n nice: !yDomain && !yAxisScale,\n }),\n [allData, innerHeight, yDomain, yAxisScale],\n )\n\n const xTicks = xScale.ticks(xTickCount)\n const yTicks = yAxisScale ? yAxisScale.ticks : yScale.ticks(yTickCount)\n\n const handleTooltip = useCallback(\n (\n event:\n | React.TouchEvent<SVGRectElement>\n | React.MouseEvent<SVGRectElement>,\n ) => {\n if (!enableTooltip) return\n\n const point = localPoint(event)\n if (!point) return\n\n const x0 = xScale.invert(point.x - margin.left)\n\n // Snap to the data point closest to the cursor across all series, so the\n // cursor line + tooltip line up with real values.\n let anchorDate: Date | null = null\n let bestDistance = Infinity\n for (const s of series) {\n const d = nearestDatum(s.data, x0)\n if (!d) continue\n const distance = Math.abs(d.date.valueOf() - x0.valueOf())\n if (distance < bestDistance) {\n bestDistance = distance\n anchorDate = d.date\n }\n }\n\n if (!anchorDate) return\n\n showTooltip({\n tooltipData: { date: anchorDate },\n tooltipLeft: xScale(anchorDate) + margin.left,\n tooltipTop: margin.top,\n })\n },\n [enableTooltip, margin, series, showTooltip, xScale],\n )\n\n const tooltipRows: ChartTooltipRow[] = tooltipData\n ? series.flatMap((s, i) => {\n const d = nearestDatum(s.data, tooltipData.date)\n if (!d || !withinDomain(s.data, tooltipData.date)) return []\n return [\n {\n key: s.id,\n label: s.label ?? s.id,\n color: LEGEND_COLORS[i % LEGEND_COLORS.length] as string,\n value: formatValue(d.value),\n },\n ]\n })\n : []\n\n const [tooltipRef, tooltipSize] = useMeasuredSize<HTMLDivElement>()\n const tooltipPos = clampTooltipPosition({\n anchorX: tooltipLeft ?? 0,\n anchorY: tooltipTop ?? margin.top,\n width,\n height,\n tipWidth: tooltipSize.width,\n tipHeight: tooltipSize.height,\n placement: 'beside',\n })\n\n if (width < 10 || height < 10) return null\n\n return (\n <div className={cn('relative', className)}>\n <svg className=\"block\" height={height} width={width}>\n <Group left={margin.left} top={margin.top}>\n {/* Grid lines */}\n {showGrid &&\n yTicks.map((tick) => (\n <line\n className=\"stroke-slate-a4\"\n key={`grid-y-${tick}`}\n strokeDasharray=\"4,4\"\n x1={0}\n x2={innerWidth}\n y1={yScale(tick)}\n y2={yScale(tick)}\n />\n ))}\n\n {/* X axis */}\n <line\n className=\"stroke-slate-a6\"\n x1={0}\n x2={innerWidth}\n y1={innerHeight}\n y2={innerHeight}\n />\n\n {/* Reference markers (e.g. sunrise / sunset) */}\n {referenceLines?.map((ref) => {\n const x = xScale(ref.date)\n if (!Number.isFinite(x)) return null\n // Sit the label beside the line, on whichever side keeps it in\n // frame: right of a left-half marker, left of a right-half one.\n const anchorEnd = x > innerWidth / 2\n return (\n <g key={ref.key} pointerEvents=\"none\">\n <line\n className=\"stroke-orange-8\"\n strokeDasharray=\"3,3\"\n x1={x}\n x2={x}\n y1={0}\n y2={innerHeight}\n />\n {ref.label != null && (\n <text\n className=\"fill-orange-11 text-[10px]\"\n dy=\"0.9em\"\n textAnchor={anchorEnd ? 'end' : 'start'}\n x={x + (anchorEnd ? -4 : 4)}\n y={0}\n >\n {ref.label}\n </text>\n )}\n </g>\n )\n })}\n\n {/* X axis labels */}\n {xTicks.map((tick) => (\n <text\n dy=\"1em\"\n fill=\"var(--gray-a11)\"\n fontSize={10}\n key={`x-${tick.valueOf()}`}\n textAnchor=\"middle\"\n x={xScale(tick)}\n y={innerHeight + 8}\n >\n {formatDate(tick)}\n </text>\n ))}\n\n {/* Y axis. With `yAxisUnit`, matches BarChart: a vertical axis line,\n short tick marks, plain numeric ticks, and the unit as a bold\n top-left header (top tick hidden). Without it, ticks repeat\n `formatValue` and no axis line/marks are drawn. */}\n {yAxisUnit !== undefined && (\n <line\n stroke=\"var(--gray-a6)\"\n strokeWidth={1}\n x1={0}\n x2={0}\n y1={0}\n y2={innerHeight}\n />\n )}\n {yTicks.map((tick) => {\n const y = yScale(tick)\n return (\n <g key={`y-${tick}`}>\n {yAxisUnit !== undefined && (\n <line\n stroke=\"var(--gray-a8)\"\n strokeWidth={1}\n x1={-4}\n x2={0}\n y1={y}\n y2={y}\n />\n )}\n <text\n dy=\"0.32em\"\n fill=\"var(--gray-a11)\"\n fontSize={10}\n textAnchor=\"end\"\n x={yAxisUnit !== undefined ? -7 : -4}\n y={y}\n >\n {yAxisUnit !== undefined\n ? formatYAxisTick(tick)\n : formatValue(tick)}\n </text>\n </g>\n )\n })}\n {yAxisUnit !== undefined && (\n <text\n fill=\"var(--gray-a11)\"\n fontSize={10}\n fontWeight={600}\n textAnchor=\"start\"\n x={-margin.left}\n y={-6}\n >\n {yAxisUnit}\n </text>\n )}\n\n {/* Lines */}\n {series.map((s, i) => (\n <LinePath\n className={cn(LINE_COLORS[i % LINE_COLORS.length], s.className)}\n curve={resolveCurve(s.curve ?? defaultCurve)}\n data={s.data}\n fill=\"none\"\n key={s.id}\n strokeDasharray={s.dashed ? (s.dashPattern ?? '6,4') : undefined}\n strokeWidth={2}\n x={(d) => xScale(d.date)}\n y={(d) => yScale(d.value)}\n />\n ))}\n\n {/* Tooltip hover target */}\n {enableTooltip && (\n <rect\n fill=\"transparent\"\n height={innerHeight}\n onMouseLeave={hideTooltip}\n onMouseMove={handleTooltip}\n onTouchEnd={hideTooltip}\n onTouchMove={handleTooltip}\n width={innerWidth}\n x={0}\n y={0}\n />\n )}\n\n {/* Cursor line + a dot per series */}\n {tooltipOpen && tooltipData && (\n <>\n <line\n className=\"stroke-slate-a6\"\n pointerEvents=\"none\"\n strokeDasharray=\"4,4\"\n x1={xScale(tooltipData.date)}\n x2={xScale(tooltipData.date)}\n y1={0}\n y2={innerHeight}\n />\n {series.map((s, i) => {\n const d = nearestDatum(s.data, tooltipData.date)\n if (!d || !withinDomain(s.data, tooltipData.date)) return null\n return (\n <circle\n key={s.id}\n className={cn(DOT_COLORS[i % DOT_COLORS.length])}\n cx={xScale(d.date)}\n cy={yScale(d.value)}\n pointerEvents=\"none\"\n r={4}\n stroke=\"white\"\n strokeWidth={2}\n />\n )\n })}\n </>\n )}\n </Group>\n </svg>\n\n {topContent && topContent.length > 0 && (\n <div className=\"pointer-events-none absolute inset-0\">\n {topContent.map((item) => {\n const x = xScale(item.date)\n if (!Number.isFinite(x)) return null\n return (\n <div\n key={item.key}\n className=\"absolute -translate-x-1/2\"\n style={{ left: margin.left + x, top: 0 }}\n >\n {item.content}\n </div>\n )\n })}\n </div>\n )}\n\n <div\n ref={tooltipRef}\n className=\"pointer-events-none absolute z-10\"\n style={{\n left: tooltipPos.left,\n top: tooltipPos.top,\n opacity: tooltipOpen && tooltipData ? 1 : 0,\n transition:\n 'left 140ms ease-out, top 140ms ease-out, opacity 140ms ease-out',\n }}\n >\n {tooltipData && (\n <ChartTooltipCard\n label={(formatTooltipDate ?? formatDate)(tooltipData.date)}\n rows={tooltipRows}\n />\n )}\n </div>\n </div>\n )\n}\n\nexport { LineChart }\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"line-chart.js","names":[],"sources":["../../src/components/line-chart.tsx"],"sourcesContent":["import {\n curveLinear,\n curveMonotoneX,\n curveStep,\n curveStepAfter,\n curveStepBefore,\n} from '@visx/curve'\nimport { localPoint } from '@visx/event'\nimport { Group } from '@visx/group'\nimport { scaleLinear, scaleTime } from '@visx/scale'\nimport { LinePath } from '@visx/shape'\nimport { useTooltip } from '@visx/tooltip'\nimport { bisector, extent } from '@visx/vendor/d3-array'\nimport * as React from 'react'\nimport { useCallback, useMemo } from 'react'\nimport { useReducedMotion } from '../hooks/use-reduced-motion'\nimport { buildYAxisScale, formatYAxisTick } from '../utils/chart-scale'\nimport { cn } from '../utils/cn'\nimport { localeNumberFormat } from '../utils/format'\nimport {\n ChartTooltipCard,\n type ChartTooltipRow,\n clampTooltipPosition,\n useMeasuredSize,\n} from './chart'\n\nexport interface LineChartDatum {\n date: Date\n value: number\n}\n\nexport type LineChartCurve =\n | 'monotone'\n | 'step'\n | 'step-after'\n | 'step-before'\n | 'linear'\n\nexport interface LineChartSeries {\n id: string\n data: LineChartDatum[]\n /** Label shown in the hover tooltip. Defaults to `id`. */\n label?: React.ReactNode\n className?: string\n /** Curve interpolation type. Default: inherits from LineChartProps.curve */\n curve?: LineChartCurve\n /** Render as a dashed line */\n dashed?: boolean\n /** Custom dash pattern (e.g. \"8,4\" or \"4,2,1,2\"). Only applies when dashed is true. */\n dashPattern?: string\n}\n\nexport interface LineChartProps {\n series: LineChartSeries[]\n width: number\n height: number\n margin?: { top: number; right: number; bottom: number; left: number }\n /** Default curve for all series. Default: 'monotone' */\n curve?: LineChartCurve\n showGrid?: boolean\n showTooltip?: boolean\n className?: string\n xTickCount?: number\n yTickCount?: number\n /** Fixes the y-axis to an explicit `[min, max]`. Defaults to the data extent. */\n yDomain?: [number, number]\n /** Formats the x-axis tick labels. */\n formatDate?: (date: Date) => string\n /** Formats the tooltip title. Defaults to `formatDate`. */\n formatTooltipDate?: (date: Date) => string\n formatValue?: (value: number) => string\n /**\n * Unit shown once at the top of the y-axis (e.g. \"kW\"). When set, y-axis tick\n * labels render as plain numbers (matching BarChart / PowerHistoryChart)\n * instead of repeating `formatValue` on every tick. `formatValue` still feeds\n * the tooltip. Omit to keep the per-tick `formatValue` labels.\n */\n yAxisUnit?: string\n /**\n * Vertical reference markers positioned on the time axis (e.g. sunrise /\n * sunset). Each renders a dashed line across the plot with an optional label.\n */\n referenceLines?: Array<{ key: string; date: Date; label?: React.ReactNode }>\n /**\n * HTML content pinned to the top of the plot at a given time (e.g. an hourly\n * weather icon). Positioned by the same time scale as the series, so it lines\n * up with the curve below it.\n */\n topContent?: Array<{ key: string; date: Date; content: React.ReactNode }>\n}\n\nconst DEFAULT_MARGIN = { top: 16, right: 16, bottom: 40, left: 48 }\n\nconst CURVE_MAP = {\n monotone: curveMonotoneX,\n step: curveStep,\n 'step-after': curveStepAfter,\n 'step-before': curveStepBefore,\n linear: curveLinear,\n} as const\n\nconst resolveCurve = (type: LineChartCurve) => CURVE_MAP[type]\n\nconst dateBisector = bisector<LineChartDatum, Date>((d) => d.date)\nconst bisectDate = (data: LineChartDatum[], x: Date, lo?: number) =>\n dateBisector.left(data, x, lo)\n\n/** Whether `date` falls within a series' own x-range (data is sorted ascending). */\nfunction withinDomain(data: LineChartDatum[], date: Date): boolean {\n const first = data[0]\n const last = data[data.length - 1]\n if (!first || !last) return false\n const t = date.valueOf()\n return t >= first.date.valueOf() && t <= last.date.valueOf()\n}\n\n/**\n * y-domain padded 10% beyond the data extent. The baseline is pinned to 0 so\n * all-positive series render from the axis up; a series that dips below 0\n * (signed grid / battery power) extends the domain downward to keep the zero\n * crossing visible.\n */\nfunction computeYDomain(data: LineChartDatum[]): [number, number] {\n let min = 0\n let max = 0\n for (const d of data) {\n if (d.value < min) min = d.value\n if (d.value > max) max = d.value\n }\n if (min === max) return [min, min + 1]\n return [min * 1.1, max * 1.1]\n}\n\nfunction nearestDatum(\n data: LineChartDatum[],\n date: Date,\n): LineChartDatum | undefined {\n if (data.length === 0) return undefined\n const index = bisectDate(data, date, 1)\n const d0 = data[index - 1]\n const d1 = data[index]\n if (!d0) return d1\n if (!d1) return d0\n return date.valueOf() - d0.date.valueOf() > d1.date.valueOf() - date.valueOf()\n ? d1\n : d0\n}\n\nconst defaultFormatDate = (date: Date) =>\n date.toLocaleDateString(undefined, { month: 'short', day: 'numeric' })\n\nconst defaultValueFormat = localeNumberFormat()\nconst defaultFormatValue = (value: number) => defaultValueFormat.format(value)\n\nconst LINE_COLORS = [\n 'stroke-spark-9',\n 'stroke-green-9',\n 'stroke-blue-9',\n 'stroke-orange-9',\n 'stroke-red-9',\n]\n\nconst DOT_COLORS = [\n 'fill-spark-9',\n 'fill-green-9',\n 'fill-blue-9',\n 'fill-orange-9',\n 'fill-red-9',\n]\n\n// CSS-var colours matching LINE_COLORS, used for the tooltip legend dots.\nconst LEGEND_COLORS = [\n 'var(--spark-9)',\n 'var(--green-9)',\n 'var(--blue-9)',\n 'var(--orange-9)',\n 'var(--red-9)',\n]\n\nconst LineChart: React.FC<LineChartProps> = ({\n series,\n width,\n height,\n margin = DEFAULT_MARGIN,\n curve: defaultCurve = 'monotone',\n showGrid = true,\n showTooltip: enableTooltip = true,\n className,\n xTickCount = 5,\n yTickCount = 4,\n formatDate = defaultFormatDate,\n formatTooltipDate,\n formatValue = defaultFormatValue,\n yAxisUnit,\n yDomain,\n referenceLines,\n topContent,\n}) => {\n const {\n showTooltip,\n hideTooltip,\n tooltipData,\n tooltipLeft,\n tooltipTop,\n tooltipOpen,\n } = useTooltip<{ date: Date }>()\n\n const innerWidth = Math.max(0, width - margin.left - margin.right)\n const innerHeight = Math.max(0, height - margin.top - margin.bottom)\n\n const allData = useMemo(() => series.flatMap((s) => s.data), [series])\n\n const xScale = useMemo(\n () =>\n scaleTime({\n range: [0, innerWidth],\n domain: extent(allData, (d) => d.date) as [Date, Date],\n }),\n [allData, innerWidth],\n )\n\n // With a unit, the y-axis is generated by the shared scale util (nice ticks\n // + rounded bounds) so it matches BarChart / PowerHistoryChart exactly.\n const yAxisScale = useMemo(() => {\n if (yAxisUnit === undefined) return null\n let min = 0\n let max = 0\n for (const d of allData) {\n if (d.value < min) min = d.value\n if (d.value > max) max = d.value\n }\n return buildYAxisScale(min, max)\n }, [allData, yAxisUnit])\n\n const yScale = useMemo(\n () =>\n scaleLinear({\n range: [innerHeight, 0],\n domain:\n yDomain ??\n (yAxisScale\n ? [yAxisScale.min, yAxisScale.max]\n : computeYDomain(allData)),\n nice: !yDomain && !yAxisScale,\n }),\n [allData, innerHeight, yDomain, yAxisScale],\n )\n\n const xTicks = xScale.ticks(xTickCount)\n const yTicks = yAxisScale ? yAxisScale.ticks : yScale.ticks(yTickCount)\n\n const handleTooltip = useCallback(\n (\n event:\n | React.TouchEvent<SVGRectElement>\n | React.MouseEvent<SVGRectElement>,\n ) => {\n if (!enableTooltip) return\n\n const point = localPoint(event)\n if (!point) return\n\n const x0 = xScale.invert(point.x - margin.left)\n\n // Snap to the data point closest to the cursor across all series, so the\n // cursor line + tooltip line up with real values.\n let anchorDate: Date | null = null\n let bestDistance = Infinity\n for (const s of series) {\n const d = nearestDatum(s.data, x0)\n if (!d) continue\n const distance = Math.abs(d.date.valueOf() - x0.valueOf())\n if (distance < bestDistance) {\n bestDistance = distance\n anchorDate = d.date\n }\n }\n\n if (!anchorDate) return\n\n showTooltip({\n tooltipData: { date: anchorDate },\n tooltipLeft: xScale(anchorDate) + margin.left,\n tooltipTop: margin.top,\n })\n },\n [enableTooltip, margin, series, showTooltip, xScale],\n )\n\n const tooltipRows: ChartTooltipRow[] = tooltipData\n ? series.flatMap((s, i) => {\n const d = nearestDatum(s.data, tooltipData.date)\n if (!d || !withinDomain(s.data, tooltipData.date)) return []\n return [\n {\n key: s.id,\n label: s.label ?? s.id,\n color: LEGEND_COLORS[i % LEGEND_COLORS.length] as string,\n value: formatValue(d.value),\n },\n ]\n })\n : []\n\n const reducedMotion = useReducedMotion()\n const [tooltipRef, tooltipSize] = useMeasuredSize<HTMLDivElement>()\n const tooltipPos = clampTooltipPosition({\n anchorX: tooltipLeft ?? 0,\n anchorY: tooltipTop ?? margin.top,\n width,\n height,\n tipWidth: tooltipSize.width,\n tipHeight: tooltipSize.height,\n placement: 'beside',\n })\n\n if (width < 10 || height < 10) return null\n\n return (\n <div className={cn('relative', className)}>\n <svg className=\"block\" height={height} width={width}>\n <Group left={margin.left} top={margin.top}>\n {/* Grid lines */}\n {showGrid &&\n yTicks.map((tick) => (\n <line\n className=\"stroke-gray-a4\"\n key={`grid-y-${tick}`}\n strokeDasharray=\"4,4\"\n x1={0}\n x2={innerWidth}\n y1={yScale(tick)}\n y2={yScale(tick)}\n />\n ))}\n\n {/* X axis */}\n <line\n className=\"stroke-gray-a6\"\n x1={0}\n x2={innerWidth}\n y1={innerHeight}\n y2={innerHeight}\n />\n\n {/* Reference markers (e.g. sunrise / sunset) */}\n {referenceLines?.map((ref) => {\n const x = xScale(ref.date)\n if (!Number.isFinite(x)) return null\n // Sit the label beside the line, on whichever side keeps it in\n // frame: right of a left-half marker, left of a right-half one.\n const anchorEnd = x > innerWidth / 2\n return (\n <g key={ref.key} pointerEvents=\"none\">\n <line\n className=\"stroke-orange-8\"\n strokeDasharray=\"3,3\"\n x1={x}\n x2={x}\n y1={0}\n y2={innerHeight}\n />\n {ref.label != null && (\n <text\n className=\"fill-orange-11 text-[10px]\"\n dy=\"0.9em\"\n textAnchor={anchorEnd ? 'end' : 'start'}\n x={x + (anchorEnd ? -4 : 4)}\n y={0}\n >\n {ref.label}\n </text>\n )}\n </g>\n )\n })}\n\n {/* X axis labels */}\n {xTicks.map((tick) => (\n <text\n dy=\"1em\"\n fill=\"var(--neutral-a11)\"\n fontSize={10}\n key={`x-${tick.valueOf()}`}\n textAnchor=\"middle\"\n x={xScale(tick)}\n y={innerHeight + 8}\n >\n {formatDate(tick)}\n </text>\n ))}\n\n {/* Y axis. With `yAxisUnit`, matches BarChart: a vertical axis line,\n short tick marks, plain numeric ticks, and the unit as a bold\n top-left header (top tick hidden). Without it, ticks repeat\n `formatValue` and no axis line/marks are drawn. */}\n {yAxisUnit !== undefined && (\n <line\n stroke=\"var(--neutral-a6)\"\n strokeWidth={1}\n x1={0}\n x2={0}\n y1={0}\n y2={innerHeight}\n />\n )}\n {yTicks.map((tick) => {\n const y = yScale(tick)\n return (\n <g key={`y-${tick}`}>\n {yAxisUnit !== undefined && (\n <line\n stroke=\"var(--neutral-a8)\"\n strokeWidth={1}\n x1={-4}\n x2={0}\n y1={y}\n y2={y}\n />\n )}\n <text\n dy=\"0.32em\"\n fill=\"var(--neutral-a11)\"\n fontSize={10}\n textAnchor=\"end\"\n x={yAxisUnit !== undefined ? -7 : -4}\n y={y}\n >\n {yAxisUnit !== undefined\n ? formatYAxisTick(tick)\n : formatValue(tick)}\n </text>\n </g>\n )\n })}\n {yAxisUnit !== undefined && (\n <text\n fill=\"var(--neutral-a11)\"\n fontSize={10}\n fontWeight={600}\n textAnchor=\"start\"\n x={-margin.left}\n y={-6}\n >\n {yAxisUnit}\n </text>\n )}\n\n {/* Lines */}\n {series.map((s, i) => (\n <LinePath\n className={cn(LINE_COLORS[i % LINE_COLORS.length], s.className)}\n curve={resolveCurve(s.curve ?? defaultCurve)}\n data={s.data}\n fill=\"none\"\n key={s.id}\n strokeDasharray={s.dashed ? (s.dashPattern ?? '6,4') : undefined}\n strokeWidth={2}\n x={(d) => xScale(d.date)}\n y={(d) => yScale(d.value)}\n />\n ))}\n\n {/* Tooltip hover target */}\n {enableTooltip && (\n <rect\n fill=\"transparent\"\n height={innerHeight}\n onMouseLeave={hideTooltip}\n onMouseMove={handleTooltip}\n onTouchEnd={hideTooltip}\n onTouchMove={handleTooltip}\n width={innerWidth}\n x={0}\n y={0}\n />\n )}\n\n {/* Cursor line + a dot per series */}\n {tooltipOpen && tooltipData && (\n <>\n <line\n className=\"stroke-gray-a6\"\n pointerEvents=\"none\"\n strokeDasharray=\"4,4\"\n x1={xScale(tooltipData.date)}\n x2={xScale(tooltipData.date)}\n y1={0}\n y2={innerHeight}\n />\n {series.map((s, i) => {\n const d = nearestDatum(s.data, tooltipData.date)\n if (!d || !withinDomain(s.data, tooltipData.date)) return null\n return (\n <circle\n key={s.id}\n className={cn(DOT_COLORS[i % DOT_COLORS.length])}\n cx={xScale(d.date)}\n cy={yScale(d.value)}\n pointerEvents=\"none\"\n r={4}\n stroke=\"white\"\n strokeWidth={2}\n />\n )\n })}\n </>\n )}\n </Group>\n </svg>\n\n {topContent && topContent.length > 0 && (\n <div className=\"pointer-events-none absolute inset-0\">\n {topContent.map((item) => {\n const x = xScale(item.date)\n if (!Number.isFinite(x)) return null\n return (\n <div\n key={item.key}\n className=\"absolute -translate-x-1/2\"\n style={{ left: margin.left + x, top: 0 }}\n >\n {item.content}\n </div>\n )\n })}\n </div>\n )}\n\n <div\n ref={tooltipRef}\n className=\"pointer-events-none absolute z-10\"\n style={{\n left: tooltipPos.left,\n top: tooltipPos.top,\n opacity: tooltipOpen && tooltipData ? 1 : 0,\n transition: reducedMotion\n ? 'opacity 140ms ease-out'\n : 'left 140ms ease-out, top 140ms ease-out, opacity 140ms ease-out',\n }}\n >\n {tooltipData && (\n <ChartTooltipCard\n label={(formatTooltipDate ?? formatDate)(tooltipData.date)}\n rows={tooltipRows}\n />\n )}\n </div>\n </div>\n )\n}\n\nexport { LineChart }\n"],"mappings":"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"}
|
package/dist/components/list.cjs
CHANGED
|
@@ -39,7 +39,7 @@ function ListItem({ className, children, recent, selected, skeleton, render, ...
|
|
|
39
39
|
});
|
|
40
40
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
|
|
41
41
|
"data-slot": "list-item",
|
|
42
|
-
className: (0, cnfast.cn)("relative has-
|
|
42
|
+
className: (0, cnfast.cn)("relative has-focus-visible:z-10", "group-data-[variant=soft]/list:rounded-md group-data-[variant=soft]/list:bg-gray-a2 dark:group-data-[variant=soft]/list:bg-gray-a3", "group-data-[variant=surface]/list:bg-gray-2", "group-data-[variant=surface]/list:border-x group-data-[variant=surface]/list:border-t group-data-[variant=surface]/list:border-gray-a6 group-data-[variant=surface]/list:first:rounded-t-md group-data-[variant=surface]/list:last:rounded-b-md group-data-[variant=surface]/list:last:border-b", "group-data-[variant=outline]/list:border-x group-data-[variant=outline]/list:border-t group-data-[variant=outline]/list:border-gray-a6 group-data-[variant=outline]/list:first:rounded-t-md group-data-[variant=outline]/list:last:rounded-b-md group-data-[variant=outline]/list:last:border-b", className),
|
|
43
43
|
...props,
|
|
44
44
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ListItemContext.Provider, {
|
|
45
45
|
value: recentCtx,
|