@anuma/sdk 11.0.0 → 11.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/react/index.cjs +404 -64
- package/dist/react/index.d.mts +5 -1
- package/dist/react/index.d.ts +5 -1
- package/dist/react/index.mjs +405 -64
- package/dist/tools/index.cjs +58 -3
- package/dist/tools/index.d.mts +4 -1
- package/dist/tools/index.d.ts +4 -1
- package/dist/tools/index.mjs +58 -3
- package/package.json +1 -1
package/dist/react/index.mjs
CHANGED
|
@@ -34413,6 +34413,7 @@ import {
|
|
|
34413
34413
|
BarChart,
|
|
34414
34414
|
CartesianGrid,
|
|
34415
34415
|
Cell,
|
|
34416
|
+
Label,
|
|
34416
34417
|
Line as Line2,
|
|
34417
34418
|
LineChart,
|
|
34418
34419
|
Pie,
|
|
@@ -34425,6 +34426,12 @@ function cx(...classes) {
|
|
|
34425
34426
|
return classes.filter(Boolean).join(" ");
|
|
34426
34427
|
}
|
|
34427
34428
|
var THEMES = { light: "", dark: ".dark" };
|
|
34429
|
+
var SAFE_CSS_KEY = /^[\w-]+$/;
|
|
34430
|
+
var SAFE_CSS_COLOR = /^(?:#(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})|[a-z]+|(?:rgba?|hsla?|hwb|lab|lch|oklab|oklch)\([\w\s.,%/+-]*\)|var\(--[\w-]+\))$/i;
|
|
34431
|
+
function isSafeCssColor(value) {
|
|
34432
|
+
if (typeof value !== "string" || !SAFE_CSS_COLOR.test(value)) return false;
|
|
34433
|
+
return typeof CSS === "undefined" || typeof CSS.supports !== "function" || CSS.supports("color", value);
|
|
34434
|
+
}
|
|
34428
34435
|
var ChartContext = React2.createContext(null);
|
|
34429
34436
|
function useChart() {
|
|
34430
34437
|
const context = React2.useContext(ChartContext);
|
|
@@ -34434,7 +34441,9 @@ function useChart() {
|
|
|
34434
34441
|
return context;
|
|
34435
34442
|
}
|
|
34436
34443
|
function ChartStyle({ id: id2, config }) {
|
|
34437
|
-
const colorConfig = Object.entries(config).filter(
|
|
34444
|
+
const colorConfig = Object.entries(config).filter(
|
|
34445
|
+
([key3, cfg]) => SAFE_CSS_KEY.test(key3) && (cfg.theme || cfg.color)
|
|
34446
|
+
);
|
|
34438
34447
|
if (!colorConfig.length) return null;
|
|
34439
34448
|
return /* @__PURE__ */ jsx2(
|
|
34440
34449
|
"style",
|
|
@@ -34445,7 +34454,7 @@ function ChartStyle({ id: id2, config }) {
|
|
|
34445
34454
|
${prefix} [data-chart=${id2}] {
|
|
34446
34455
|
${colorConfig.map(([key3, itemConfig]) => {
|
|
34447
34456
|
const color = itemConfig.theme?.[theme] || itemConfig.color;
|
|
34448
|
-
return color ? ` --color-${key3}: ${color};` : null;
|
|
34457
|
+
return isSafeCssColor(color) ? ` --color-${key3}: ${color};` : null;
|
|
34449
34458
|
}).join("\n")}
|
|
34450
34459
|
}
|
|
34451
34460
|
`
|
|
@@ -34494,7 +34503,8 @@ function ChartTooltipContent({
|
|
|
34494
34503
|
formatter,
|
|
34495
34504
|
color,
|
|
34496
34505
|
nameKey,
|
|
34497
|
-
labelKey
|
|
34506
|
+
labelKey,
|
|
34507
|
+
valueFormatter
|
|
34498
34508
|
}) {
|
|
34499
34509
|
const { config } = useChart();
|
|
34500
34510
|
const tooltipLabel = React2.useMemo(() => {
|
|
@@ -34561,7 +34571,7 @@ function ChartTooltipContent({
|
|
|
34561
34571
|
nestLabel ? tooltipLabel : null,
|
|
34562
34572
|
/* @__PURE__ */ jsx2("span", { className: "text-muted-foreground", children: itemConfig?.label || item.name })
|
|
34563
34573
|
] }),
|
|
34564
|
-
item.value && /* @__PURE__ */ jsx2("span", { className: "text-foreground font-
|
|
34574
|
+
item.value !== void 0 && item.value !== null && /* @__PURE__ */ jsx2("span", { className: "text-foreground font-medium tabular-nums", children: valueFormatter && typeof item.value === "number" ? valueFormatter(item.value) : item.value.toLocaleString() })
|
|
34565
34575
|
]
|
|
34566
34576
|
}
|
|
34567
34577
|
)
|
|
@@ -34607,7 +34617,7 @@ function ChartLegendContent({
|
|
|
34607
34617
|
style: { backgroundColor: item.color }
|
|
34608
34618
|
}
|
|
34609
34619
|
),
|
|
34610
|
-
itemConfig?.label
|
|
34620
|
+
itemConfig?.label ?? cellText(item.value)
|
|
34611
34621
|
]
|
|
34612
34622
|
},
|
|
34613
34623
|
String(item.value)
|
|
@@ -34634,86 +34644,417 @@ var DEFAULT_COLORS = [
|
|
|
34634
34644
|
"var(--chart-4)",
|
|
34635
34645
|
"var(--chart-5)"
|
|
34636
34646
|
];
|
|
34647
|
+
var SURFACE = "var(--chart-surface)";
|
|
34648
|
+
var DOT_LIMIT = 12;
|
|
34649
|
+
var MAX_TICKS = 8;
|
|
34650
|
+
var MINUS = "\u2212";
|
|
34651
|
+
function paletteColor(index) {
|
|
34652
|
+
return index < DEFAULT_COLORS.length ? DEFAULT_COLORS[index] : `hsl(${Math.round(index * 137.508 % 360)} 65% 55%)`;
|
|
34653
|
+
}
|
|
34654
|
+
function cellText(value) {
|
|
34655
|
+
return typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? String(value) : "";
|
|
34656
|
+
}
|
|
34657
|
+
var VISUALLY_HIDDEN = {
|
|
34658
|
+
position: "absolute",
|
|
34659
|
+
width: 1,
|
|
34660
|
+
height: 1,
|
|
34661
|
+
padding: 0,
|
|
34662
|
+
margin: -1,
|
|
34663
|
+
overflow: "hidden",
|
|
34664
|
+
clip: "rect(0, 0, 0, 0)",
|
|
34665
|
+
whiteSpace: "nowrap",
|
|
34666
|
+
border: 0
|
|
34667
|
+
};
|
|
34668
|
+
function tickDigits(ticks) {
|
|
34669
|
+
if (!ticks || ticks.length < 2) return 3;
|
|
34670
|
+
const step = ticks[1] - ticks[0];
|
|
34671
|
+
const magnitude = Math.max(...ticks.map(Math.abs));
|
|
34672
|
+
if (step <= 0 || magnitude === 0) return 3;
|
|
34673
|
+
const needed = Math.floor(Math.log10(magnitude)) - Math.floor(Math.log10(step)) + 1;
|
|
34674
|
+
return Math.min(21, Math.max(3, needed));
|
|
34675
|
+
}
|
|
34676
|
+
function keepSmall(options) {
|
|
34677
|
+
const small = new Intl.NumberFormat(void 0, { ...options, maximumSignificantDigits: 3 });
|
|
34678
|
+
const regular = new Intl.NumberFormat(void 0, { ...options, maximumFractionDigits: 2 });
|
|
34679
|
+
return (n, format) => format(n !== 0 && Math.abs(n) < 1 ? small : regular, n);
|
|
34680
|
+
}
|
|
34681
|
+
function buildFormatters(format, currency, ticks) {
|
|
34682
|
+
const digits = tickDigits(ticks);
|
|
34683
|
+
if (format === "currency") {
|
|
34684
|
+
const money = (options) => new Intl.NumberFormat(void 0, {
|
|
34685
|
+
style: "currency",
|
|
34686
|
+
currency: currency ?? "USD",
|
|
34687
|
+
...options
|
|
34688
|
+
});
|
|
34689
|
+
const compact2 = money({ notation: "compact", maximumSignificantDigits: 3 });
|
|
34690
|
+
const tick2 = money({ notation: "compact", maximumSignificantDigits: digits });
|
|
34691
|
+
const small2 = money({ maximumSignificantDigits: 4 });
|
|
34692
|
+
const cents = money({ minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
|
34693
|
+
const value2 = (n) => Math.abs(n) >= 1e6 ? compact2.format(n) : n !== 0 && Math.abs(n) < 1 ? small2.format(n) : cents.format(n);
|
|
34694
|
+
return { tick: (n) => tick2.format(n), value: value2, change: (d) => value2(Math.abs(d)) };
|
|
34695
|
+
}
|
|
34696
|
+
if (format === "percent") {
|
|
34697
|
+
const percent = keepSmall({ style: "percent" });
|
|
34698
|
+
const points = keepSmall({});
|
|
34699
|
+
const tick2 = new Intl.NumberFormat(void 0, {
|
|
34700
|
+
style: "percent",
|
|
34701
|
+
maximumSignificantDigits: digits
|
|
34702
|
+
});
|
|
34703
|
+
return {
|
|
34704
|
+
tick: (n) => tick2.format(n / 100),
|
|
34705
|
+
value: (n) => percent(n, (formatter) => formatter.format(n / 100)),
|
|
34706
|
+
change: (d) => `${points(Math.abs(d), (formatter, n) => formatter.format(n))} pts`
|
|
34707
|
+
};
|
|
34708
|
+
}
|
|
34709
|
+
const tick = new Intl.NumberFormat(void 0, {
|
|
34710
|
+
notation: "compact",
|
|
34711
|
+
maximumSignificantDigits: digits
|
|
34712
|
+
});
|
|
34713
|
+
const compact = new Intl.NumberFormat(void 0, {
|
|
34714
|
+
notation: "compact",
|
|
34715
|
+
maximumSignificantDigits: 3
|
|
34716
|
+
});
|
|
34717
|
+
const small = new Intl.NumberFormat(void 0, { maximumSignificantDigits: 4 });
|
|
34718
|
+
const plain2 = new Intl.NumberFormat(void 0, { maximumFractionDigits: 2 });
|
|
34719
|
+
const value = (n) => Math.abs(n) >= 1e6 ? compact.format(n) : n !== 0 && Math.abs(n) < 1 ? small.format(n) : plain2.format(n);
|
|
34720
|
+
return { tick: (n) => tick.format(n), value, change: (d) => value(Math.abs(d)) };
|
|
34721
|
+
}
|
|
34722
|
+
function seriesValues(points, keys) {
|
|
34723
|
+
return points.flatMap(
|
|
34724
|
+
(point) => keys.map((key3) => point[key3]).filter((v) => typeof v === "number")
|
|
34725
|
+
);
|
|
34726
|
+
}
|
|
34727
|
+
function niceStep(rough) {
|
|
34728
|
+
const exponent = Math.floor(Math.log10(rough));
|
|
34729
|
+
const base = 10 ** exponent;
|
|
34730
|
+
const fraction = rough / base;
|
|
34731
|
+
const nice = fraction <= 1 ? 1 : fraction <= 2 ? 2 : fraction <= 2.5 ? 2.5 : fraction <= 5 ? 5 : 10;
|
|
34732
|
+
return nice * base;
|
|
34733
|
+
}
|
|
34734
|
+
function niceTicks(values) {
|
|
34735
|
+
if (values.length === 0) return void 0;
|
|
34736
|
+
const min = Math.min(...values);
|
|
34737
|
+
const max = Math.max(...values);
|
|
34738
|
+
const span = max - min || Math.abs(max) * 0.02 || 1;
|
|
34739
|
+
const low = min - span * 0.1;
|
|
34740
|
+
const high = max + span * 0.1;
|
|
34741
|
+
const step = niceStep((high - low) / 3);
|
|
34742
|
+
const start = min >= 0 ? Math.max(0, Math.floor(low / step) * step) : Math.floor(low / step) * step;
|
|
34743
|
+
const ticks = [];
|
|
34744
|
+
for (let index = 0; index <= MAX_TICKS; index++) {
|
|
34745
|
+
const tick = Number((start + index * step).toPrecision(15));
|
|
34746
|
+
if (ticks.length > 0 && tick <= ticks[ticks.length - 1]) break;
|
|
34747
|
+
ticks.push(tick);
|
|
34748
|
+
if (tick >= high) break;
|
|
34749
|
+
}
|
|
34750
|
+
return ticks.length >= 2 ? ticks : void 0;
|
|
34751
|
+
}
|
|
34637
34752
|
function buildChartConfig(dataKeys, colors) {
|
|
34638
34753
|
const config = {};
|
|
34639
34754
|
dataKeys.forEach((key3, i) => {
|
|
34755
|
+
const custom = colors?.[key3];
|
|
34640
34756
|
config[key3] = {
|
|
34641
34757
|
label: key3.charAt(0).toUpperCase() + key3.slice(1),
|
|
34642
|
-
color:
|
|
34758
|
+
color: isSafeCssColor(custom) ? custom : paletteColor(i)
|
|
34643
34759
|
};
|
|
34644
34760
|
});
|
|
34645
34761
|
return config;
|
|
34646
34762
|
}
|
|
34763
|
+
function lastValueIndex(points, key3) {
|
|
34764
|
+
for (let index = points.length - 1; index >= 0; index--) {
|
|
34765
|
+
if (typeof points[index][key3] === "number") return index;
|
|
34766
|
+
}
|
|
34767
|
+
return -1;
|
|
34768
|
+
}
|
|
34769
|
+
function usePrefersReducedMotion() {
|
|
34770
|
+
const [reduced, setReduced] = React2.useState(false);
|
|
34771
|
+
React2.useEffect(() => {
|
|
34772
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
|
|
34773
|
+
const query = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
34774
|
+
setReduced(query.matches);
|
|
34775
|
+
const onChange = (event) => setReduced(event.matches);
|
|
34776
|
+
query.addEventListener?.("change", onChange);
|
|
34777
|
+
return () => query.removeEventListener?.("change", onChange);
|
|
34778
|
+
}, []);
|
|
34779
|
+
return reduced;
|
|
34780
|
+
}
|
|
34781
|
+
function buildTrend(values, format, formatters) {
|
|
34782
|
+
if (values.length < 2) return void 0;
|
|
34783
|
+
const first = values[0];
|
|
34784
|
+
const last = values[values.length - 1];
|
|
34785
|
+
const difference = last - first;
|
|
34786
|
+
const direction = difference > 0 ? "up" : difference < 0 ? "down" : "flat";
|
|
34787
|
+
const sign = direction === "up" ? "+" : direction === "down" ? MINUS : "";
|
|
34788
|
+
const percent = format !== "percent" && first !== 0 ? ` (${sign}${new Intl.NumberFormat(void 0, { maximumFractionDigits: 2 }).format(
|
|
34789
|
+
Math.abs(difference / Math.abs(first) * 100)
|
|
34790
|
+
)}%)` : "";
|
|
34791
|
+
return {
|
|
34792
|
+
value: formatters.value(last),
|
|
34793
|
+
change: `${sign}${formatters.change(difference)}${percent}`,
|
|
34794
|
+
direction
|
|
34795
|
+
};
|
|
34796
|
+
}
|
|
34797
|
+
var TREND_CLASS = {
|
|
34798
|
+
up: "text-emerald-600 dark:text-emerald-400",
|
|
34799
|
+
down: "text-red-600 dark:text-red-400",
|
|
34800
|
+
flat: "text-muted-foreground"
|
|
34801
|
+
};
|
|
34802
|
+
var TREND_ARROW = { up: "\u25B2", down: "\u25BC", flat: "" };
|
|
34803
|
+
function ChartHeader({
|
|
34804
|
+
title,
|
|
34805
|
+
trend,
|
|
34806
|
+
range
|
|
34807
|
+
}) {
|
|
34808
|
+
if (!trend) {
|
|
34809
|
+
return title ? /* @__PURE__ */ jsx2("p", { className: "mb-3 text-sm font-medium", children: title }) : null;
|
|
34810
|
+
}
|
|
34811
|
+
return /* @__PURE__ */ jsxs("div", { className: "mb-3", "data-testid": "chart-header", children: [
|
|
34812
|
+
title && /* @__PURE__ */ jsx2("p", { className: "text-sm text-muted-foreground", children: title }),
|
|
34813
|
+
/* @__PURE__ */ jsx2("p", { className: "mt-0.5 text-2xl font-semibold tracking-tight text-foreground", children: trend.value }),
|
|
34814
|
+
/* @__PURE__ */ jsxs("p", { className: "mt-0.5 flex flex-wrap items-center gap-x-1.5 text-xs", children: [
|
|
34815
|
+
/* @__PURE__ */ jsxs("span", { className: cx("font-medium", TREND_CLASS[trend.direction]), children: [
|
|
34816
|
+
TREND_ARROW[trend.direction] && /* @__PURE__ */ jsx2("span", { "aria-hidden": "true", className: "mr-1 text-[0.6rem]", children: TREND_ARROW[trend.direction] }),
|
|
34817
|
+
trend.change
|
|
34818
|
+
] }),
|
|
34819
|
+
range && /* @__PURE__ */ jsx2("span", { className: "text-muted-foreground", children: range })
|
|
34820
|
+
] })
|
|
34821
|
+
] });
|
|
34822
|
+
}
|
|
34647
34823
|
function ChartCard({ data }) {
|
|
34648
34824
|
const containerRef = React2.useRef(null);
|
|
34649
34825
|
const [ready, setReady] = React2.useState(false);
|
|
34826
|
+
const gradientId = `chart-fill-${React2.useId().replace(/:/g, "")}`;
|
|
34827
|
+
const reducedMotion = usePrefersReducedMotion();
|
|
34650
34828
|
React2.useEffect(() => {
|
|
34651
34829
|
const frame = requestAnimationFrame(() => setReady(true));
|
|
34652
34830
|
return () => cancelAnimationFrame(frame);
|
|
34653
34831
|
}, []);
|
|
34654
34832
|
if ("error" in data) {
|
|
34655
|
-
return /* @__PURE__ */ jsx2("div", { className: "my-4 max-w-lg", children: /* @__PURE__ */ jsx2("div", { className: "rounded-xl bg-sidebar dark:bg-card px-4 py-3", children: /* @__PURE__ */ jsx2("p", { className: "text-sm text-muted-foreground", children:
|
|
34833
|
+
return /* @__PURE__ */ jsx2("div", { className: "my-4 max-w-lg", children: /* @__PURE__ */ jsx2("div", { className: "rounded-xl bg-sidebar dark:bg-card px-4 py-3", children: /* @__PURE__ */ jsx2("p", { className: "text-sm text-muted-foreground", children: "Couldn't display this chart." }) }) });
|
|
34656
34834
|
}
|
|
34657
|
-
const {
|
|
34835
|
+
const {
|
|
34836
|
+
chartType,
|
|
34837
|
+
title,
|
|
34838
|
+
data: chartData,
|
|
34839
|
+
dataKeys,
|
|
34840
|
+
xAxisKey,
|
|
34841
|
+
colors,
|
|
34842
|
+
valueFormat,
|
|
34843
|
+
currency
|
|
34844
|
+
} = data;
|
|
34658
34845
|
const chartConfig = buildChartConfig(dataKeys, colors);
|
|
34659
|
-
|
|
34660
|
-
|
|
34661
|
-
|
|
34662
|
-
|
|
34663
|
-
|
|
34664
|
-
|
|
34665
|
-
|
|
34666
|
-
|
|
34667
|
-
|
|
34668
|
-
|
|
34669
|
-
|
|
34670
|
-
|
|
34671
|
-
|
|
34672
|
-
|
|
34673
|
-
|
|
34674
|
-
|
|
34675
|
-
|
|
34676
|
-
|
|
34677
|
-
|
|
34678
|
-
|
|
34679
|
-
|
|
34680
|
-
|
|
34681
|
-
|
|
34682
|
-
|
|
34683
|
-
|
|
34684
|
-
|
|
34685
|
-
|
|
34686
|
-
|
|
34687
|
-
|
|
34688
|
-
|
|
34689
|
-
|
|
34690
|
-
|
|
34691
|
-
|
|
34692
|
-
|
|
34693
|
-
|
|
34694
|
-
|
|
34695
|
-
|
|
34696
|
-
|
|
34697
|
-
|
|
34698
|
-
|
|
34699
|
-
|
|
34700
|
-
|
|
34701
|
-
|
|
34702
|
-
|
|
34703
|
-
|
|
34846
|
+
const seriesColor = (key3) => chartConfig[key3]?.color;
|
|
34847
|
+
const isTrendChart = chartType === "line" || chartType === "area";
|
|
34848
|
+
const plottedKeys = chartType === "pie" ? dataKeys.slice(0, 1) : dataKeys;
|
|
34849
|
+
const values = seriesValues(chartData, plottedKeys);
|
|
34850
|
+
const yTicks = isTrendChart ? niceTicks(values) : void 0;
|
|
34851
|
+
const yDomain = yTicks ? [yTicks[0], yTicks[yTicks.length - 1]] : void 0;
|
|
34852
|
+
const formatters = buildFormatters(valueFormat, currency, yTicks);
|
|
34853
|
+
const trend = isTrendChart && dataKeys.length === 1 ? buildTrend(values, valueFormat, formatters) : void 0;
|
|
34854
|
+
const trendRows = trend ? chartData.filter((point) => typeof point[dataKeys[0]] === "number") : [];
|
|
34855
|
+
const range = trend && xAxisKey ? [trendRows[0], trendRows[trendRows.length - 1]].map((point) => cellText(point[xAxisKey])).filter(Boolean).join(" \u2013 ") : void 0;
|
|
34856
|
+
const headerTitle = title ?? (trend ? chartConfig[dataKeys[0]]?.label : void 0);
|
|
34857
|
+
const tickSamples = [...yDomain ?? [], ...values].map((value) => formatters.tick(value));
|
|
34858
|
+
const longestTick = tickSamples.reduce((max, label) => Math.max(max, label.length), 0);
|
|
34859
|
+
const animate = !reducedMotion;
|
|
34860
|
+
const showDots = chartData.length <= DOT_LIMIT;
|
|
34861
|
+
const curve = showDots ? "linear" : "monotone";
|
|
34862
|
+
const hasNegative = values.some((value) => value < 0);
|
|
34863
|
+
const margin = { top: 8, right: 8, bottom: 0, left: 0 };
|
|
34864
|
+
const xAxis = xAxisKey && /* @__PURE__ */ jsx2(
|
|
34865
|
+
XAxis,
|
|
34866
|
+
{
|
|
34867
|
+
dataKey: xAxisKey,
|
|
34868
|
+
tickLine: false,
|
|
34869
|
+
axisLine: false,
|
|
34870
|
+
tickMargin: 8,
|
|
34871
|
+
minTickGap: 16,
|
|
34872
|
+
interval: "preserveStartEnd",
|
|
34873
|
+
padding: isTrendChart ? { left: 12, right: 12 } : void 0
|
|
34874
|
+
}
|
|
34875
|
+
);
|
|
34876
|
+
const yAxis = /* @__PURE__ */ jsx2(
|
|
34877
|
+
YAxis,
|
|
34878
|
+
{
|
|
34879
|
+
tickLine: false,
|
|
34880
|
+
axisLine: false,
|
|
34881
|
+
tickCount: yTicks ? void 0 : 4,
|
|
34882
|
+
ticks: yTicks,
|
|
34883
|
+
tickMargin: 4,
|
|
34884
|
+
tickFormatter: formatters.tick,
|
|
34885
|
+
domain: yDomain,
|
|
34886
|
+
allowDataOverflow: false,
|
|
34887
|
+
width: Math.min(120, Math.max(36, longestTick * 7 + 12))
|
|
34888
|
+
}
|
|
34889
|
+
);
|
|
34890
|
+
const tooltip = /* @__PURE__ */ jsx2(
|
|
34891
|
+
ChartTooltip,
|
|
34892
|
+
{
|
|
34893
|
+
cursor: chartType === "bar" ? { fill: "var(--muted)", opacity: 0.5 } : { stroke: "var(--border)", strokeWidth: 1 },
|
|
34894
|
+
content: /* @__PURE__ */ jsx2(
|
|
34895
|
+
ChartTooltipContent,
|
|
34704
34896
|
{
|
|
34705
|
-
|
|
34706
|
-
|
|
34707
|
-
nameKey: xAxisKey || "name",
|
|
34708
|
-
cx: "50%",
|
|
34709
|
-
cy: "50%",
|
|
34710
|
-
outerRadius: 80,
|
|
34711
|
-
children: chartData.map((_, index) => /* @__PURE__ */ jsx2(Cell, { fill: DEFAULT_COLORS[index % DEFAULT_COLORS.length] }, index))
|
|
34897
|
+
indicator: chartType === "bar" ? "dot" : "line",
|
|
34898
|
+
valueFormatter: formatters.value
|
|
34712
34899
|
}
|
|
34713
|
-
)
|
|
34714
|
-
|
|
34715
|
-
|
|
34716
|
-
|
|
34900
|
+
)
|
|
34901
|
+
}
|
|
34902
|
+
);
|
|
34903
|
+
const legend = dataKeys.length > 1 && /* @__PURE__ */ jsx2(ChartLegend, { content: /* @__PURE__ */ jsx2(ChartLegendContent, {}) });
|
|
34904
|
+
const marker = (key3, r) => ({
|
|
34905
|
+
r,
|
|
34906
|
+
fill: seriesColor(key3),
|
|
34907
|
+
stroke: SURFACE,
|
|
34908
|
+
strokeWidth: 2
|
|
34909
|
+
});
|
|
34910
|
+
const lineDot = (key3) => showDots ? marker(key3, 4) : (props) => props.index === lastValueIndex(chartData, key3) && typeof props.cx === "number" && typeof props.cy === "number" ? /* @__PURE__ */ jsx2("circle", { cx: props.cx, cy: props.cy, ...marker(key3, 4) }, `end-${key3}`) : /* @__PURE__ */ jsx2("g", {}, `dot-${key3}-${props.index}`);
|
|
34911
|
+
const labelKey = chartType === "pie" ? xAxisKey || "name" : xAxisKey;
|
|
34912
|
+
const tableColumns = labelKey ? [labelKey, ...plottedKeys] : plottedKeys;
|
|
34913
|
+
return /* @__PURE__ */ jsx2(
|
|
34914
|
+
"div",
|
|
34915
|
+
{
|
|
34916
|
+
className: "my-4 max-w-lg",
|
|
34917
|
+
ref: containerRef,
|
|
34918
|
+
role: "figure",
|
|
34919
|
+
"aria-label": [title, `${chartType} chart`].filter(Boolean).join(", "),
|
|
34920
|
+
children: /* @__PURE__ */ jsxs("div", { className: "rounded-xl bg-sidebar dark:bg-card px-5 py-4 [--chart-surface:var(--sidebar)] dark:[--chart-surface:var(--card)]", children: [
|
|
34921
|
+
/* @__PURE__ */ jsx2(ChartHeader, { title: headerTitle, trend, range }),
|
|
34922
|
+
/* @__PURE__ */ jsxs("table", { style: VISUALLY_HIDDEN, children: [
|
|
34923
|
+
/* @__PURE__ */ jsx2("thead", { children: /* @__PURE__ */ jsx2("tr", { children: tableColumns.map((column) => /* @__PURE__ */ jsx2("th", { scope: "col", children: column }, column)) }) }),
|
|
34924
|
+
/* @__PURE__ */ jsx2("tbody", { children: chartData.map((point, row) => /* @__PURE__ */ jsx2("tr", { children: tableColumns.map((column) => /* @__PURE__ */ jsx2("td", { children: cellText(point[column]) }, column)) }, row)) })
|
|
34925
|
+
] }),
|
|
34926
|
+
ready ? /* @__PURE__ */ jsx2(
|
|
34927
|
+
ChartContainer,
|
|
34928
|
+
{
|
|
34929
|
+
config: chartConfig,
|
|
34930
|
+
className: "aspect-auto h-[220px] w-full",
|
|
34931
|
+
"aria-hidden": "true",
|
|
34932
|
+
children: chartType === "bar" ? /* @__PURE__ */ jsxs(BarChart, { data: chartData, margin, barGap: 2, barCategoryGap: "24%", children: [
|
|
34933
|
+
/* @__PURE__ */ jsx2(CartesianGrid, { vertical: false }),
|
|
34934
|
+
xAxis,
|
|
34935
|
+
yAxis,
|
|
34936
|
+
tooltip,
|
|
34937
|
+
legend,
|
|
34938
|
+
dataKeys.map((key3) => /* @__PURE__ */ jsx2(
|
|
34939
|
+
Bar,
|
|
34940
|
+
{
|
|
34941
|
+
dataKey: key3,
|
|
34942
|
+
fill: seriesColor(key3),
|
|
34943
|
+
maxBarSize: 24,
|
|
34944
|
+
radius: hasNegative ? 2 : [4, 4, 0, 0],
|
|
34945
|
+
isAnimationActive: animate
|
|
34946
|
+
},
|
|
34947
|
+
key3
|
|
34948
|
+
))
|
|
34949
|
+
] }) : chartType === "line" ? /* @__PURE__ */ jsxs(LineChart, { data: chartData, margin, children: [
|
|
34950
|
+
/* @__PURE__ */ jsx2(CartesianGrid, { vertical: false }),
|
|
34951
|
+
xAxis,
|
|
34952
|
+
yAxis,
|
|
34953
|
+
tooltip,
|
|
34954
|
+
legend,
|
|
34955
|
+
dataKeys.map((key3) => /* @__PURE__ */ jsx2(
|
|
34956
|
+
Line2,
|
|
34957
|
+
{
|
|
34958
|
+
type: curve,
|
|
34959
|
+
dataKey: key3,
|
|
34960
|
+
stroke: seriesColor(key3),
|
|
34961
|
+
strokeWidth: 2,
|
|
34962
|
+
strokeLinecap: "round",
|
|
34963
|
+
strokeLinejoin: "round",
|
|
34964
|
+
dot: lineDot(key3),
|
|
34965
|
+
activeDot: marker(key3, 5),
|
|
34966
|
+
isAnimationActive: animate,
|
|
34967
|
+
animationDuration: 600
|
|
34968
|
+
},
|
|
34969
|
+
key3
|
|
34970
|
+
))
|
|
34971
|
+
] }) : chartType === "area" ? /* @__PURE__ */ jsxs(AreaChart, { data: chartData, margin, children: [
|
|
34972
|
+
/* @__PURE__ */ jsx2("defs", { children: dataKeys.map((key3, index) => /* @__PURE__ */ jsxs(
|
|
34973
|
+
"linearGradient",
|
|
34974
|
+
{
|
|
34975
|
+
id: `${gradientId}-${index}`,
|
|
34976
|
+
x1: "0",
|
|
34977
|
+
y1: "0",
|
|
34978
|
+
x2: "0",
|
|
34979
|
+
y2: "1",
|
|
34980
|
+
children: [
|
|
34981
|
+
/* @__PURE__ */ jsx2("stop", { offset: "0%", stopColor: seriesColor(key3), stopOpacity: 0.24 }),
|
|
34982
|
+
/* @__PURE__ */ jsx2("stop", { offset: "100%", stopColor: seriesColor(key3), stopOpacity: 0 })
|
|
34983
|
+
]
|
|
34984
|
+
},
|
|
34985
|
+
key3
|
|
34986
|
+
)) }),
|
|
34987
|
+
/* @__PURE__ */ jsx2(CartesianGrid, { vertical: false }),
|
|
34988
|
+
xAxis,
|
|
34989
|
+
yAxis,
|
|
34990
|
+
tooltip,
|
|
34991
|
+
legend,
|
|
34992
|
+
dataKeys.map((key3, index) => /* @__PURE__ */ jsx2(
|
|
34993
|
+
Area,
|
|
34994
|
+
{
|
|
34995
|
+
type: curve,
|
|
34996
|
+
dataKey: key3,
|
|
34997
|
+
stroke: seriesColor(key3),
|
|
34998
|
+
strokeWidth: 2,
|
|
34999
|
+
fill: `url(#${gradientId}-${index})`,
|
|
35000
|
+
dot: lineDot(key3),
|
|
35001
|
+
activeDot: marker(key3, 5),
|
|
35002
|
+
baseValue: "dataMin",
|
|
35003
|
+
isAnimationActive: animate,
|
|
35004
|
+
animationDuration: 600
|
|
35005
|
+
},
|
|
35006
|
+
key3
|
|
35007
|
+
))
|
|
35008
|
+
] }) : /* @__PURE__ */ jsxs(PieChart, { margin, children: [
|
|
35009
|
+
tooltip,
|
|
35010
|
+
/* @__PURE__ */ jsxs(
|
|
35011
|
+
Pie,
|
|
35012
|
+
{
|
|
35013
|
+
data: chartData,
|
|
35014
|
+
dataKey: dataKeys[0],
|
|
35015
|
+
nameKey: xAxisKey || "name",
|
|
35016
|
+
cx: "50%",
|
|
35017
|
+
cy: "50%",
|
|
35018
|
+
innerRadius: "58%",
|
|
35019
|
+
outerRadius: "86%",
|
|
35020
|
+
paddingAngle: chartData.length > 1 ? 1 : 0,
|
|
35021
|
+
stroke: SURFACE,
|
|
35022
|
+
strokeWidth: 2,
|
|
35023
|
+
isAnimationActive: animate,
|
|
35024
|
+
children: [
|
|
35025
|
+
chartData.map((_, index) => /* @__PURE__ */ jsx2(Cell, { fill: paletteColor(index) }, index)),
|
|
35026
|
+
/* @__PURE__ */ jsx2(
|
|
35027
|
+
Label,
|
|
35028
|
+
{
|
|
35029
|
+
position: "center",
|
|
35030
|
+
content: ({ viewBox }) => {
|
|
35031
|
+
const box = viewBox;
|
|
35032
|
+
if (box?.cx === void 0 || box.cy === void 0) return null;
|
|
35033
|
+
return /* @__PURE__ */ jsxs("text", { x: box.cx, y: box.cy, textAnchor: "middle", dominantBaseline: "middle", children: [
|
|
35034
|
+
/* @__PURE__ */ jsx2(
|
|
35035
|
+
"tspan",
|
|
35036
|
+
{
|
|
35037
|
+
x: box.cx,
|
|
35038
|
+
y: box.cy - 6,
|
|
35039
|
+
className: "fill-foreground text-lg font-semibold",
|
|
35040
|
+
children: formatters.value(values.reduce((sum, value) => sum + value, 0))
|
|
35041
|
+
}
|
|
35042
|
+
),
|
|
35043
|
+
/* @__PURE__ */ jsx2("tspan", { x: box.cx, y: box.cy + 14, className: "fill-muted-foreground", children: "Total" })
|
|
35044
|
+
] });
|
|
35045
|
+
}
|
|
35046
|
+
}
|
|
35047
|
+
)
|
|
35048
|
+
]
|
|
35049
|
+
}
|
|
35050
|
+
),
|
|
35051
|
+
/* @__PURE__ */ jsx2(ChartLegend, { content: /* @__PURE__ */ jsx2(ChartLegendContent, { nameKey: xAxisKey || "name" }) })
|
|
35052
|
+
] })
|
|
35053
|
+
}
|
|
35054
|
+
) : /* @__PURE__ */ jsx2("div", { className: "h-[220px] w-full" })
|
|
35055
|
+
] })
|
|
35056
|
+
}
|
|
35057
|
+
);
|
|
34717
35058
|
}
|
|
34718
35059
|
|
|
34719
35060
|
// src/react/LoggerProvider.tsx
|
package/dist/tools/index.cjs
CHANGED
|
@@ -2529,10 +2529,33 @@ function createDisplayTool(options, config) {
|
|
|
2529
2529
|
}
|
|
2530
2530
|
|
|
2531
2531
|
// src/tools/chart.ts
|
|
2532
|
+
var VALUE_FORMATS = ["number", "currency", "percent"];
|
|
2533
|
+
var CURRENCY_CODE = /^[A-Z]{3}$/;
|
|
2534
|
+
function toValueFormat(value) {
|
|
2535
|
+
return VALUE_FORMATS.find((format) => format === value);
|
|
2536
|
+
}
|
|
2537
|
+
function toCurrencyCode(value) {
|
|
2538
|
+
if (typeof value !== "string") return void 0;
|
|
2539
|
+
const code = value.trim().toUpperCase();
|
|
2540
|
+
return CURRENCY_CODE.test(code) ? code : void 0;
|
|
2541
|
+
}
|
|
2542
|
+
var NUMERIC_STRING = /^[-+]?(?:\d+\.?\d*|\.\d+)(?:e[-+]?\d+)?$/i;
|
|
2543
|
+
var THOUSANDS_GROUPED = /^[-+]?\d{1,3}(?:,\d{3})+(?:\.\d*)?$/;
|
|
2544
|
+
function toNumber(value) {
|
|
2545
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : void 0;
|
|
2546
|
+
if (typeof value !== "string") return void 0;
|
|
2547
|
+
let cleaned = value.replace(/[\s$€£¥%]/g, "");
|
|
2548
|
+
if (cleaned.includes(",")) {
|
|
2549
|
+
if (!THOUSANDS_GROUPED.test(cleaned)) return void 0;
|
|
2550
|
+
cleaned = cleaned.replace(/,/g, "");
|
|
2551
|
+
}
|
|
2552
|
+
const number = NUMERIC_STRING.test(cleaned) ? Number(cleaned) : void 0;
|
|
2553
|
+
return number !== void 0 && Number.isFinite(number) ? number : void 0;
|
|
2554
|
+
}
|
|
2532
2555
|
function createChartTool(options) {
|
|
2533
2556
|
return createDisplayTool(options, {
|
|
2534
2557
|
name: "display_chart",
|
|
2535
|
-
description: 'Render a bar, line, area, or pie chart inline \u2014 visualize data, plot a trend over time, or graph a comparison. Use whenever the user asks to chart, plot, graph, or visualize numbers (sales, prices, temperatures, metrics). You MUST pass the actual numeric values in the "data" array \u2014 they are never inferred.',
|
|
2558
|
+
description: 'Render a bar, line, area, or pie chart inline \u2014 visualize data, plot a trend over time, or graph a comparison. Use whenever the user asks to chart, plot, graph, or visualize numbers (sales, prices, temperatures, metrics). You MUST pass the actual numeric values in the "data" array \u2014 they are never inferred. Do not chart price or market history (crypto, stocks, market caps) unless those values came from a tool result or a cited source earlier in this conversation; never fill a price series from memory. Set valueFormat to "currency" for prices and money, or "percent" for percentage values.',
|
|
2536
2559
|
parameters: {
|
|
2537
2560
|
type: "object",
|
|
2538
2561
|
properties: {
|
|
@@ -2566,6 +2589,15 @@ function createChartTool(options) {
|
|
|
2566
2589
|
type: "object",
|
|
2567
2590
|
additionalProperties: { type: "string" },
|
|
2568
2591
|
description: "Optional color overrides. Map of dataKey to CSS color value (e.g. { 'revenue': '#2563eb' }). If omitted, uses theme chart colors."
|
|
2592
|
+
},
|
|
2593
|
+
valueFormat: {
|
|
2594
|
+
type: "string",
|
|
2595
|
+
enum: ["number", "currency", "percent"],
|
|
2596
|
+
description: 'How to display the values on the axis, tooltip and headline. "currency" for prices and money (set currency too), "percent" when values are already percentages (3.2 means 3.2%). Defaults to "number".'
|
|
2597
|
+
},
|
|
2598
|
+
currency: {
|
|
2599
|
+
type: "string",
|
|
2600
|
+
description: 'ISO 4217 currency code used when valueFormat is "currency", e.g. "USD" or "EUR". Defaults to USD.'
|
|
2569
2601
|
}
|
|
2570
2602
|
},
|
|
2571
2603
|
required: ["chartType", "data", "dataKeys"]
|
|
@@ -2590,13 +2622,36 @@ function createChartTool(options) {
|
|
|
2590
2622
|
error: 'The "dataKeys" array is required and must list the numeric keys to chart, e.g. ["revenue"].'
|
|
2591
2623
|
};
|
|
2592
2624
|
}
|
|
2625
|
+
const points = data.map((point) => ({ ...point }));
|
|
2626
|
+
for (const key of dataKeys) {
|
|
2627
|
+
let numericCount = 0;
|
|
2628
|
+
for (const [index, point] of points.entries()) {
|
|
2629
|
+
const raw = point[key];
|
|
2630
|
+
if (raw === void 0 || raw === null) continue;
|
|
2631
|
+
const value = toNumber(raw);
|
|
2632
|
+
if (value === void 0) {
|
|
2633
|
+
return {
|
|
2634
|
+
error: `Series "${key}" has a non-numeric value at data[${index}]: ${JSON.stringify(raw)}. Values for dataKeys must be plain numbers, e.g. 65000 rather than "$65,000 USD".`
|
|
2635
|
+
};
|
|
2636
|
+
}
|
|
2637
|
+
point[key] = value;
|
|
2638
|
+
numericCount++;
|
|
2639
|
+
}
|
|
2640
|
+
if (numericCount === 0) {
|
|
2641
|
+
return {
|
|
2642
|
+
error: `Series "${key}" has no numeric values. Every entry in "dataKeys" must name a numeric key present in the "data" objects.`
|
|
2643
|
+
};
|
|
2644
|
+
}
|
|
2645
|
+
}
|
|
2593
2646
|
return {
|
|
2594
2647
|
chartType,
|
|
2595
2648
|
title: args.title,
|
|
2596
|
-
data,
|
|
2649
|
+
data: points,
|
|
2597
2650
|
dataKeys,
|
|
2598
2651
|
xAxisKey: args.xAxisKey,
|
|
2599
|
-
colors: args.colors
|
|
2652
|
+
colors: args.colors,
|
|
2653
|
+
valueFormat: toValueFormat(args.valueFormat),
|
|
2654
|
+
currency: toCurrencyCode(args.currency)
|
|
2600
2655
|
};
|
|
2601
2656
|
}
|
|
2602
2657
|
});
|