@tensor_1/react 2.37.0 → 2.39.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -0
- package/dist/{chart-theme-Cl0IrkKQ.d.cts → ChartCore-BKK2HEfi.d.cts} +77 -50
- package/dist/chart-analytic-guide.d.ts +6 -0
- package/dist/chart-analytic-guide.js +10 -0
- package/dist/chart-analytic-model.d.ts +141 -0
- package/dist/chart-analytic-model.js +252 -0
- package/dist/chart-analytic.cjs +1372 -0
- package/dist/chart-analytic.d.cts +335 -0
- package/dist/chart-analytic.d.ts +19 -0
- package/dist/chart-analytic.js +95 -0
- package/dist/chart-panels-model.d.ts +92 -0
- package/dist/chart-panels-model.js +284 -0
- package/dist/chart-preset.cjs +41 -4
- package/dist/chart-preset.d.cts +2 -2
- package/dist/chart-preset.d.ts +1 -1
- package/dist/chart-stats-o4zDhpVm.d.cts +46 -0
- package/dist/chart-stats.d.ts +46 -0
- package/dist/chart-stats.js +89 -0
- package/dist/chart-theme.d.ts +3 -0
- package/dist/chart-theme.js +2 -0
- package/dist/chart.cjs +41 -4
- package/dist/chart.d.cts +2 -2
- package/dist/chart.d.ts +1 -1
- package/dist/components/Chart.d.ts +1 -1
- package/dist/components/ChartCore.d.ts +23 -3
- package/dist/components/ChartCore.js +40 -5
- package/dist/components/ChartPanels.d.ts +52 -0
- package/dist/components/ChartPanels.js +170 -0
- package/dist/components/InsightCard.d.ts +86 -0
- package/dist/components/InsightCard.js +118 -0
- package/dist/components/Stat.d.ts +7 -0
- package/dist/components/Stat.js +6 -3
- package/dist/correlation-scatter-model.d.ts +68 -0
- package/dist/correlation-scatter-model.js +179 -0
- package/dist/icons/Icon.d.ts +23 -23
- package/dist/index.cjs +1185 -961
- package/dist/index.d.cts +91 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +10 -0
- package/package.json +6 -1
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cx } from "../cx.js";
|
|
3
|
+
import { CircleCheckIcon, CircleQuestionMarkIcon, OctagonAlertIcon, TriangleAlertIcon } from "../icons/components.js";
|
|
4
|
+
const defaultNumber = new Intl.NumberFormat("en", { maximumFractionDigits: 1 });
|
|
5
|
+
const DEFAULT_INSIGHT_CARD_LABELS = {
|
|
6
|
+
coverage: (covered, total, percent, note) => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
7
|
+
covered,
|
|
8
|
+
" of ",
|
|
9
|
+
total,
|
|
10
|
+
" ",
|
|
11
|
+
note,
|
|
12
|
+
" (",
|
|
13
|
+
percent,
|
|
14
|
+
"%)"
|
|
15
|
+
] }),
|
|
16
|
+
bullet: (actual, target) => `${actual} against a target of ${target}`,
|
|
17
|
+
source: "Source",
|
|
18
|
+
updated: "Updated",
|
|
19
|
+
kpis: "Key figures",
|
|
20
|
+
formatNumber: (value) => defaultNumber.format(value)
|
|
21
|
+
};
|
|
22
|
+
const STATUS_ICON = {
|
|
23
|
+
ok: CircleCheckIcon,
|
|
24
|
+
warning: TriangleAlertIcon,
|
|
25
|
+
critical: OctagonAlertIcon,
|
|
26
|
+
unknown: CircleQuestionMarkIcon
|
|
27
|
+
};
|
|
28
|
+
function InsightCard({
|
|
29
|
+
eyebrow,
|
|
30
|
+
headline,
|
|
31
|
+
sowhat,
|
|
32
|
+
status,
|
|
33
|
+
kpis,
|
|
34
|
+
coverage,
|
|
35
|
+
actions,
|
|
36
|
+
source,
|
|
37
|
+
updated,
|
|
38
|
+
layout = "stack",
|
|
39
|
+
variant = "card",
|
|
40
|
+
aside,
|
|
41
|
+
headingLevel = 3,
|
|
42
|
+
labels: labelOverrides,
|
|
43
|
+
className,
|
|
44
|
+
children,
|
|
45
|
+
...props
|
|
46
|
+
}) {
|
|
47
|
+
const labels = { ...DEFAULT_INSIGHT_CARD_LABELS, ...labelOverrides };
|
|
48
|
+
const Heading = `h${headingLevel}`;
|
|
49
|
+
const StatusIcon = status ? STATUS_ICON[status.tone] : null;
|
|
50
|
+
const percent = coverage && coverage.total > 0 ? Math.round(coverage.covered / coverage.total * 100) : null;
|
|
51
|
+
const hasFooter = coverage != null || source != null || updated != null || actions != null;
|
|
52
|
+
return /* @__PURE__ */ jsxs("article", { className: cx("uix-insight", variant === "plain" && "uix-insight--plain", className), "data-layout": layout, ...props, children: [
|
|
53
|
+
/* @__PURE__ */ jsxs("header", { className: "uix-insight__header", children: [
|
|
54
|
+
/* @__PURE__ */ jsxs("div", { className: "uix-insight__heading", children: [
|
|
55
|
+
eyebrow != null ? /* @__PURE__ */ jsx("div", { className: "uix-insight__eyebrow", children: eyebrow }) : null,
|
|
56
|
+
/* @__PURE__ */ jsx(Heading, { className: "uix-insight__headline", children: headline }),
|
|
57
|
+
sowhat != null ? /* @__PURE__ */ jsx("p", { className: "uix-insight__sowhat", children: sowhat }) : null
|
|
58
|
+
] }),
|
|
59
|
+
status && StatusIcon ? /* @__PURE__ */ jsxs("span", { className: "uix-insight__status", "data-tone": status.tone, children: [
|
|
60
|
+
/* @__PURE__ */ jsx(StatusIcon, { size: "sm", "aria-hidden": "true" }),
|
|
61
|
+
/* @__PURE__ */ jsx("span", { children: status.label })
|
|
62
|
+
] }) : null
|
|
63
|
+
] }),
|
|
64
|
+
kpis?.length ? /* @__PURE__ */ jsx("dl", { className: "uix-insight__kpis", "aria-label": labels.kpis, children: kpis.map((kpi, index) => /* @__PURE__ */ jsxs("div", { className: "uix-insight__kpi", children: [
|
|
65
|
+
/* @__PURE__ */ jsx("dt", { className: "uix-insight__kpi-label", children: kpi.label }),
|
|
66
|
+
/* @__PURE__ */ jsx("dd", { className: "uix-insight__kpi-value", children: kpi.value }),
|
|
67
|
+
kpi.comparison ? /* @__PURE__ */ jsx("dd", { className: "uix-insight__kpi-comparison", "data-tone": kpi.comparison.tone ?? "neutral", children: kpi.comparison.text }) : null,
|
|
68
|
+
kpi.target ? /* @__PURE__ */ jsx("dd", { className: "uix-insight__kpi-target", children: /* @__PURE__ */ jsx(Bullet, { ...kpi.target, label: labels.bullet(labels.formatNumber(kpi.target.actual), labels.formatNumber(kpi.target.target)) }) }) : null
|
|
69
|
+
] }, index)) }) : null,
|
|
70
|
+
children != null || aside != null ? /* @__PURE__ */ jsxs("div", { className: "uix-insight__body", children: [
|
|
71
|
+
children != null ? /* @__PURE__ */ jsx("div", { className: "uix-insight__main", children }) : null,
|
|
72
|
+
aside != null ? /* @__PURE__ */ jsx("div", { className: "uix-insight__aside", children: aside }) : null
|
|
73
|
+
] }) : null,
|
|
74
|
+
hasFooter ? /* @__PURE__ */ jsxs("footer", { className: "uix-insight__footer", children: [
|
|
75
|
+
/* @__PURE__ */ jsxs("div", { className: "uix-insight__meta", children: [
|
|
76
|
+
coverage && percent != null ? /* @__PURE__ */ jsxs("p", { className: "uix-insight__coverage", children: [
|
|
77
|
+
labels.coverage(coverage.covered, coverage.total, percent, coverage.note),
|
|
78
|
+
coverage.partialPeriod != null ? /* @__PURE__ */ jsx("span", { className: "uix-insight__partial", children: coverage.partialPeriod }) : null
|
|
79
|
+
] }) : null,
|
|
80
|
+
source != null || updated != null ? /* @__PURE__ */ jsxs("p", { className: "uix-insight__source", children: [
|
|
81
|
+
source != null ? /* @__PURE__ */ jsxs("span", { children: [
|
|
82
|
+
labels.source,
|
|
83
|
+
": ",
|
|
84
|
+
source
|
|
85
|
+
] }) : null,
|
|
86
|
+
updated != null ? /* @__PURE__ */ jsxs("span", { children: [
|
|
87
|
+
labels.updated,
|
|
88
|
+
": ",
|
|
89
|
+
updated
|
|
90
|
+
] }) : null
|
|
91
|
+
] }) : null
|
|
92
|
+
] }),
|
|
93
|
+
actions != null ? /* @__PURE__ */ jsx("div", { className: "uix-insight__actions", children: actions }) : null
|
|
94
|
+
] }) : null
|
|
95
|
+
] });
|
|
96
|
+
}
|
|
97
|
+
function Bullet({ actual, target, ranges, max, label, className, style, ...props }) {
|
|
98
|
+
const end = Math.max(max ?? 0, ...(ranges ?? []).map((r) => r[1]), actual, target, 0) * (max ? 1 : 1.1) || 1;
|
|
99
|
+
const pct = (value) => `${Math.max(0, Math.min(100, value / end * 100))}%`;
|
|
100
|
+
return /* @__PURE__ */ jsxs("div", { className: cx("uix-bullet", className), role: "img", "aria-label": label, style, ...props, children: [
|
|
101
|
+
(ranges ?? []).map(([from, to], index) => /* @__PURE__ */ jsx(
|
|
102
|
+
"span",
|
|
103
|
+
{
|
|
104
|
+
className: "uix-bullet__range",
|
|
105
|
+
"data-band": Math.min(index, 2),
|
|
106
|
+
style: { left: pct(from), width: `calc(${pct(to)} - ${pct(from)})` }
|
|
107
|
+
},
|
|
108
|
+
index
|
|
109
|
+
)),
|
|
110
|
+
/* @__PURE__ */ jsx("span", { className: "uix-bullet__bar", style: { width: pct(actual) } }),
|
|
111
|
+
/* @__PURE__ */ jsx("span", { className: "uix-bullet__target", style: { left: pct(target) } })
|
|
112
|
+
] });
|
|
113
|
+
}
|
|
114
|
+
export {
|
|
115
|
+
Bullet,
|
|
116
|
+
DEFAULT_INSIGHT_CARD_LABELS,
|
|
117
|
+
InsightCard
|
|
118
|
+
};
|
|
@@ -33,6 +33,13 @@ interface StatProps extends HTMLAttributes<HTMLElement> {
|
|
|
33
33
|
};
|
|
34
34
|
/** Whether the editor this tile opens is currently open (`aria-expanded`). */
|
|
35
35
|
expanded?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* What the tile started is still running (HAR-1753). The button is announced as busy and
|
|
38
|
+
* unavailable (`aria-busy`, `aria-disabled`) and stays focusable; `onActivate`, `onClick` and
|
|
39
|
+
* `onKeyDown` are not called until it ends. Only with `onActivate`: a read-only tile and a
|
|
40
|
+
* link tile ignore it.
|
|
41
|
+
*/
|
|
42
|
+
pending?: boolean;
|
|
36
43
|
/**
|
|
37
44
|
* What `onActivate` opens, for `aria-haspopup` (HAR-1350; TENSOR B6). Default `'dialog'`;
|
|
38
45
|
* `'menu'` for a status menu; `false` for an in-place action (no chevron either).
|
package/dist/components/Stat.js
CHANGED
|
@@ -3,7 +3,7 @@ import { forwardRef, useId } from "react";
|
|
|
3
3
|
import { cx } from "../cx.js";
|
|
4
4
|
import { renderUixLink } from "../link.js";
|
|
5
5
|
const Chevron = () => /* @__PURE__ */ jsx("span", { className: "uix-stat__chevron", "aria-hidden": "true", children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "m6 9 6 6 6-6" }) }) });
|
|
6
|
-
const Stat = forwardRef(function Stat2({ label, value, icon, meta, trend, tone = "neutral", size = "hero", onActivate, activateLabel, expanded, trendLabels, haspopup = "dialog", href, current, renderLink, className, onClick, ...props }, ref) {
|
|
6
|
+
const Stat = forwardRef(function Stat2({ label, value, icon, meta, trend, tone = "neutral", size = "hero", onActivate, activateLabel, expanded, trendLabels, haspopup = "dialog", href, current, renderLink, className, onClick, onKeyDown, pending = false, ...props }, ref) {
|
|
7
7
|
const id = useId();
|
|
8
8
|
const interactive = onActivate != null;
|
|
9
9
|
const linked = !interactive && href != null;
|
|
@@ -33,11 +33,11 @@ const Stat = forwardRef(function Stat2({ label, value, icon, meta, trend, tone =
|
|
|
33
33
|
] })
|
|
34
34
|
] });
|
|
35
35
|
if (linked) {
|
|
36
|
-
const linkProps = { ...props, href, className: classes, onClick, "aria-current": current ? "page" : void 0, children: body };
|
|
36
|
+
const linkProps = { ...props, href, className: classes, onClick, onKeyDown, "aria-current": current ? "page" : void 0, children: body };
|
|
37
37
|
return /* @__PURE__ */ jsx(Fragment, { children: renderLink ? renderUixLink(renderLink, linkProps) : /* @__PURE__ */ jsx("a", { ref, ...linkProps }) });
|
|
38
38
|
}
|
|
39
39
|
if (!interactive) {
|
|
40
|
-
return /* @__PURE__ */ jsx("div", { ref, className: classes, onClick, ...props, children: body });
|
|
40
|
+
return /* @__PURE__ */ jsx("div", { ref, className: classes, onClick, onKeyDown, ...props, children: body });
|
|
41
41
|
}
|
|
42
42
|
return /* @__PURE__ */ jsxs(
|
|
43
43
|
"button",
|
|
@@ -50,10 +50,13 @@ const Stat = forwardRef(function Stat2({ label, value, icon, meta, trend, tone =
|
|
|
50
50
|
"aria-expanded": expanded,
|
|
51
51
|
"aria-labelledby": `${id}-label ${id}-sep ${id}-value${activateLabel ? ` ${id}-action` : ""}`,
|
|
52
52
|
"aria-describedby": meta != null || trend != null ? `${id}-meta` : void 0,
|
|
53
|
+
...pending ? { "aria-busy": true, "aria-disabled": true } : null,
|
|
53
54
|
onClick: (e) => {
|
|
55
|
+
if (pending) return;
|
|
54
56
|
onClick?.(e);
|
|
55
57
|
if (!e.defaultPrevented) onActivate();
|
|
56
58
|
},
|
|
59
|
+
onKeyDown: pending ? void 0 : onKeyDown,
|
|
57
60
|
children: [
|
|
58
61
|
/* @__PURE__ */ jsx("span", { id: `${id}-sep`, className: "uix-visually-hidden", children: ":" }),
|
|
59
62
|
activateLabel && /* @__PURE__ */ jsxs("span", { id: `${id}-action`, className: "uix-visually-hidden", children: [
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { EChartsOption } from 'echarts';
|
|
2
|
+
import { UixChartTokens } from './chart-theme.js';
|
|
3
|
+
import { LinearFit } from './chart-stats.js';
|
|
4
|
+
import { ChartThreshold } from './chart-analytic-model.js';
|
|
5
|
+
|
|
6
|
+
interface CorrelationPoint {
|
|
7
|
+
x: number;
|
|
8
|
+
y: number;
|
|
9
|
+
label: string;
|
|
10
|
+
href?: string;
|
|
11
|
+
/** A point that matters (a breach): a status hue AND a distinct shape, never colour alone. */
|
|
12
|
+
emphasis?: 'danger' | 'warning';
|
|
13
|
+
}
|
|
14
|
+
interface CorrelationScatterLabels {
|
|
15
|
+
/** The stats caption. `r` is null when it is undefined (y constant). */
|
|
16
|
+
stats: (stats: {
|
|
17
|
+
r: number | null;
|
|
18
|
+
n: number;
|
|
19
|
+
}) => string;
|
|
20
|
+
notEnough: (n: number, min: number) => string;
|
|
21
|
+
percentile: (p: number) => string;
|
|
22
|
+
trend: string;
|
|
23
|
+
/** Header of the label column in the data table. */
|
|
24
|
+
point: string;
|
|
25
|
+
formatX: (x: number) => string;
|
|
26
|
+
formatY: (y: number) => string;
|
|
27
|
+
}
|
|
28
|
+
/** r to two decimals, truncated toward zero so an imperfect fit never reads "r = 1.00". */
|
|
29
|
+
declare function formatCorrelation(r: number): string;
|
|
30
|
+
declare const DEFAULT_CORRELATION_SCATTER_LABELS: CorrelationScatterLabels;
|
|
31
|
+
interface CorrelationScatterSpec {
|
|
32
|
+
points: CorrelationPoint[];
|
|
33
|
+
xLabel: string;
|
|
34
|
+
yLabel: string;
|
|
35
|
+
trend?: 'linear' | 'none';
|
|
36
|
+
/** Percentile lines of y, in percent (e.g. [50, 90]). */
|
|
37
|
+
percentiles?: number[];
|
|
38
|
+
thresholds?: {
|
|
39
|
+
x?: ChartThreshold[];
|
|
40
|
+
y?: ChartThreshold[];
|
|
41
|
+
};
|
|
42
|
+
breakpoint?: {
|
|
43
|
+
x: number;
|
|
44
|
+
label: string;
|
|
45
|
+
};
|
|
46
|
+
/** Below this many points there is no trend and no stats. Default 8. */
|
|
47
|
+
minPoints?: number;
|
|
48
|
+
}
|
|
49
|
+
interface CorrelationScatterModel {
|
|
50
|
+
/** False below `minPoints`: render the "not enough data" state instead of a trend. */
|
|
51
|
+
enough: boolean;
|
|
52
|
+
n: number;
|
|
53
|
+
minPoints: number;
|
|
54
|
+
fit: LinearFit | null;
|
|
55
|
+
option: EChartsOption;
|
|
56
|
+
statsText: string;
|
|
57
|
+
table: {
|
|
58
|
+
headers: string[];
|
|
59
|
+
rows: Record<string, string | number>[];
|
|
60
|
+
};
|
|
61
|
+
/** Index into `points` for each data item of the hit series. */
|
|
62
|
+
hitSeriesId: string;
|
|
63
|
+
}
|
|
64
|
+
/** Hit target for every point, in px: above the 24 px accessible minimum (WCAG 2.5.8) with the 2 px gap around it. */
|
|
65
|
+
declare const SCATTER_HIT_SIZE = 26;
|
|
66
|
+
declare function correlationScatterModel(spec: CorrelationScatterSpec, tokens: UixChartTokens, labelOverrides?: Partial<CorrelationScatterLabels>): CorrelationScatterModel;
|
|
67
|
+
|
|
68
|
+
export { type CorrelationPoint, type CorrelationScatterLabels, type CorrelationScatterModel, type CorrelationScatterSpec, DEFAULT_CORRELATION_SCATTER_LABELS, SCATTER_HIT_SIZE, correlationScatterModel, formatCorrelation };
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { linearFit, quantiles } from "./chart-stats.js";
|
|
2
|
+
import { combineMarks, thresholdMarks } from "./chart-analytic-model.js";
|
|
3
|
+
import { niceCeil } from "./chart-panels-model.js";
|
|
4
|
+
const defaultNumber = new Intl.NumberFormat("en", { maximumFractionDigits: 2 });
|
|
5
|
+
function formatCorrelation(r) {
|
|
6
|
+
const shown = Math.abs(r) < 1 ? Math.trunc(r * 100) / 100 : Math.sign(r);
|
|
7
|
+
return shown.toFixed(2);
|
|
8
|
+
}
|
|
9
|
+
const DEFAULT_CORRELATION_SCATTER_LABELS = {
|
|
10
|
+
stats: ({ r, n }) => `${r == null ? "" : `r = ${formatCorrelation(r)} \xB7 `}n = ${n} \xB7 association, not cause`,
|
|
11
|
+
notEnough: (n, min) => `Not enough data (n = ${n} of ${min})`,
|
|
12
|
+
percentile: (p) => `p${p}`,
|
|
13
|
+
trend: "Trend",
|
|
14
|
+
point: "Point",
|
|
15
|
+
formatX: (x) => defaultNumber.format(x),
|
|
16
|
+
formatY: (y) => defaultNumber.format(y)
|
|
17
|
+
};
|
|
18
|
+
const SCATTER_HIT_SIZE = 26;
|
|
19
|
+
const DOT_SIZE = 9;
|
|
20
|
+
const escapeHtml = (text) => text.replace(/[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[c] ?? c);
|
|
21
|
+
const niceRange = (values) => {
|
|
22
|
+
const lo = Math.min(...values);
|
|
23
|
+
const hi = Math.max(...values);
|
|
24
|
+
const max = niceCeil(hi > 0 ? hi * 1.08 : hi || 1);
|
|
25
|
+
const min = lo >= 0 ? 0 : -niceCeil(-lo * 1.08);
|
|
26
|
+
return [min, max];
|
|
27
|
+
};
|
|
28
|
+
function correlationScatterModel(spec, tokens, labelOverrides) {
|
|
29
|
+
const labels = { ...DEFAULT_CORRELATION_SCATTER_LABELS, ...labelOverrides };
|
|
30
|
+
const minPoints = Math.max(2, spec.minPoints ?? 8);
|
|
31
|
+
const points = spec.points.filter((p) => Number.isFinite(p.x) && Number.isFinite(p.y));
|
|
32
|
+
const n = points.length;
|
|
33
|
+
const enough = n >= minPoints;
|
|
34
|
+
const fit = enough && spec.trend !== "none" ? linearFit(points) : null;
|
|
35
|
+
const statsText = labels.stats({ r: fit?.r ?? null, n });
|
|
36
|
+
const xs = [...points.map((p) => p.x), ...(spec.thresholds?.x ?? []).map((t) => t.value), ...spec.breakpoint ? [spec.breakpoint.x] : []];
|
|
37
|
+
const ys = [...points.map((p) => p.y), ...(spec.thresholds?.y ?? []).map((t) => t.value)];
|
|
38
|
+
const [xMin, xMax] = xs.length ? niceRange(xs) : [0, 1];
|
|
39
|
+
const [yMin, yMax] = ys.length ? niceRange(ys) : [0, 1];
|
|
40
|
+
const dotData = points.map((p) => ({
|
|
41
|
+
value: [p.x, p.y],
|
|
42
|
+
symbol: p.emphasis === "danger" ? "diamond" : p.emphasis === "warning" ? "triangle" : "circle",
|
|
43
|
+
symbolSize: p.emphasis ? DOT_SIZE + 3 : DOT_SIZE,
|
|
44
|
+
itemStyle: {
|
|
45
|
+
color: p.emphasis === "danger" ? tokens.danger : p.emphasis === "warning" ? tokens.warning : tokens.palette[0],
|
|
46
|
+
borderColor: tokens.surface,
|
|
47
|
+
borderWidth: 2,
|
|
48
|
+
opacity: 1
|
|
49
|
+
}
|
|
50
|
+
}));
|
|
51
|
+
const pcts = (spec.percentiles ?? []).filter((p) => p > 0 && p < 100);
|
|
52
|
+
const pctValues = quantiles(points.map((p) => p.y), pcts.map((p) => p / 100));
|
|
53
|
+
const percentileLines = enough && pcts.length ? {
|
|
54
|
+
markLine: {
|
|
55
|
+
silent: true,
|
|
56
|
+
symbol: "none",
|
|
57
|
+
animation: false,
|
|
58
|
+
data: pcts.flatMap((p, i) => {
|
|
59
|
+
const value = pctValues[i];
|
|
60
|
+
return value == null ? [] : [{
|
|
61
|
+
yAxis: value,
|
|
62
|
+
lineStyle: { color: tokens.reference, width: 1, type: "solid", opacity: 0.6 },
|
|
63
|
+
label: { show: true, position: "end", formatter: labels.percentile(p), color: tokens.textMuted, fontFamily: tokens.fontSans, fontSize: 11, distance: 6 }
|
|
64
|
+
}];
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
} : {};
|
|
68
|
+
const xLines = {
|
|
69
|
+
markLine: {
|
|
70
|
+
silent: true,
|
|
71
|
+
symbol: "none",
|
|
72
|
+
animation: false,
|
|
73
|
+
data: [
|
|
74
|
+
...(spec.thresholds?.x ?? []).map((t) => ({
|
|
75
|
+
xAxis: t.value,
|
|
76
|
+
lineStyle: { color: tokens.reference, width: 1, type: "solid" },
|
|
77
|
+
label: { show: true, position: "end", formatter: t.label, color: tokens.textMuted, fontFamily: tokens.fontSans, fontSize: 11 }
|
|
78
|
+
})),
|
|
79
|
+
...spec.breakpoint && enough ? [{
|
|
80
|
+
xAxis: spec.breakpoint.x,
|
|
81
|
+
lineStyle: { color: tokens.text, width: 1, type: "solid" },
|
|
82
|
+
label: { show: true, position: "end", formatter: spec.breakpoint.label, color: tokens.text, fontFamily: tokens.fontSans, fontSize: 11, fontWeight: 600 }
|
|
83
|
+
}] : []
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
const marks = combineMarks(
|
|
88
|
+
spec.thresholds?.y?.length ? thresholdMarks(spec.thresholds.y, { tokens, extent: [yMin, yMax] }) : null,
|
|
89
|
+
percentileLines,
|
|
90
|
+
(xLines.markLine?.data).length ? xLines : null
|
|
91
|
+
);
|
|
92
|
+
const series = [
|
|
93
|
+
{
|
|
94
|
+
id: "points",
|
|
95
|
+
name: spec.yLabel,
|
|
96
|
+
type: "scatter",
|
|
97
|
+
data: dotData,
|
|
98
|
+
silent: true,
|
|
99
|
+
animation: false,
|
|
100
|
+
z: 3,
|
|
101
|
+
...marks
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
// the hit layer: transparent 24 px targets over the dots carry the tooltip and the click
|
|
105
|
+
id: "points-hit",
|
|
106
|
+
name: spec.yLabel,
|
|
107
|
+
type: "scatter",
|
|
108
|
+
data: points.map((p, index) => ({ value: [p.x, p.y, index] })),
|
|
109
|
+
symbol: "circle",
|
|
110
|
+
symbolSize: SCATTER_HIT_SIZE,
|
|
111
|
+
itemStyle: { color: "rgba(0,0,0,0)" },
|
|
112
|
+
emphasis: { itemStyle: { color: "rgba(0,0,0,0)", borderColor: tokens.text, borderWidth: 1 } },
|
|
113
|
+
cursor: "pointer",
|
|
114
|
+
animation: false,
|
|
115
|
+
z: 4
|
|
116
|
+
}
|
|
117
|
+
];
|
|
118
|
+
if (fit) {
|
|
119
|
+
series.push({
|
|
120
|
+
id: "trend",
|
|
121
|
+
name: labels.trend,
|
|
122
|
+
type: "line",
|
|
123
|
+
data: [[xMin, fit.intercept + fit.slope * xMin], [xMax, fit.intercept + fit.slope * xMax]],
|
|
124
|
+
symbol: "none",
|
|
125
|
+
silent: true,
|
|
126
|
+
lineStyle: { color: tokens.reference, width: 1.5, type: "solid" },
|
|
127
|
+
tooltip: { show: false },
|
|
128
|
+
animation: false,
|
|
129
|
+
clip: true,
|
|
130
|
+
z: 2
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
const option = {
|
|
134
|
+
animation: false,
|
|
135
|
+
grid: { top: 28, right: spec.thresholds?.y?.length || pcts.length ? 100 : 20, bottom: 44, left: 52, containLabel: false },
|
|
136
|
+
xAxis: {
|
|
137
|
+
type: "value",
|
|
138
|
+
min: xMin,
|
|
139
|
+
max: xMax,
|
|
140
|
+
name: spec.xLabel,
|
|
141
|
+
nameLocation: "middle",
|
|
142
|
+
nameGap: 28,
|
|
143
|
+
nameTextStyle: { color: tokens.textMuted, fontFamily: tokens.fontSans, fontSize: 12 },
|
|
144
|
+
axisLabel: { formatter: (v) => labels.formatX(v) },
|
|
145
|
+
splitLine: { show: true }
|
|
146
|
+
},
|
|
147
|
+
yAxis: {
|
|
148
|
+
type: "value",
|
|
149
|
+
min: yMin,
|
|
150
|
+
max: yMax,
|
|
151
|
+
name: spec.yLabel,
|
|
152
|
+
nameLocation: "end",
|
|
153
|
+
nameGap: 10,
|
|
154
|
+
nameTextStyle: { align: "left", padding: [0, 0, 0, -48], color: tokens.textMuted, fontFamily: tokens.fontSans, fontSize: 12 },
|
|
155
|
+
axisLabel: { formatter: (v) => labels.formatY(v) }
|
|
156
|
+
},
|
|
157
|
+
tooltip: {
|
|
158
|
+
trigger: "item",
|
|
159
|
+
confine: true,
|
|
160
|
+
formatter: (params) => {
|
|
161
|
+
const p = params;
|
|
162
|
+
if (p.seriesId !== "points-hit" || !Array.isArray(p.value)) return "";
|
|
163
|
+
const point = points[Number(p.value[2])];
|
|
164
|
+
if (!point) return "";
|
|
165
|
+
return `<div style="font-weight:600;margin-bottom:4px">${escapeHtml(point.label)}</div><div>${escapeHtml(spec.xLabel)}: ${escapeHtml(labels.formatX(point.x))}</div><div>${escapeHtml(spec.yLabel)}: ${escapeHtml(labels.formatY(point.y))}</div>`;
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
series
|
|
169
|
+
};
|
|
170
|
+
const headers = [labels.point, spec.xLabel, spec.yLabel];
|
|
171
|
+
const rows = points.map((p) => ({ [labels.point]: p.label, [spec.xLabel]: labels.formatX(p.x), [spec.yLabel]: labels.formatY(p.y) }));
|
|
172
|
+
return { enough, n, minPoints, fit, option, statsText, table: { headers, rows }, hitSeriesId: "points-hit" };
|
|
173
|
+
}
|
|
174
|
+
export {
|
|
175
|
+
DEFAULT_CORRELATION_SCATTER_LABELS,
|
|
176
|
+
SCATTER_HIT_SIZE,
|
|
177
|
+
correlationScatterModel,
|
|
178
|
+
formatCorrelation
|
|
179
|
+
};
|
package/dist/icons/Icon.d.ts
CHANGED
|
@@ -5,28 +5,41 @@ import { IconNode, UixIcon, IconProps } from './types.js';
|
|
|
5
5
|
/** Renders a glyph as an inline SVG; the props contract shared by every icon. */
|
|
6
6
|
declare function renderIcon(node: IconNode, { size, tone, label, strokeWidth, className, style, ...rest }: IconProps, ref?: unknown): react.ReactElement<{
|
|
7
7
|
string?: number | string | undefined | undefined;
|
|
8
|
+
target?: string | undefined | undefined;
|
|
8
9
|
filter?: string | undefined | undefined;
|
|
9
|
-
values?: string | undefined | undefined;
|
|
10
10
|
fill: string;
|
|
11
|
+
values?: string | undefined | undefined;
|
|
12
|
+
type?: string | undefined | undefined;
|
|
13
|
+
min?: number | string | undefined | undefined;
|
|
14
|
+
max?: number | string | undefined | undefined;
|
|
15
|
+
name?: string | undefined | undefined;
|
|
11
16
|
color?: string | undefined | undefined;
|
|
17
|
+
width?: number | string | undefined | undefined;
|
|
18
|
+
rotate?: number | string | undefined | undefined;
|
|
19
|
+
offset?: number | string | undefined | undefined;
|
|
20
|
+
overflow?: number | string | undefined | undefined;
|
|
12
21
|
fontStyle?: number | string | undefined | undefined;
|
|
13
22
|
fontWeight?: number | string | undefined | undefined;
|
|
14
|
-
fontSize?: number | string | undefined | undefined;
|
|
15
23
|
fontFamily?: string | undefined | undefined;
|
|
16
|
-
|
|
24
|
+
fontSize?: number | string | undefined | undefined;
|
|
25
|
+
opacity?: number | string | undefined | undefined;
|
|
17
26
|
height?: number | string | undefined | undefined;
|
|
18
|
-
|
|
27
|
+
end?: number | string | undefined | undefined;
|
|
28
|
+
scale?: number | string | undefined | undefined;
|
|
29
|
+
to?: number | string | undefined | undefined;
|
|
19
30
|
z?: number | string | undefined | undefined;
|
|
20
|
-
opacity?: number | string | undefined | undefined;
|
|
21
31
|
r?: number | string | undefined | undefined;
|
|
22
|
-
id?: string | undefined | undefined;
|
|
23
|
-
name?: string | undefined | undefined;
|
|
24
32
|
x?: number | string | undefined | undefined;
|
|
25
|
-
y?: number | string | undefined | undefined;
|
|
26
33
|
cursor?: number | string | undefined | undefined;
|
|
34
|
+
id?: string | undefined | undefined;
|
|
35
|
+
radius?: number | string | undefined | undefined;
|
|
36
|
+
from?: number | string | undefined | undefined;
|
|
37
|
+
y?: number | string | undefined | undefined;
|
|
38
|
+
slope?: number | string | undefined | undefined;
|
|
39
|
+
intercept?: number | string | undefined | undefined;
|
|
40
|
+
points?: string | undefined | undefined;
|
|
27
41
|
children?: react.ReactNode;
|
|
28
42
|
clipPath?: string | undefined | undefined;
|
|
29
|
-
radius?: number | string | undefined | undefined;
|
|
30
43
|
media?: string | undefined | undefined;
|
|
31
44
|
suppressHydrationWarning?: boolean | undefined | undefined;
|
|
32
45
|
lang?: string | undefined | undefined;
|
|
@@ -246,7 +259,6 @@ declare function renderIcon(node: IconNode, { size, tone, label, strokeWidth, cl
|
|
|
246
259
|
onAnimationIterationCapture?: react.AnimationEventHandler<SVGSVGElement> | undefined;
|
|
247
260
|
onTransitionEnd?: react.TransitionEventHandler<SVGSVGElement> | undefined;
|
|
248
261
|
onTransitionEndCapture?: react.TransitionEventHandler<SVGSVGElement> | undefined;
|
|
249
|
-
end?: number | string | undefined | undefined;
|
|
250
262
|
alphabetic?: number | string | undefined | undefined;
|
|
251
263
|
ideographic?: number | string | undefined | undefined;
|
|
252
264
|
mathematical?: number | string | undefined | undefined;
|
|
@@ -256,17 +268,14 @@ declare function renderIcon(node: IconNode, { size, tone, label, strokeWidth, cl
|
|
|
256
268
|
unicode?: number | string | undefined | undefined;
|
|
257
269
|
clip?: number | string | undefined | undefined;
|
|
258
270
|
stroke: string;
|
|
259
|
-
|
|
271
|
+
href?: string | undefined | undefined;
|
|
260
272
|
capHeight?: number | string | undefined | undefined;
|
|
261
273
|
dy?: number | string | undefined | undefined;
|
|
262
274
|
dx?: number | string | undefined | undefined;
|
|
263
275
|
transform?: string | undefined | undefined;
|
|
264
276
|
mask?: string | undefined | undefined;
|
|
265
277
|
path?: string | undefined | undefined;
|
|
266
|
-
max?: number | string | undefined | undefined;
|
|
267
278
|
method?: string | undefined | undefined;
|
|
268
|
-
min?: number | string | undefined | undefined;
|
|
269
|
-
target?: string | undefined | undefined;
|
|
270
279
|
crossOrigin?: "" | "anonymous" | "use-credentials" | undefined;
|
|
271
280
|
accentHeight?: number | string | undefined | undefined;
|
|
272
281
|
additive?: "replace" | "sum" | undefined | undefined;
|
|
@@ -323,7 +332,6 @@ declare function renderIcon(node: IconNode, { size, tone, label, strokeWidth, cl
|
|
|
323
332
|
fontVariant?: number | string | undefined | undefined;
|
|
324
333
|
format?: number | string | undefined | undefined;
|
|
325
334
|
fr?: number | string | undefined | undefined;
|
|
326
|
-
from?: number | string | undefined | undefined;
|
|
327
335
|
fx?: number | string | undefined | undefined;
|
|
328
336
|
fy?: number | string | undefined | undefined;
|
|
329
337
|
g1?: number | string | undefined | undefined;
|
|
@@ -336,11 +344,9 @@ declare function renderIcon(node: IconNode, { size, tone, label, strokeWidth, cl
|
|
|
336
344
|
gradientUnits?: string | undefined | undefined;
|
|
337
345
|
horizAdvX?: number | string | undefined | undefined;
|
|
338
346
|
horizOriginX?: number | string | undefined | undefined;
|
|
339
|
-
href?: string | undefined | undefined;
|
|
340
347
|
imageRendering?: number | string | undefined | undefined;
|
|
341
348
|
in2?: number | string | undefined | undefined;
|
|
342
349
|
in?: string | undefined | undefined;
|
|
343
|
-
intercept?: number | string | undefined | undefined;
|
|
344
350
|
k1?: number | string | undefined | undefined;
|
|
345
351
|
k2?: number | string | undefined | undefined;
|
|
346
352
|
k3?: number | string | undefined | undefined;
|
|
@@ -371,7 +377,6 @@ declare function renderIcon(node: IconNode, { size, tone, label, strokeWidth, cl
|
|
|
371
377
|
orient?: number | string | undefined | undefined;
|
|
372
378
|
orientation?: number | string | undefined | undefined;
|
|
373
379
|
origin?: number | string | undefined | undefined;
|
|
374
|
-
overflow?: number | string | undefined | undefined;
|
|
375
380
|
overlinePosition?: number | string | undefined | undefined;
|
|
376
381
|
overlineThickness?: number | string | undefined | undefined;
|
|
377
382
|
paintOrder?: number | string | undefined | undefined;
|
|
@@ -381,7 +386,6 @@ declare function renderIcon(node: IconNode, { size, tone, label, strokeWidth, cl
|
|
|
381
386
|
patternTransform?: number | string | undefined | undefined;
|
|
382
387
|
patternUnits?: string | undefined | undefined;
|
|
383
388
|
pointerEvents?: number | string | undefined | undefined;
|
|
384
|
-
points?: string | undefined | undefined;
|
|
385
389
|
pointsAtX?: number | string | undefined | undefined;
|
|
386
390
|
pointsAtY?: number | string | undefined | undefined;
|
|
387
391
|
pointsAtZ?: number | string | undefined | undefined;
|
|
@@ -397,13 +401,10 @@ declare function renderIcon(node: IconNode, { size, tone, label, strokeWidth, cl
|
|
|
397
401
|
requiredFeatures?: number | string | undefined | undefined;
|
|
398
402
|
restart?: number | string | undefined | undefined;
|
|
399
403
|
result?: string | undefined | undefined;
|
|
400
|
-
rotate?: number | string | undefined | undefined;
|
|
401
404
|
rx?: number | string | undefined | undefined;
|
|
402
405
|
ry?: number | string | undefined | undefined;
|
|
403
|
-
scale?: number | string | undefined | undefined;
|
|
404
406
|
seed?: number | string | undefined | undefined;
|
|
405
407
|
shapeRendering?: number | string | undefined | undefined;
|
|
406
|
-
slope?: number | string | undefined | undefined;
|
|
407
408
|
spacing?: number | string | undefined | undefined;
|
|
408
409
|
specularConstant?: number | string | undefined | undefined;
|
|
409
410
|
specularExponent?: number | string | undefined | undefined;
|
|
@@ -433,7 +434,6 @@ declare function renderIcon(node: IconNode, { size, tone, label, strokeWidth, cl
|
|
|
433
434
|
textDecoration?: number | string | undefined | undefined;
|
|
434
435
|
textLength?: number | string | undefined | undefined;
|
|
435
436
|
textRendering?: number | string | undefined | undefined;
|
|
436
|
-
to?: number | string | undefined | undefined;
|
|
437
437
|
transformOrigin?: string | undefined | undefined;
|
|
438
438
|
u1?: number | string | undefined | undefined;
|
|
439
439
|
u2?: number | string | undefined | undefined;
|