hazo_ui 3.4.1 → 4.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGE_LOG.md +44 -0
- package/README.md +106 -0
- package/SETUP_CHECKLIST.md +8 -1
- package/dist/index.cjs +279 -579
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +53 -63
- package/dist/index.d.ts +53 -63
- package/dist/index.js +276 -578
- package/dist/index.js.map +1 -1
- package/package.json +4 -8
package/dist/index.cjs
CHANGED
|
@@ -73,6 +73,7 @@ var ScrollAreaPrimitive = require('@radix-ui/react-scroll-area');
|
|
|
73
73
|
var TogglePrimitive = require('@radix-ui/react-toggle');
|
|
74
74
|
var ToggleGroupPrimitive = require('@radix-ui/react-toggle-group');
|
|
75
75
|
var AlertDialogPrimitive = require('@radix-ui/react-alert-dialog');
|
|
76
|
+
var SliderPrimitive = require('@radix-ui/react-slider');
|
|
76
77
|
var sonner = require('sonner');
|
|
77
78
|
var client$1 = require('hazo_state/client');
|
|
78
79
|
|
|
@@ -143,6 +144,7 @@ var ScrollAreaPrimitive__namespace = /*#__PURE__*/_interopNamespace(ScrollAreaPr
|
|
|
143
144
|
var TogglePrimitive__namespace = /*#__PURE__*/_interopNamespace(TogglePrimitive);
|
|
144
145
|
var ToggleGroupPrimitive__namespace = /*#__PURE__*/_interopNamespace(ToggleGroupPrimitive);
|
|
145
146
|
var AlertDialogPrimitive__namespace = /*#__PURE__*/_interopNamespace(AlertDialogPrimitive);
|
|
147
|
+
var SliderPrimitive__namespace = /*#__PURE__*/_interopNamespace(SliderPrimitive);
|
|
146
148
|
|
|
147
149
|
var __create = Object.create;
|
|
148
150
|
var __defProp = Object.defineProperty;
|
|
@@ -7458,6 +7460,51 @@ function ButtonGroupText({ className, asChild = false, ...props }) {
|
|
|
7458
7460
|
function ButtonGroupSeparator({ className, orientation = "vertical", ...props }) {
|
|
7459
7461
|
return /* @__PURE__ */ jsxRuntime.jsx(Separator3, { orientation, className: cn("bg-input relative !m-0 self-stretch data-[orientation=vertical]:h-auto", className), ...props });
|
|
7460
7462
|
}
|
|
7463
|
+
var Slider = React26__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7464
|
+
SliderPrimitive__namespace.Root,
|
|
7465
|
+
{
|
|
7466
|
+
ref,
|
|
7467
|
+
className: cn("relative flex w-full touch-none select-none items-center", className),
|
|
7468
|
+
...props,
|
|
7469
|
+
children: [
|
|
7470
|
+
/* @__PURE__ */ jsxRuntime.jsx(SliderPrimitive__namespace.Track, { className: "relative h-2 w-full grow overflow-hidden rounded-full bg-secondary", children: /* @__PURE__ */ jsxRuntime.jsx(SliderPrimitive__namespace.Range, { className: "absolute h-full bg-primary" }) }),
|
|
7471
|
+
/* @__PURE__ */ jsxRuntime.jsx(SliderPrimitive__namespace.Thumb, { className: "block h-5 w-5 rounded-full border-2 border-primary bg-background ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50" })
|
|
7472
|
+
]
|
|
7473
|
+
}
|
|
7474
|
+
));
|
|
7475
|
+
Slider.displayName = SliderPrimitive__namespace.Root.displayName;
|
|
7476
|
+
var InputAffix = React26__namespace.forwardRef(
|
|
7477
|
+
({ className, containerClassName, prefix, suffix, type = "text", ...props }, ref) => {
|
|
7478
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7479
|
+
"div",
|
|
7480
|
+
{
|
|
7481
|
+
className: cn(
|
|
7482
|
+
"flex h-10 w-full items-center rounded-md border border-input bg-background text-sm ring-offset-background focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2",
|
|
7483
|
+
containerClassName
|
|
7484
|
+
),
|
|
7485
|
+
children: [
|
|
7486
|
+
prefix != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex select-none items-center pl-3 text-muted-foreground", children: prefix }),
|
|
7487
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7488
|
+
"input",
|
|
7489
|
+
{
|
|
7490
|
+
type,
|
|
7491
|
+
ref,
|
|
7492
|
+
className: cn(
|
|
7493
|
+
"h-full w-full bg-transparent px-3 py-2 outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
|
|
7494
|
+
prefix != null && "pl-2",
|
|
7495
|
+
suffix != null && "pr-2",
|
|
7496
|
+
className
|
|
7497
|
+
),
|
|
7498
|
+
...props
|
|
7499
|
+
}
|
|
7500
|
+
),
|
|
7501
|
+
suffix != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex select-none items-center pr-3 text-muted-foreground", children: suffix })
|
|
7502
|
+
]
|
|
7503
|
+
}
|
|
7504
|
+
);
|
|
7505
|
+
}
|
|
7506
|
+
);
|
|
7507
|
+
InputAffix.displayName = "InputAffix";
|
|
7461
7508
|
var SkeletonBase = React26__namespace.forwardRef(
|
|
7462
7509
|
({ className, ...rest }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
7463
7510
|
"div",
|
|
@@ -9736,573 +9783,12 @@ function pick_x_label_indices(length) {
|
|
|
9736
9783
|
if (length === 2) return [0, 0, 1];
|
|
9737
9784
|
return [0, Math.floor(length / 2), length - 1];
|
|
9738
9785
|
}
|
|
9739
|
-
var PAD_LEFT =
|
|
9740
|
-
var PAD_RIGHT =
|
|
9741
|
-
var PAD_TOP =
|
|
9786
|
+
var PAD_LEFT = 32;
|
|
9787
|
+
var PAD_RIGHT = 8;
|
|
9788
|
+
var PAD_TOP = 10;
|
|
9742
9789
|
var PAD_BOTTOM = 22;
|
|
9743
|
-
var AXIS_LABEL_COLOR = "#8b949e";
|
|
9744
|
-
var GRIDLINE_COLOR = "#2a3441";
|
|
9745
|
-
function compute_geometry(data, width, height) {
|
|
9746
|
-
const vals = data.filter((v) => v !== null && !Number.isNaN(v));
|
|
9747
|
-
if (vals.length === 0) return null;
|
|
9748
|
-
const mn = Math.min(...vals);
|
|
9749
|
-
const mx = Math.max(...vals);
|
|
9750
|
-
const rng = mx - mn || mx * 0.1 + 1;
|
|
9751
|
-
const y_min = Math.max(0, mn - rng * 0.1);
|
|
9752
|
-
const y_max = mx + rng * 0.1;
|
|
9753
|
-
const y_rng = y_max - y_min || 1;
|
|
9754
|
-
const plot_w = width - PAD_LEFT - PAD_RIGHT;
|
|
9755
|
-
const plot_h = height - PAD_TOP - PAD_BOTTOM;
|
|
9756
|
-
return {
|
|
9757
|
-
vbox_w: width,
|
|
9758
|
-
vbox_h: height,
|
|
9759
|
-
y_min,
|
|
9760
|
-
y_max,
|
|
9761
|
-
cx: (i) => data.length <= 1 ? PAD_LEFT + plot_w / 2 : PAD_LEFT + i * plot_w / (data.length - 1),
|
|
9762
|
-
cy: (v) => PAD_TOP + (1 - (v - y_min) / y_rng) * plot_h
|
|
9763
|
-
};
|
|
9764
|
-
}
|
|
9765
|
-
function build_paths(data, g) {
|
|
9766
|
-
let line_d = "";
|
|
9767
|
-
let first_idx = -1;
|
|
9768
|
-
data.forEach((v, i) => {
|
|
9769
|
-
if (v === null || Number.isNaN(v)) return;
|
|
9770
|
-
if (first_idx === -1) first_idx = i;
|
|
9771
|
-
line_d += `${line_d ? " L" : "M"}${g.cx(i).toFixed(1)},${g.cy(v).toFixed(1)}`;
|
|
9772
|
-
});
|
|
9773
|
-
const last_idx = data.length - 1;
|
|
9774
|
-
const last_v = data[last_idx];
|
|
9775
|
-
const area_d = line_d && last_v !== null && last_v !== void 0 && !Number.isNaN(last_v) ? `${line_d} L${g.cx(last_idx).toFixed(1)},${g.vbox_h - PAD_BOTTOM} L${g.cx(first_idx).toFixed(1)},${g.vbox_h - PAD_BOTTOM} Z` : "";
|
|
9776
|
-
return { line_d, area_d };
|
|
9777
|
-
}
|
|
9778
|
-
function LineChart({
|
|
9779
|
-
data,
|
|
9780
|
-
dates,
|
|
9781
|
-
color: color2,
|
|
9782
|
-
width = 360,
|
|
9783
|
-
height = 130,
|
|
9784
|
-
unit = "",
|
|
9785
|
-
showTooltip = true,
|
|
9786
|
-
className
|
|
9787
|
-
}) {
|
|
9788
|
-
const geo = compute_geometry(data, width, height);
|
|
9789
|
-
const svg_ref = React26__namespace.useRef(null);
|
|
9790
|
-
const [hover_idx, set_hover_idx] = React26__namespace.useState(null);
|
|
9791
|
-
const handle_mouse_move = React26__namespace.useCallback(
|
|
9792
|
-
(e) => {
|
|
9793
|
-
if (!geo) return;
|
|
9794
|
-
const rect = e.currentTarget.getBoundingClientRect();
|
|
9795
|
-
if (rect.width === 0) return;
|
|
9796
|
-
const vbox_x = (e.clientX - rect.left) / rect.width * geo.vbox_w;
|
|
9797
|
-
const plot_w = geo.vbox_w - PAD_LEFT - PAD_RIGHT;
|
|
9798
|
-
if (vbox_x < PAD_LEFT || vbox_x > geo.vbox_w - PAD_RIGHT) {
|
|
9799
|
-
set_hover_idx(null);
|
|
9800
|
-
return;
|
|
9801
|
-
}
|
|
9802
|
-
const ratio = (vbox_x - PAD_LEFT) / plot_w;
|
|
9803
|
-
const idx = Math.round(ratio * (data.length - 1));
|
|
9804
|
-
const clamped = Math.max(0, Math.min(data.length - 1, idx));
|
|
9805
|
-
let resolved = clamped;
|
|
9806
|
-
if (data[resolved] === null || Number.isNaN(data[resolved])) {
|
|
9807
|
-
for (let step = 1; step < data.length; step += 1) {
|
|
9808
|
-
const left_i = clamped - step;
|
|
9809
|
-
const right_i = clamped + step;
|
|
9810
|
-
if (left_i >= 0 && data[left_i] !== null && !Number.isNaN(data[left_i])) {
|
|
9811
|
-
resolved = left_i;
|
|
9812
|
-
break;
|
|
9813
|
-
}
|
|
9814
|
-
if (right_i < data.length && data[right_i] !== null && !Number.isNaN(data[right_i])) {
|
|
9815
|
-
resolved = right_i;
|
|
9816
|
-
break;
|
|
9817
|
-
}
|
|
9818
|
-
}
|
|
9819
|
-
}
|
|
9820
|
-
set_hover_idx(resolved);
|
|
9821
|
-
},
|
|
9822
|
-
[geo, data]
|
|
9823
|
-
);
|
|
9824
|
-
const handle_mouse_leave = React26__namespace.useCallback(() => set_hover_idx(null), []);
|
|
9825
|
-
if (!geo) {
|
|
9826
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
9827
|
-
"svg",
|
|
9828
|
-
{
|
|
9829
|
-
viewBox: `0 0 ${width} ${height}`,
|
|
9830
|
-
className: cn("cls_hazo_chart cls_hazo_chart_empty", className),
|
|
9831
|
-
style: { width: "100%", height: "auto", display: "block", maxHeight: `${height + 10}px` }
|
|
9832
|
-
}
|
|
9833
|
-
);
|
|
9834
|
-
}
|
|
9835
|
-
const { line_d, area_d } = build_paths(data, geo);
|
|
9836
|
-
const x_label_idx = pick_x_label_indices(data.length);
|
|
9837
|
-
const last_idx = data.length - 1;
|
|
9838
|
-
const last_v = data[last_idx];
|
|
9839
|
-
const has_last = last_v !== null && last_v !== void 0 && !Number.isNaN(last_v);
|
|
9840
|
-
const hover_v = hover_idx !== null ? data[hover_idx] : null;
|
|
9841
|
-
const hover_has_v = hover_v !== null && hover_v !== void 0 && !Number.isNaN(hover_v);
|
|
9842
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
9843
|
-
"svg",
|
|
9844
|
-
{
|
|
9845
|
-
ref: svg_ref,
|
|
9846
|
-
viewBox: `0 0 ${width} ${height}`,
|
|
9847
|
-
onMouseMove: showTooltip ? handle_mouse_move : void 0,
|
|
9848
|
-
onMouseLeave: showTooltip ? handle_mouse_leave : void 0,
|
|
9849
|
-
className: cn("cls_hazo_chart", className),
|
|
9850
|
-
style: {
|
|
9851
|
-
width: "100%",
|
|
9852
|
-
height: "auto",
|
|
9853
|
-
display: "block",
|
|
9854
|
-
maxHeight: `${height + 10}px`,
|
|
9855
|
-
cursor: showTooltip ? "crosshair" : "default"
|
|
9856
|
-
},
|
|
9857
|
-
children: [
|
|
9858
|
-
[0, 1, 2].map((i) => {
|
|
9859
|
-
const y = PAD_TOP + i / 2 * (geo.vbox_h - PAD_TOP - PAD_BOTTOM);
|
|
9860
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
9861
|
-
"line",
|
|
9862
|
-
{
|
|
9863
|
-
x1: PAD_LEFT,
|
|
9864
|
-
x2: geo.vbox_w - PAD_RIGHT,
|
|
9865
|
-
y1: y,
|
|
9866
|
-
y2: y,
|
|
9867
|
-
stroke: GRIDLINE_COLOR,
|
|
9868
|
-
strokeWidth: 0.5,
|
|
9869
|
-
strokeDasharray: "2,3"
|
|
9870
|
-
},
|
|
9871
|
-
i
|
|
9872
|
-
);
|
|
9873
|
-
}),
|
|
9874
|
-
area_d && /* @__PURE__ */ jsxRuntime.jsx("path", { d: area_d, fill: color2, fillOpacity: 0.12, stroke: "none" }),
|
|
9875
|
-
line_d && /* @__PURE__ */ jsxRuntime.jsx("path", { d: line_d, stroke: color2, strokeWidth: 1.8, fill: "none" }),
|
|
9876
|
-
/* @__PURE__ */ jsxRuntime.jsx("text", { x: PAD_LEFT - 4, y: PAD_TOP + 3, textAnchor: "end", fill: AXIS_LABEL_COLOR, fontSize: 9, children: format_num(geo.y_max) }),
|
|
9877
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9878
|
-
"text",
|
|
9879
|
-
{
|
|
9880
|
-
x: PAD_LEFT - 4,
|
|
9881
|
-
y: PAD_TOP + (geo.vbox_h - PAD_TOP - PAD_BOTTOM) / 2 + 3,
|
|
9882
|
-
textAnchor: "end",
|
|
9883
|
-
fill: AXIS_LABEL_COLOR,
|
|
9884
|
-
fontSize: 9,
|
|
9885
|
-
children: format_num((geo.y_max + geo.y_min) / 2)
|
|
9886
|
-
}
|
|
9887
|
-
),
|
|
9888
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9889
|
-
"text",
|
|
9890
|
-
{
|
|
9891
|
-
x: PAD_LEFT - 4,
|
|
9892
|
-
y: geo.vbox_h - PAD_BOTTOM + 3,
|
|
9893
|
-
textAnchor: "end",
|
|
9894
|
-
fill: AXIS_LABEL_COLOR,
|
|
9895
|
-
fontSize: 9,
|
|
9896
|
-
children: format_num(geo.y_min)
|
|
9897
|
-
}
|
|
9898
|
-
),
|
|
9899
|
-
x_label_idx.map((idx, k) => {
|
|
9900
|
-
const anchor = k === 0 ? "start" : k === 1 ? "middle" : "end";
|
|
9901
|
-
const x_pos = geo.cx(idx);
|
|
9902
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
9903
|
-
"text",
|
|
9904
|
-
{
|
|
9905
|
-
x: x_pos,
|
|
9906
|
-
y: geo.vbox_h - 6,
|
|
9907
|
-
textAnchor: anchor,
|
|
9908
|
-
fill: AXIS_LABEL_COLOR,
|
|
9909
|
-
fontSize: 9,
|
|
9910
|
-
children: dates[idx] ?? ""
|
|
9911
|
-
},
|
|
9912
|
-
`x_${k}`
|
|
9913
|
-
);
|
|
9914
|
-
}),
|
|
9915
|
-
has_last && hover_idx === null && (() => {
|
|
9916
|
-
const x = geo.cx(last_idx);
|
|
9917
|
-
const y = geo.cy(last_v);
|
|
9918
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
9919
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9920
|
-
"line",
|
|
9921
|
-
{
|
|
9922
|
-
x1: x,
|
|
9923
|
-
x2: PAD_LEFT,
|
|
9924
|
-
y1: y,
|
|
9925
|
-
y2: y,
|
|
9926
|
-
stroke: color2,
|
|
9927
|
-
strokeWidth: 0.5,
|
|
9928
|
-
strokeDasharray: "2,2",
|
|
9929
|
-
opacity: 0.4
|
|
9930
|
-
}
|
|
9931
|
-
),
|
|
9932
|
-
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: x, cy: y, r: 3.5, fill: color2, stroke: color2, strokeWidth: 2, fillOpacity: 0.3 }),
|
|
9933
|
-
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: x, cy: y, r: 2, fill: color2 }),
|
|
9934
|
-
/* @__PURE__ */ jsxRuntime.jsxs("text", { x: x - 6, y: y - 6, textAnchor: "end", fill: color2, fontSize: 10, fontWeight: 700, children: [
|
|
9935
|
-
format_num(last_v),
|
|
9936
|
-
unit
|
|
9937
|
-
] })
|
|
9938
|
-
] });
|
|
9939
|
-
})(),
|
|
9940
|
-
showTooltip && hover_idx !== null && hover_has_v && (() => {
|
|
9941
|
-
const x = geo.cx(hover_idx);
|
|
9942
|
-
const y = geo.cy(hover_v);
|
|
9943
|
-
const label = `${format_num(hover_v)}${unit}`;
|
|
9944
|
-
const date = dates[hover_idx] ?? "";
|
|
9945
|
-
const bubble_text_w = Math.max(label.length, date.length) * 5.5 + 12;
|
|
9946
|
-
const bubble_w = Math.max(bubble_text_w, 40);
|
|
9947
|
-
const bubble_h = 26;
|
|
9948
|
-
const flip = x + bubble_w + 6 > geo.vbox_w - PAD_RIGHT;
|
|
9949
|
-
const bubble_x = flip ? x - bubble_w - 6 : x + 6;
|
|
9950
|
-
const bubble_y = Math.max(PAD_TOP, Math.min(y - bubble_h / 2, geo.vbox_h - PAD_BOTTOM - bubble_h));
|
|
9951
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
9952
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9953
|
-
"line",
|
|
9954
|
-
{
|
|
9955
|
-
x1: x,
|
|
9956
|
-
x2: x,
|
|
9957
|
-
y1: PAD_TOP,
|
|
9958
|
-
y2: geo.vbox_h - PAD_BOTTOM,
|
|
9959
|
-
stroke: color2,
|
|
9960
|
-
strokeWidth: 0.5,
|
|
9961
|
-
strokeDasharray: "2,2",
|
|
9962
|
-
opacity: 0.6
|
|
9963
|
-
}
|
|
9964
|
-
),
|
|
9965
|
-
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: x, cy: y, r: 3, fill: color2 }),
|
|
9966
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9967
|
-
"rect",
|
|
9968
|
-
{
|
|
9969
|
-
x: bubble_x,
|
|
9970
|
-
y: bubble_y,
|
|
9971
|
-
width: bubble_w,
|
|
9972
|
-
height: bubble_h,
|
|
9973
|
-
rx: 3,
|
|
9974
|
-
fill: "#0d1117",
|
|
9975
|
-
stroke: color2,
|
|
9976
|
-
strokeWidth: 0.5,
|
|
9977
|
-
fillOpacity: 0.92
|
|
9978
|
-
}
|
|
9979
|
-
),
|
|
9980
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9981
|
-
"text",
|
|
9982
|
-
{
|
|
9983
|
-
x: bubble_x + bubble_w / 2,
|
|
9984
|
-
y: bubble_y + 11,
|
|
9985
|
-
textAnchor: "middle",
|
|
9986
|
-
fill: color2,
|
|
9987
|
-
fontSize: 10,
|
|
9988
|
-
fontWeight: 700,
|
|
9989
|
-
children: label
|
|
9990
|
-
}
|
|
9991
|
-
),
|
|
9992
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9993
|
-
"text",
|
|
9994
|
-
{
|
|
9995
|
-
x: bubble_x + bubble_w / 2,
|
|
9996
|
-
y: bubble_y + 22,
|
|
9997
|
-
textAnchor: "middle",
|
|
9998
|
-
fill: AXIS_LABEL_COLOR,
|
|
9999
|
-
fontSize: 8,
|
|
10000
|
-
children: date
|
|
10001
|
-
}
|
|
10002
|
-
)
|
|
10003
|
-
] });
|
|
10004
|
-
})()
|
|
10005
|
-
]
|
|
10006
|
-
}
|
|
10007
|
-
);
|
|
10008
|
-
}
|
|
10009
|
-
var PAD_LEFT2 = 38;
|
|
10010
|
-
var PAD_RIGHT2 = 14;
|
|
10011
|
-
var PAD_TOP2 = 12;
|
|
10012
|
-
var PAD_BOTTOM2 = 22;
|
|
10013
|
-
var AXIS_LABEL_COLOR2 = "#8b949e";
|
|
10014
|
-
var GRIDLINE_COLOR2 = "#2a3441";
|
|
10015
|
-
function compute_geometry2(series, width, height) {
|
|
10016
|
-
const all_vals = [];
|
|
10017
|
-
let n = 0;
|
|
10018
|
-
for (const s of series) {
|
|
10019
|
-
n = Math.max(n, s.data.length);
|
|
10020
|
-
for (const v of s.data) if (v !== null && !Number.isNaN(v)) all_vals.push(v);
|
|
10021
|
-
}
|
|
10022
|
-
if (all_vals.length === 0 || n === 0) return null;
|
|
10023
|
-
const mn = Math.min(...all_vals);
|
|
10024
|
-
const mx = Math.max(...all_vals);
|
|
10025
|
-
const rng = mx - mn || mx * 0.1 + 1;
|
|
10026
|
-
const y_min = Math.max(0, mn - rng * 0.05);
|
|
10027
|
-
const y_max = mx + rng * 0.05;
|
|
10028
|
-
const y_rng = y_max - y_min || 1;
|
|
10029
|
-
const plot_w = width - PAD_LEFT2 - PAD_RIGHT2;
|
|
10030
|
-
const plot_h = height - PAD_TOP2 - PAD_BOTTOM2;
|
|
10031
|
-
return {
|
|
10032
|
-
vbox_w: width,
|
|
10033
|
-
vbox_h: height,
|
|
10034
|
-
y_min,
|
|
10035
|
-
y_max,
|
|
10036
|
-
point_count: n,
|
|
10037
|
-
cx: (i) => n <= 1 ? PAD_LEFT2 + plot_w / 2 : PAD_LEFT2 + i * plot_w / (n - 1),
|
|
10038
|
-
cy: (v) => PAD_TOP2 + (1 - (v - y_min) / y_rng) * plot_h
|
|
10039
|
-
};
|
|
10040
|
-
}
|
|
10041
|
-
function MultiLineChart({
|
|
10042
|
-
series,
|
|
10043
|
-
dates,
|
|
10044
|
-
width = 360,
|
|
10045
|
-
height = 140,
|
|
10046
|
-
showTooltip = true,
|
|
10047
|
-
showLegend = true,
|
|
10048
|
-
className
|
|
10049
|
-
}) {
|
|
10050
|
-
const geo = compute_geometry2(series, width, height);
|
|
10051
|
-
const [hover_idx, set_hover_idx] = React26__namespace.useState(null);
|
|
10052
|
-
const handle_mouse_move = React26__namespace.useCallback(
|
|
10053
|
-
(e) => {
|
|
10054
|
-
if (!geo) return;
|
|
10055
|
-
const rect = e.currentTarget.getBoundingClientRect();
|
|
10056
|
-
if (rect.width === 0) return;
|
|
10057
|
-
const vbox_x = (e.clientX - rect.left) / rect.width * geo.vbox_w;
|
|
10058
|
-
const plot_w = geo.vbox_w - PAD_LEFT2 - PAD_RIGHT2;
|
|
10059
|
-
if (vbox_x < PAD_LEFT2 || vbox_x > geo.vbox_w - PAD_RIGHT2) {
|
|
10060
|
-
set_hover_idx(null);
|
|
10061
|
-
return;
|
|
10062
|
-
}
|
|
10063
|
-
const ratio = (vbox_x - PAD_LEFT2) / plot_w;
|
|
10064
|
-
const idx = Math.round(ratio * (geo.point_count - 1));
|
|
10065
|
-
set_hover_idx(Math.max(0, Math.min(geo.point_count - 1, idx)));
|
|
10066
|
-
},
|
|
10067
|
-
[geo]
|
|
10068
|
-
);
|
|
10069
|
-
const handle_mouse_leave = React26__namespace.useCallback(() => set_hover_idx(null), []);
|
|
10070
|
-
if (!geo) {
|
|
10071
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
10072
|
-
"svg",
|
|
10073
|
-
{
|
|
10074
|
-
viewBox: `0 0 ${width} ${height}`,
|
|
10075
|
-
className: cn("cls_hazo_chart cls_hazo_chart_empty", className),
|
|
10076
|
-
style: { width: "100%", height: "auto", display: "block", maxHeight: `${height + 10}px` }
|
|
10077
|
-
}
|
|
10078
|
-
);
|
|
10079
|
-
}
|
|
10080
|
-
const x_label_idx = pick_x_label_indices(geo.point_count);
|
|
10081
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("cls_hazo_chart_wrapper", className), children: [
|
|
10082
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
10083
|
-
"svg",
|
|
10084
|
-
{
|
|
10085
|
-
viewBox: `0 0 ${width} ${height}`,
|
|
10086
|
-
onMouseMove: showTooltip ? handle_mouse_move : void 0,
|
|
10087
|
-
onMouseLeave: showTooltip ? handle_mouse_leave : void 0,
|
|
10088
|
-
className: "cls_hazo_chart cls_hazo_chart_multi",
|
|
10089
|
-
style: {
|
|
10090
|
-
width: "100%",
|
|
10091
|
-
height: "auto",
|
|
10092
|
-
display: "block",
|
|
10093
|
-
maxHeight: `${height + 10}px`,
|
|
10094
|
-
cursor: showTooltip ? "crosshair" : "default"
|
|
10095
|
-
},
|
|
10096
|
-
children: [
|
|
10097
|
-
[0, 1, 2].map((i) => {
|
|
10098
|
-
const y = PAD_TOP2 + i / 2 * (geo.vbox_h - PAD_TOP2 - PAD_BOTTOM2);
|
|
10099
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
10100
|
-
"line",
|
|
10101
|
-
{
|
|
10102
|
-
x1: PAD_LEFT2,
|
|
10103
|
-
x2: geo.vbox_w - PAD_RIGHT2,
|
|
10104
|
-
y1: y,
|
|
10105
|
-
y2: y,
|
|
10106
|
-
stroke: GRIDLINE_COLOR2,
|
|
10107
|
-
strokeWidth: 0.5,
|
|
10108
|
-
strokeDasharray: "2,3"
|
|
10109
|
-
},
|
|
10110
|
-
i
|
|
10111
|
-
);
|
|
10112
|
-
}),
|
|
10113
|
-
/* @__PURE__ */ jsxRuntime.jsx("text", { x: PAD_LEFT2 - 4, y: PAD_TOP2 + 3, textAnchor: "end", fill: AXIS_LABEL_COLOR2, fontSize: 9, children: format_num(geo.y_max) }),
|
|
10114
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10115
|
-
"text",
|
|
10116
|
-
{
|
|
10117
|
-
x: PAD_LEFT2 - 4,
|
|
10118
|
-
y: PAD_TOP2 + (geo.vbox_h - PAD_TOP2 - PAD_BOTTOM2) / 2 + 3,
|
|
10119
|
-
textAnchor: "end",
|
|
10120
|
-
fill: AXIS_LABEL_COLOR2,
|
|
10121
|
-
fontSize: 9,
|
|
10122
|
-
children: format_num((geo.y_max + geo.y_min) / 2)
|
|
10123
|
-
}
|
|
10124
|
-
),
|
|
10125
|
-
/* @__PURE__ */ jsxRuntime.jsx("text", { x: PAD_LEFT2 - 4, y: geo.vbox_h - PAD_BOTTOM2 + 3, textAnchor: "end", fill: AXIS_LABEL_COLOR2, fontSize: 9, children: format_num(geo.y_min) }),
|
|
10126
|
-
x_label_idx.map((idx, k) => {
|
|
10127
|
-
const anchor = k === 0 ? "start" : k === 1 ? "middle" : "end";
|
|
10128
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
10129
|
-
"text",
|
|
10130
|
-
{
|
|
10131
|
-
x: geo.cx(idx),
|
|
10132
|
-
y: geo.vbox_h - 6,
|
|
10133
|
-
textAnchor: anchor,
|
|
10134
|
-
fill: AXIS_LABEL_COLOR2,
|
|
10135
|
-
fontSize: 9,
|
|
10136
|
-
children: dates[idx] ?? ""
|
|
10137
|
-
},
|
|
10138
|
-
`x_${k}`
|
|
10139
|
-
);
|
|
10140
|
-
}),
|
|
10141
|
-
series.map((s, s_idx) => {
|
|
10142
|
-
let d = "";
|
|
10143
|
-
s.data.forEach((v, i) => {
|
|
10144
|
-
if (v === null || Number.isNaN(v)) return;
|
|
10145
|
-
d += `${d ? " L" : "M"}${geo.cx(i).toFixed(1)},${geo.cy(v).toFixed(1)}`;
|
|
10146
|
-
});
|
|
10147
|
-
const last_idx = s.data.length - 1;
|
|
10148
|
-
const last_v = s.data[last_idx];
|
|
10149
|
-
const has_last = last_v !== null && last_v !== void 0 && !Number.isNaN(last_v);
|
|
10150
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
|
|
10151
|
-
d && /* @__PURE__ */ jsxRuntime.jsx("path", { d, stroke: s.color, strokeWidth: 1.7, fill: "none" }),
|
|
10152
|
-
has_last && hover_idx === null && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
10153
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10154
|
-
"circle",
|
|
10155
|
-
{
|
|
10156
|
-
cx: geo.cx(last_idx),
|
|
10157
|
-
cy: geo.cy(last_v),
|
|
10158
|
-
r: 3,
|
|
10159
|
-
fill: s.color,
|
|
10160
|
-
fillOpacity: 0.3,
|
|
10161
|
-
stroke: s.color,
|
|
10162
|
-
strokeWidth: 1.5
|
|
10163
|
-
}
|
|
10164
|
-
),
|
|
10165
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10166
|
-
"text",
|
|
10167
|
-
{
|
|
10168
|
-
x: geo.cx(last_idx) - 5,
|
|
10169
|
-
y: geo.cy(last_v) - 5,
|
|
10170
|
-
textAnchor: "end",
|
|
10171
|
-
fill: s.color,
|
|
10172
|
-
fontSize: 9,
|
|
10173
|
-
fontWeight: 700,
|
|
10174
|
-
children: format_num(last_v)
|
|
10175
|
-
}
|
|
10176
|
-
)
|
|
10177
|
-
] })
|
|
10178
|
-
] }, `series_${s_idx}`);
|
|
10179
|
-
}),
|
|
10180
|
-
showTooltip && hover_idx !== null && (() => {
|
|
10181
|
-
const x = geo.cx(hover_idx);
|
|
10182
|
-
const items = series.map((s) => ({
|
|
10183
|
-
label: s.label,
|
|
10184
|
-
color: s.color,
|
|
10185
|
-
value: s.data[hover_idx] ?? null
|
|
10186
|
-
})).filter((it) => it.value !== null && !Number.isNaN(it.value));
|
|
10187
|
-
if (items.length === 0) return null;
|
|
10188
|
-
const bubble_w = 70;
|
|
10189
|
-
const row_h = 12;
|
|
10190
|
-
const bubble_h = items.length * row_h + 18;
|
|
10191
|
-
const flip = x + bubble_w + 6 > geo.vbox_w - PAD_RIGHT2;
|
|
10192
|
-
const bubble_x = flip ? x - bubble_w - 6 : x + 6;
|
|
10193
|
-
const bubble_y = Math.max(PAD_TOP2, Math.min(PAD_TOP2 + 5, geo.vbox_h - PAD_BOTTOM2 - bubble_h));
|
|
10194
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
10195
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10196
|
-
"line",
|
|
10197
|
-
{
|
|
10198
|
-
x1: x,
|
|
10199
|
-
x2: x,
|
|
10200
|
-
y1: PAD_TOP2,
|
|
10201
|
-
y2: geo.vbox_h - PAD_BOTTOM2,
|
|
10202
|
-
stroke: AXIS_LABEL_COLOR2,
|
|
10203
|
-
strokeWidth: 0.5,
|
|
10204
|
-
strokeDasharray: "2,2",
|
|
10205
|
-
opacity: 0.6
|
|
10206
|
-
}
|
|
10207
|
-
),
|
|
10208
|
-
items.map((it) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
10209
|
-
"circle",
|
|
10210
|
-
{
|
|
10211
|
-
cx: x,
|
|
10212
|
-
cy: geo.cy(it.value),
|
|
10213
|
-
r: 3,
|
|
10214
|
-
fill: it.color
|
|
10215
|
-
},
|
|
10216
|
-
`hd_${it.label}`
|
|
10217
|
-
)),
|
|
10218
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10219
|
-
"rect",
|
|
10220
|
-
{
|
|
10221
|
-
x: bubble_x,
|
|
10222
|
-
y: bubble_y,
|
|
10223
|
-
width: bubble_w,
|
|
10224
|
-
height: bubble_h,
|
|
10225
|
-
rx: 3,
|
|
10226
|
-
fill: "#0d1117",
|
|
10227
|
-
stroke: AXIS_LABEL_COLOR2,
|
|
10228
|
-
strokeWidth: 0.5,
|
|
10229
|
-
fillOpacity: 0.92
|
|
10230
|
-
}
|
|
10231
|
-
),
|
|
10232
|
-
/* @__PURE__ */ jsxRuntime.jsx("text", { x: bubble_x + 6, y: bubble_y + 10, fill: AXIS_LABEL_COLOR2, fontSize: 8, children: dates[hover_idx] ?? "" }),
|
|
10233
|
-
items.map((it, i) => /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
|
|
10234
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10235
|
-
"rect",
|
|
10236
|
-
{
|
|
10237
|
-
x: bubble_x + 6,
|
|
10238
|
-
y: bubble_y + 14 + i * row_h,
|
|
10239
|
-
width: 6,
|
|
10240
|
-
height: 6,
|
|
10241
|
-
fill: it.color
|
|
10242
|
-
}
|
|
10243
|
-
),
|
|
10244
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10245
|
-
"text",
|
|
10246
|
-
{
|
|
10247
|
-
x: bubble_x + 16,
|
|
10248
|
-
y: bubble_y + 20 + i * row_h,
|
|
10249
|
-
fill: it.color,
|
|
10250
|
-
fontSize: 9,
|
|
10251
|
-
fontWeight: 600,
|
|
10252
|
-
children: format_num(it.value)
|
|
10253
|
-
}
|
|
10254
|
-
)
|
|
10255
|
-
] }, `row_${i}`))
|
|
10256
|
-
] });
|
|
10257
|
-
})()
|
|
10258
|
-
]
|
|
10259
|
-
}
|
|
10260
|
-
),
|
|
10261
|
-
showLegend && /* @__PURE__ */ jsxRuntime.jsx(
|
|
10262
|
-
"div",
|
|
10263
|
-
{
|
|
10264
|
-
className: "cls_hazo_chart_legend",
|
|
10265
|
-
style: {
|
|
10266
|
-
display: "flex",
|
|
10267
|
-
gap: "12px",
|
|
10268
|
-
justifyContent: "center",
|
|
10269
|
-
marginTop: "4px",
|
|
10270
|
-
fontSize: "10px",
|
|
10271
|
-
color: AXIS_LABEL_COLOR2,
|
|
10272
|
-
flexWrap: "wrap"
|
|
10273
|
-
},
|
|
10274
|
-
children: series.map((s) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10275
|
-
"span",
|
|
10276
|
-
{
|
|
10277
|
-
style: { display: "inline-flex", alignItems: "center", gap: "4px" },
|
|
10278
|
-
children: [
|
|
10279
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10280
|
-
"i",
|
|
10281
|
-
{
|
|
10282
|
-
style: {
|
|
10283
|
-
display: "inline-block",
|
|
10284
|
-
width: "8px",
|
|
10285
|
-
height: "8px",
|
|
10286
|
-
background: s.color,
|
|
10287
|
-
borderRadius: "1px"
|
|
10288
|
-
}
|
|
10289
|
-
}
|
|
10290
|
-
),
|
|
10291
|
-
s.label
|
|
10292
|
-
]
|
|
10293
|
-
},
|
|
10294
|
-
s.label
|
|
10295
|
-
))
|
|
10296
|
-
}
|
|
10297
|
-
)
|
|
10298
|
-
] });
|
|
10299
|
-
}
|
|
10300
|
-
var PAD_LEFT3 = 32;
|
|
10301
|
-
var PAD_RIGHT3 = 8;
|
|
10302
|
-
var PAD_TOP3 = 10;
|
|
10303
|
-
var PAD_BOTTOM3 = 22;
|
|
10304
9790
|
var BAR_GAP_RATIO = 0.25;
|
|
10305
|
-
var
|
|
9791
|
+
var AXIS_LABEL_COLOR = "#8b949e";
|
|
10306
9792
|
function StackedBars({
|
|
10307
9793
|
bars,
|
|
10308
9794
|
width = 360,
|
|
@@ -10312,11 +9798,11 @@ function StackedBars({
|
|
|
10312
9798
|
}) {
|
|
10313
9799
|
const totals = bars.map((b) => b.segments.reduce((sum, s) => sum + s.value, 0));
|
|
10314
9800
|
const y_max = Math.max(0, ...totals) || 1;
|
|
10315
|
-
const plot_w = width -
|
|
10316
|
-
const plot_h = height -
|
|
9801
|
+
const plot_w = width - PAD_LEFT - PAD_RIGHT;
|
|
9802
|
+
const plot_h = height - PAD_TOP - PAD_BOTTOM;
|
|
10317
9803
|
const slot_w = bars.length > 0 ? plot_w / bars.length : 0;
|
|
10318
9804
|
const bar_w = slot_w * (1 - BAR_GAP_RATIO);
|
|
10319
|
-
const x_for = (i) =>
|
|
9805
|
+
const x_for = (i) => PAD_LEFT + i * slot_w + (slot_w - bar_w) / 2;
|
|
10320
9806
|
const x_label_idx = pick_x_label_indices(bars.length);
|
|
10321
9807
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10322
9808
|
"svg",
|
|
@@ -10326,14 +9812,14 @@ function StackedBars({
|
|
|
10326
9812
|
style: { width: "100%", height: "auto", display: "block", maxHeight: `${height + 10}px` },
|
|
10327
9813
|
children: [
|
|
10328
9814
|
showYAxis && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
10329
|
-
/* @__PURE__ */ jsxRuntime.jsx("text", { x:
|
|
9815
|
+
/* @__PURE__ */ jsxRuntime.jsx("text", { x: PAD_LEFT - 4, y: PAD_TOP + 3, textAnchor: "end", fill: AXIS_LABEL_COLOR, fontSize: 9, children: format_num(y_max) }),
|
|
10330
9816
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10331
9817
|
"text",
|
|
10332
9818
|
{
|
|
10333
|
-
x:
|
|
10334
|
-
y:
|
|
9819
|
+
x: PAD_LEFT - 4,
|
|
9820
|
+
y: PAD_TOP + plot_h / 2 + 3,
|
|
10335
9821
|
textAnchor: "end",
|
|
10336
|
-
fill:
|
|
9822
|
+
fill: AXIS_LABEL_COLOR,
|
|
10337
9823
|
fontSize: 9,
|
|
10338
9824
|
children: format_num(y_max / 2)
|
|
10339
9825
|
}
|
|
@@ -10341,17 +9827,17 @@ function StackedBars({
|
|
|
10341
9827
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10342
9828
|
"text",
|
|
10343
9829
|
{
|
|
10344
|
-
x:
|
|
10345
|
-
y: height -
|
|
9830
|
+
x: PAD_LEFT - 4,
|
|
9831
|
+
y: height - PAD_BOTTOM + 3,
|
|
10346
9832
|
textAnchor: "end",
|
|
10347
|
-
fill:
|
|
9833
|
+
fill: AXIS_LABEL_COLOR,
|
|
10348
9834
|
fontSize: 9,
|
|
10349
9835
|
children: "0"
|
|
10350
9836
|
}
|
|
10351
9837
|
)
|
|
10352
9838
|
] }),
|
|
10353
9839
|
bars.map((bar, i) => {
|
|
10354
|
-
let cursor_y = height -
|
|
9840
|
+
let cursor_y = height - PAD_BOTTOM;
|
|
10355
9841
|
return /* @__PURE__ */ jsxRuntime.jsx("g", { children: bar.segments.map((seg, s_idx) => {
|
|
10356
9842
|
if (seg.value <= 0) return null;
|
|
10357
9843
|
const seg_h = seg.value / y_max * plot_h;
|
|
@@ -10379,7 +9865,7 @@ function StackedBars({
|
|
|
10379
9865
|
x: x_pos,
|
|
10380
9866
|
y: height - 6,
|
|
10381
9867
|
textAnchor: anchor,
|
|
10382
|
-
fill:
|
|
9868
|
+
fill: AXIS_LABEL_COLOR,
|
|
10383
9869
|
fontSize: 9,
|
|
10384
9870
|
children: bars[idx]?.label ?? ""
|
|
10385
9871
|
},
|
|
@@ -10428,6 +9914,219 @@ function DateRangeSelector({
|
|
|
10428
9914
|
}
|
|
10429
9915
|
);
|
|
10430
9916
|
}
|
|
9917
|
+
var PAD_LEFT2 = 80;
|
|
9918
|
+
var PAD_RIGHT2 = 72;
|
|
9919
|
+
var PAD_TOP2 = 12;
|
|
9920
|
+
var PAD_BOTTOM2 = 12;
|
|
9921
|
+
var ROW_H = 44;
|
|
9922
|
+
var LABEL_H = 14;
|
|
9923
|
+
var BAR_H = 22;
|
|
9924
|
+
var AXIS_LABEL_COLOR2 = "#8b949e";
|
|
9925
|
+
var GRIDLINE_COLOR = "#2a3441";
|
|
9926
|
+
function step_total(step) {
|
|
9927
|
+
if (step.value !== void 0) return step.value;
|
|
9928
|
+
if (step.segments) return step.segments.reduce((s, g) => s + g.value, 0);
|
|
9929
|
+
return 0;
|
|
9930
|
+
}
|
|
9931
|
+
function FunnelChart({
|
|
9932
|
+
steps,
|
|
9933
|
+
width = 360,
|
|
9934
|
+
height,
|
|
9935
|
+
color: color2 = "#3b82f6",
|
|
9936
|
+
valueFormat,
|
|
9937
|
+
showDropoff = true,
|
|
9938
|
+
showTooltip = true,
|
|
9939
|
+
className
|
|
9940
|
+
}) {
|
|
9941
|
+
const [hover_idx, set_hover_idx] = React26__namespace.useState(null);
|
|
9942
|
+
const fmt = valueFormat ?? format_num;
|
|
9943
|
+
const totals = steps.map(step_total);
|
|
9944
|
+
const value_max = Math.max(1, ...totals);
|
|
9945
|
+
const plot_w = width - PAD_LEFT2 - PAD_RIGHT2;
|
|
9946
|
+
const vbox_h = height ?? PAD_TOP2 + steps.length * ROW_H + PAD_BOTTOM2;
|
|
9947
|
+
const handle_mouse_move = React26__namespace.useCallback(
|
|
9948
|
+
(e) => {
|
|
9949
|
+
if (steps.length === 0) return;
|
|
9950
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
9951
|
+
if (rect.height === 0) return;
|
|
9952
|
+
const vbox_y = (e.clientY - rect.top) / rect.height * vbox_h;
|
|
9953
|
+
const row_idx = Math.floor((vbox_y - PAD_TOP2) / ROW_H);
|
|
9954
|
+
if (row_idx < 0 || row_idx >= steps.length) {
|
|
9955
|
+
set_hover_idx(null);
|
|
9956
|
+
return;
|
|
9957
|
+
}
|
|
9958
|
+
set_hover_idx(row_idx);
|
|
9959
|
+
},
|
|
9960
|
+
[steps.length, vbox_h]
|
|
9961
|
+
);
|
|
9962
|
+
const handle_mouse_leave = React26__namespace.useCallback(() => set_hover_idx(null), []);
|
|
9963
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
9964
|
+
"svg",
|
|
9965
|
+
{
|
|
9966
|
+
viewBox: `0 0 ${width} ${vbox_h}`,
|
|
9967
|
+
onMouseMove: showTooltip ? handle_mouse_move : void 0,
|
|
9968
|
+
onMouseLeave: showTooltip ? handle_mouse_leave : void 0,
|
|
9969
|
+
className: cn("cls_hazo_chart cls_hazo_chart_funnel", className),
|
|
9970
|
+
style: {
|
|
9971
|
+
width: "100%",
|
|
9972
|
+
height: "auto",
|
|
9973
|
+
display: "block",
|
|
9974
|
+
cursor: showTooltip ? "crosshair" : "default"
|
|
9975
|
+
},
|
|
9976
|
+
children: [
|
|
9977
|
+
steps.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
9978
|
+
"line",
|
|
9979
|
+
{
|
|
9980
|
+
x1: PAD_LEFT2 + plot_w / 2,
|
|
9981
|
+
x2: PAD_LEFT2 + plot_w / 2,
|
|
9982
|
+
y1: PAD_TOP2,
|
|
9983
|
+
y2: PAD_TOP2 + steps.length * ROW_H,
|
|
9984
|
+
stroke: GRIDLINE_COLOR,
|
|
9985
|
+
strokeWidth: 0.5,
|
|
9986
|
+
strokeDasharray: "2,3"
|
|
9987
|
+
}
|
|
9988
|
+
),
|
|
9989
|
+
steps.map((step, i) => {
|
|
9990
|
+
const total = totals[i];
|
|
9991
|
+
const bar_w = total / value_max * plot_w;
|
|
9992
|
+
const bar_x = PAD_LEFT2 + (plot_w - bar_w) / 2;
|
|
9993
|
+
const bar_y = PAD_TOP2 + i * ROW_H + LABEL_H;
|
|
9994
|
+
const pct_first = i === 0 ? 100 : Math.round(total / (totals[0] || 1) * 100);
|
|
9995
|
+
const value_label = i === 0 ? `${fmt(total)} (100%)` : `${fmt(total)} (${pct_first}%)`;
|
|
9996
|
+
const dropoff = i > 0 ? totals[i - 1] - total : 0;
|
|
9997
|
+
const label_x = bar_x + bar_w + 6;
|
|
9998
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
|
|
9999
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10000
|
+
"text",
|
|
10001
|
+
{
|
|
10002
|
+
x: PAD_LEFT2 - 6,
|
|
10003
|
+
y: bar_y + BAR_H / 2 + 4,
|
|
10004
|
+
textAnchor: "end",
|
|
10005
|
+
fill: AXIS_LABEL_COLOR2,
|
|
10006
|
+
fontSize: 9,
|
|
10007
|
+
children: step.label
|
|
10008
|
+
}
|
|
10009
|
+
),
|
|
10010
|
+
step.segments ? (() => {
|
|
10011
|
+
let cursor_x = bar_x;
|
|
10012
|
+
return step.segments.map((seg, s_idx) => {
|
|
10013
|
+
const seg_w = seg.value / value_max * plot_w;
|
|
10014
|
+
const x = cursor_x;
|
|
10015
|
+
cursor_x += seg_w;
|
|
10016
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
10017
|
+
"rect",
|
|
10018
|
+
{
|
|
10019
|
+
x,
|
|
10020
|
+
y: bar_y,
|
|
10021
|
+
width: seg_w,
|
|
10022
|
+
height: BAR_H,
|
|
10023
|
+
fill: seg.color
|
|
10024
|
+
},
|
|
10025
|
+
`seg_${s_idx}`
|
|
10026
|
+
);
|
|
10027
|
+
});
|
|
10028
|
+
})() : /* @__PURE__ */ jsxRuntime.jsx("rect", { x: bar_x, y: bar_y, width: bar_w, height: BAR_H, fill: color2 }),
|
|
10029
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10030
|
+
"text",
|
|
10031
|
+
{
|
|
10032
|
+
x: label_x,
|
|
10033
|
+
y: bar_y + BAR_H / 2,
|
|
10034
|
+
textAnchor: "start",
|
|
10035
|
+
fill: color2,
|
|
10036
|
+
fontSize: 9,
|
|
10037
|
+
dominantBaseline: "middle",
|
|
10038
|
+
children: value_label
|
|
10039
|
+
}
|
|
10040
|
+
),
|
|
10041
|
+
showDropoff && i > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
10042
|
+
"text",
|
|
10043
|
+
{
|
|
10044
|
+
x: label_x,
|
|
10045
|
+
y: bar_y + BAR_H / 2 + 10,
|
|
10046
|
+
textAnchor: "start",
|
|
10047
|
+
fill: AXIS_LABEL_COLOR2,
|
|
10048
|
+
fontSize: 8,
|
|
10049
|
+
children: `\u2212${fmt(dropoff)}`
|
|
10050
|
+
}
|
|
10051
|
+
)
|
|
10052
|
+
] }, `step_${i}`);
|
|
10053
|
+
}),
|
|
10054
|
+
showTooltip && hover_idx !== null && (() => {
|
|
10055
|
+
const i = hover_idx;
|
|
10056
|
+
const step = steps[i];
|
|
10057
|
+
const total = totals[i];
|
|
10058
|
+
const pct_first = i === 0 ? 100 : Math.round(total / (totals[0] || 1) * 100);
|
|
10059
|
+
const pct_prev = i === 0 ? 100 : Math.round(total / (totals[i - 1] || 1) * 100);
|
|
10060
|
+
const dropoff = i > 0 ? totals[i - 1] - total : 0;
|
|
10061
|
+
const bar_w = total / value_max * plot_w;
|
|
10062
|
+
const bar_x = PAD_LEFT2 + (plot_w - bar_w) / 2;
|
|
10063
|
+
const bar_y = PAD_TOP2 + i * ROW_H + LABEL_H;
|
|
10064
|
+
const bubble_anchor_y = bar_y + BAR_H / 2;
|
|
10065
|
+
const lines = [
|
|
10066
|
+
{ text: step.label, accent: true },
|
|
10067
|
+
{ text: `Total: ${fmt(total)}`, accent: false },
|
|
10068
|
+
{ text: `% of first: ${pct_first}%`, accent: false }
|
|
10069
|
+
];
|
|
10070
|
+
if (i > 0) {
|
|
10071
|
+
lines.push({ text: `% of prev: ${pct_prev}%`, accent: false });
|
|
10072
|
+
lines.push({ text: `Drop-off: \u2212${fmt(dropoff)}`, accent: false });
|
|
10073
|
+
}
|
|
10074
|
+
if (step.segments) {
|
|
10075
|
+
step.segments.forEach((seg) => {
|
|
10076
|
+
lines.push({ text: `${seg.label}: ${fmt(seg.value)}`, accent: false });
|
|
10077
|
+
});
|
|
10078
|
+
}
|
|
10079
|
+
const line_h = 13;
|
|
10080
|
+
const pad_v = 8;
|
|
10081
|
+
const bubble_w = 120;
|
|
10082
|
+
const bubble_h = lines.length * line_h + pad_v * 2;
|
|
10083
|
+
const right_x = bar_x + bar_w + 6;
|
|
10084
|
+
const left_x = bar_x - bubble_w - 6;
|
|
10085
|
+
const fits_right = right_x + bubble_w <= width - 4;
|
|
10086
|
+
const fits_left = left_x >= 4;
|
|
10087
|
+
let bubble_x;
|
|
10088
|
+
let bubble_y;
|
|
10089
|
+
if (fits_right || fits_left) {
|
|
10090
|
+
bubble_x = fits_right ? right_x : left_x;
|
|
10091
|
+
bubble_y = Math.max(4, Math.min(bubble_anchor_y - bubble_h / 2, vbox_h - bubble_h - 4));
|
|
10092
|
+
} else {
|
|
10093
|
+
bubble_x = Math.min(Math.max(bar_x + bar_w / 2 - bubble_w / 2, 4), width - bubble_w - 4);
|
|
10094
|
+
const below_y = bar_y + BAR_H + 6;
|
|
10095
|
+
bubble_y = below_y + bubble_h <= vbox_h - 4 ? below_y : Math.max(4, bar_y - bubble_h - 6);
|
|
10096
|
+
}
|
|
10097
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
|
|
10098
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10099
|
+
"rect",
|
|
10100
|
+
{
|
|
10101
|
+
x: bubble_x,
|
|
10102
|
+
y: bubble_y,
|
|
10103
|
+
width: bubble_w,
|
|
10104
|
+
height: bubble_h,
|
|
10105
|
+
rx: 3,
|
|
10106
|
+
fill: "#0d1117",
|
|
10107
|
+
stroke: color2,
|
|
10108
|
+
strokeWidth: 0.5,
|
|
10109
|
+
fillOpacity: 0.92
|
|
10110
|
+
}
|
|
10111
|
+
),
|
|
10112
|
+
lines.map((line, k) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
10113
|
+
"text",
|
|
10114
|
+
{
|
|
10115
|
+
x: bubble_x + 7,
|
|
10116
|
+
y: bubble_y + pad_v + k * line_h + line_h * 0.75,
|
|
10117
|
+
fill: line.accent ? color2 : AXIS_LABEL_COLOR2,
|
|
10118
|
+
fontSize: line.accent ? 10 : 8,
|
|
10119
|
+
fontWeight: line.accent ? 700 : 400,
|
|
10120
|
+
children: line.text
|
|
10121
|
+
},
|
|
10122
|
+
k
|
|
10123
|
+
))
|
|
10124
|
+
] });
|
|
10125
|
+
})()
|
|
10126
|
+
]
|
|
10127
|
+
}
|
|
10128
|
+
);
|
|
10129
|
+
}
|
|
10431
10130
|
|
|
10432
10131
|
// src/assets/celebration-chime.mp3
|
|
10433
10132
|
var celebration_chime_default = "data:text/plain;charset=utf-8,";
|
|
@@ -10954,6 +10653,7 @@ exports.DropdownMenuTrigger = DropdownMenuTrigger;
|
|
|
10954
10653
|
exports.EmptyState = EmptyState;
|
|
10955
10654
|
exports.ErrorBanner = ErrorBanner;
|
|
10956
10655
|
exports.ErrorPage = ErrorPage;
|
|
10656
|
+
exports.FunnelChart = FunnelChart;
|
|
10957
10657
|
exports.HazoContextProvider = HazoContextProvider;
|
|
10958
10658
|
exports.HazoUiConfirmDialog = HazoUiConfirmDialog;
|
|
10959
10659
|
exports.HazoUiDialog = HazoUiDialog;
|
|
@@ -10985,12 +10685,11 @@ exports.HoverCard = HoverCard;
|
|
|
10985
10685
|
exports.HoverCardContent = HoverCardContent;
|
|
10986
10686
|
exports.HoverCardTrigger = HoverCardTrigger;
|
|
10987
10687
|
exports.Input = Input;
|
|
10688
|
+
exports.InputAffix = InputAffix;
|
|
10988
10689
|
exports.InverseSparkline = InverseSparkline;
|
|
10989
10690
|
exports.Label = Label3;
|
|
10990
|
-
exports.LineChart = LineChart;
|
|
10991
10691
|
exports.LoadingTimeout = LoadingTimeout;
|
|
10992
10692
|
exports.MarkdownEditor = MarkdownEditor;
|
|
10993
|
-
exports.MultiLineChart = MultiLineChart;
|
|
10994
10693
|
exports.Popover = Popover;
|
|
10995
10694
|
exports.PopoverContent = PopoverContent;
|
|
10996
10695
|
exports.PopoverTrigger = PopoverTrigger;
|
|
@@ -11021,6 +10720,7 @@ exports.SkeletonBar = SkeletonBar;
|
|
|
11021
10720
|
exports.SkeletonCircle = SkeletonCircle;
|
|
11022
10721
|
exports.SkeletonGroup = SkeletonGroup;
|
|
11023
10722
|
exports.SkeletonRect = SkeletonRect;
|
|
10723
|
+
exports.Slider = Slider;
|
|
11024
10724
|
exports.Sparkline = Sparkline;
|
|
11025
10725
|
exports.Spinner = Spinner;
|
|
11026
10726
|
exports.StackedBars = StackedBars;
|