hazo_ui 3.5.0 → 4.2.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/CHANGE_LOG.md +56 -0
- package/README.md +111 -0
- package/SETUP_CHECKLIST.md +8 -1
- package/dist/index.cjs +285 -604
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +92 -63
- package/dist/index.d.ts +92 -63
- package/dist/index.js +279 -602
- package/dist/index.js.map +1 -1
- package/package.json +5 -8
package/dist/index.js
CHANGED
|
@@ -41,7 +41,7 @@ import Link from '@tiptap/extension-link';
|
|
|
41
41
|
import TextAlign from '@tiptap/extension-text-align';
|
|
42
42
|
import Highlight from '@tiptap/extension-highlight';
|
|
43
43
|
import Color from '@tiptap/extension-color';
|
|
44
|
-
import
|
|
44
|
+
import Image2 from '@tiptap/extension-image';
|
|
45
45
|
import Placeholder from '@tiptap/extension-placeholder';
|
|
46
46
|
import HorizontalRule from '@tiptap/extension-horizontal-rule';
|
|
47
47
|
import { Table } from '@tiptap/extension-table';
|
|
@@ -60,6 +60,8 @@ import '@uiw/react-markdown-preview/markdown.css';
|
|
|
60
60
|
import Suggestion from '@tiptap/suggestion';
|
|
61
61
|
import { PluginKey } from '@tiptap/pm/state';
|
|
62
62
|
import { createPortal } from 'react-dom';
|
|
63
|
+
import Cropper from 'react-easy-crop';
|
|
64
|
+
import * as SliderPrimitive from '@radix-ui/react-slider';
|
|
63
65
|
import { Drawer as Drawer$1 } from 'vaul';
|
|
64
66
|
import * as AccordionPrimitive from '@radix-ui/react-accordion';
|
|
65
67
|
import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
|
|
@@ -4296,7 +4298,7 @@ var HazoUiRte = ({
|
|
|
4296
4298
|
multicolor: true
|
|
4297
4299
|
}),
|
|
4298
4300
|
Color,
|
|
4299
|
-
|
|
4301
|
+
Image2.configure({
|
|
4300
4302
|
inline: true,
|
|
4301
4303
|
allowBase64: true,
|
|
4302
4304
|
HTMLAttributes: {
|
|
@@ -6844,6 +6846,210 @@ function HazoUiConfirmDialog({
|
|
|
6844
6846
|
)
|
|
6845
6847
|
] }) });
|
|
6846
6848
|
}
|
|
6849
|
+
var Slider = React26.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxs(
|
|
6850
|
+
SliderPrimitive.Root,
|
|
6851
|
+
{
|
|
6852
|
+
ref,
|
|
6853
|
+
className: cn("relative flex w-full touch-none select-none items-center", className),
|
|
6854
|
+
...props,
|
|
6855
|
+
children: [
|
|
6856
|
+
/* @__PURE__ */ jsx(SliderPrimitive.Track, { className: "relative h-2 w-full grow overflow-hidden rounded-full bg-secondary", children: /* @__PURE__ */ jsx(SliderPrimitive.Range, { className: "absolute h-full bg-primary" }) }),
|
|
6857
|
+
/* @__PURE__ */ jsx(SliderPrimitive.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" })
|
|
6858
|
+
]
|
|
6859
|
+
}
|
|
6860
|
+
));
|
|
6861
|
+
Slider.displayName = SliderPrimitive.Root.displayName;
|
|
6862
|
+
async function getCroppedImg(imageSrc, areaPixels, outputSize, quality) {
|
|
6863
|
+
const img = await new Promise((resolve, reject) => {
|
|
6864
|
+
const image = new Image();
|
|
6865
|
+
image.crossOrigin = "anonymous";
|
|
6866
|
+
image.onload = () => resolve(image);
|
|
6867
|
+
image.onerror = (e) => reject(e);
|
|
6868
|
+
image.src = imageSrc;
|
|
6869
|
+
});
|
|
6870
|
+
const canvas = document.createElement("canvas");
|
|
6871
|
+
canvas.width = outputSize;
|
|
6872
|
+
canvas.height = outputSize;
|
|
6873
|
+
const ctx = canvas.getContext("2d");
|
|
6874
|
+
if (!ctx) {
|
|
6875
|
+
throw new Error("HazoUiImageCropper: canvas 2d context unavailable");
|
|
6876
|
+
}
|
|
6877
|
+
ctx.drawImage(
|
|
6878
|
+
img,
|
|
6879
|
+
areaPixels.x,
|
|
6880
|
+
areaPixels.y,
|
|
6881
|
+
areaPixels.width,
|
|
6882
|
+
areaPixels.height,
|
|
6883
|
+
0,
|
|
6884
|
+
0,
|
|
6885
|
+
outputSize,
|
|
6886
|
+
outputSize
|
|
6887
|
+
);
|
|
6888
|
+
return new Promise((resolve, reject) => {
|
|
6889
|
+
canvas.toBlob(
|
|
6890
|
+
(blob) => {
|
|
6891
|
+
if (blob) {
|
|
6892
|
+
resolve(blob);
|
|
6893
|
+
} else {
|
|
6894
|
+
reject(new Error("HazoUiImageCropper: canvas.toBlob returned null"));
|
|
6895
|
+
}
|
|
6896
|
+
},
|
|
6897
|
+
"image/webp",
|
|
6898
|
+
quality
|
|
6899
|
+
);
|
|
6900
|
+
});
|
|
6901
|
+
}
|
|
6902
|
+
var HazoUiImageCropper = React26.forwardRef(function HazoUiImageCropper2({
|
|
6903
|
+
imageSrc,
|
|
6904
|
+
onCropped,
|
|
6905
|
+
outputSize = 512,
|
|
6906
|
+
quality = 0.9,
|
|
6907
|
+
zoomLabel = "Zoom",
|
|
6908
|
+
className
|
|
6909
|
+
}, ref) {
|
|
6910
|
+
const [crop, set_crop] = React26.useState({
|
|
6911
|
+
x: 0,
|
|
6912
|
+
y: 0
|
|
6913
|
+
});
|
|
6914
|
+
const [zoom, set_zoom] = React26.useState(1);
|
|
6915
|
+
const cropped_area_pixels_ref = React26.useRef(null);
|
|
6916
|
+
const handle_crop_complete = React26.useCallback(
|
|
6917
|
+
(_croppedArea, croppedAreaPixels) => {
|
|
6918
|
+
cropped_area_pixels_ref.current = croppedAreaPixels;
|
|
6919
|
+
},
|
|
6920
|
+
[]
|
|
6921
|
+
);
|
|
6922
|
+
React26.useImperativeHandle(
|
|
6923
|
+
ref,
|
|
6924
|
+
() => ({
|
|
6925
|
+
getCroppedBlob: async () => {
|
|
6926
|
+
if (!cropped_area_pixels_ref.current) {
|
|
6927
|
+
throw new Error(
|
|
6928
|
+
"HazoUiImageCropper: crop area not yet initialised \u2014 wait for the cropper to mount before calling getCroppedBlob."
|
|
6929
|
+
);
|
|
6930
|
+
}
|
|
6931
|
+
const blob = await getCroppedImg(
|
|
6932
|
+
imageSrc,
|
|
6933
|
+
cropped_area_pixels_ref.current,
|
|
6934
|
+
outputSize,
|
|
6935
|
+
quality
|
|
6936
|
+
);
|
|
6937
|
+
await onCropped?.(blob);
|
|
6938
|
+
return blob;
|
|
6939
|
+
}
|
|
6940
|
+
}),
|
|
6941
|
+
[imageSrc, onCropped, outputSize, quality]
|
|
6942
|
+
);
|
|
6943
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("cls_image_cropper_root flex flex-col gap-4", className), children: [
|
|
6944
|
+
/* @__PURE__ */ jsx(
|
|
6945
|
+
"div",
|
|
6946
|
+
{
|
|
6947
|
+
className: "cls_cropper_stage relative w-full overflow-hidden rounded-lg bg-muted",
|
|
6948
|
+
style: { height: "320px" },
|
|
6949
|
+
children: /* @__PURE__ */ jsx(
|
|
6950
|
+
Cropper,
|
|
6951
|
+
{
|
|
6952
|
+
image: imageSrc,
|
|
6953
|
+
crop,
|
|
6954
|
+
zoom,
|
|
6955
|
+
aspect: 1,
|
|
6956
|
+
cropShape: "round",
|
|
6957
|
+
showGrid: false,
|
|
6958
|
+
onCropChange: set_crop,
|
|
6959
|
+
onZoomChange: set_zoom,
|
|
6960
|
+
onCropComplete: handle_crop_complete
|
|
6961
|
+
}
|
|
6962
|
+
)
|
|
6963
|
+
}
|
|
6964
|
+
),
|
|
6965
|
+
/* @__PURE__ */ jsxs("div", { className: "cls_zoom_control flex flex-col gap-1.5", children: [
|
|
6966
|
+
/* @__PURE__ */ jsx(
|
|
6967
|
+
"label",
|
|
6968
|
+
{
|
|
6969
|
+
className: "cls_zoom_label text-sm font-medium text-foreground",
|
|
6970
|
+
id: "hazo-cropper-zoom-label",
|
|
6971
|
+
children: zoomLabel
|
|
6972
|
+
}
|
|
6973
|
+
),
|
|
6974
|
+
/* @__PURE__ */ jsx(
|
|
6975
|
+
Slider,
|
|
6976
|
+
{
|
|
6977
|
+
"aria-labelledby": "hazo-cropper-zoom-label",
|
|
6978
|
+
min: 1,
|
|
6979
|
+
max: 3,
|
|
6980
|
+
step: 0.1,
|
|
6981
|
+
value: [zoom],
|
|
6982
|
+
onValueChange: (values) => set_zoom(values[0])
|
|
6983
|
+
}
|
|
6984
|
+
)
|
|
6985
|
+
] })
|
|
6986
|
+
] });
|
|
6987
|
+
});
|
|
6988
|
+
HazoUiImageCropper.displayName = "HazoUiImageCropper";
|
|
6989
|
+
function HazoUiImageCropperDialog({
|
|
6990
|
+
open,
|
|
6991
|
+
onOpenChange,
|
|
6992
|
+
file,
|
|
6993
|
+
onConfirm,
|
|
6994
|
+
onCancel,
|
|
6995
|
+
title = "Crop photo",
|
|
6996
|
+
confirmLabel = "Save",
|
|
6997
|
+
cancelLabel = "Cancel",
|
|
6998
|
+
zoomLabel = "Zoom",
|
|
6999
|
+
outputSize = 512,
|
|
7000
|
+
quality = 0.9
|
|
7001
|
+
}) {
|
|
7002
|
+
const cropper_ref = React26.useRef(null);
|
|
7003
|
+
const [image_src, set_image_src] = React26.useState(null);
|
|
7004
|
+
const [is_confirming, set_is_confirming] = React26.useState(false);
|
|
7005
|
+
React26.useEffect(() => {
|
|
7006
|
+
if (!file) {
|
|
7007
|
+
set_image_src(null);
|
|
7008
|
+
return;
|
|
7009
|
+
}
|
|
7010
|
+
const url = URL.createObjectURL(file);
|
|
7011
|
+
set_image_src(url);
|
|
7012
|
+
return () => {
|
|
7013
|
+
URL.revokeObjectURL(url);
|
|
7014
|
+
};
|
|
7015
|
+
}, [file]);
|
|
7016
|
+
const handle_confirm = async () => {
|
|
7017
|
+
if (!cropper_ref.current) return;
|
|
7018
|
+
set_is_confirming(true);
|
|
7019
|
+
try {
|
|
7020
|
+
const blob = await cropper_ref.current.getCroppedBlob();
|
|
7021
|
+
await onConfirm(blob);
|
|
7022
|
+
onOpenChange(false);
|
|
7023
|
+
} finally {
|
|
7024
|
+
set_is_confirming(false);
|
|
7025
|
+
}
|
|
7026
|
+
};
|
|
7027
|
+
return /* @__PURE__ */ jsx(
|
|
7028
|
+
HazoUiDialog,
|
|
7029
|
+
{
|
|
7030
|
+
open,
|
|
7031
|
+
onOpenChange,
|
|
7032
|
+
title,
|
|
7033
|
+
actionButtonText: confirmLabel,
|
|
7034
|
+
cancelButtonText: cancelLabel,
|
|
7035
|
+
onConfirm: handle_confirm,
|
|
7036
|
+
onCancel,
|
|
7037
|
+
actionButtonLoading: is_confirming,
|
|
7038
|
+
sizeWidth: "min(90vw, 520px)",
|
|
7039
|
+
contentClassName: "cls_image_cropper_dialog_body",
|
|
7040
|
+
children: image_src && /* @__PURE__ */ jsx(
|
|
7041
|
+
HazoUiImageCropper,
|
|
7042
|
+
{
|
|
7043
|
+
ref: cropper_ref,
|
|
7044
|
+
imageSrc: image_src,
|
|
7045
|
+
outputSize,
|
|
7046
|
+
quality,
|
|
7047
|
+
zoomLabel
|
|
7048
|
+
}
|
|
7049
|
+
)
|
|
7050
|
+
}
|
|
7051
|
+
);
|
|
7052
|
+
}
|
|
6847
7053
|
var Drawer = ({
|
|
6848
7054
|
shouldScaleBackground = true,
|
|
6849
7055
|
...props
|
|
@@ -7390,6 +7596,38 @@ function ButtonGroupText({ className, asChild = false, ...props }) {
|
|
|
7390
7596
|
function ButtonGroupSeparator({ className, orientation = "vertical", ...props }) {
|
|
7391
7597
|
return /* @__PURE__ */ jsx(Separator3, { orientation, className: cn("bg-input relative !m-0 self-stretch data-[orientation=vertical]:h-auto", className), ...props });
|
|
7392
7598
|
}
|
|
7599
|
+
var InputAffix = React26.forwardRef(
|
|
7600
|
+
({ className, containerClassName, prefix, suffix, type = "text", ...props }, ref) => {
|
|
7601
|
+
return /* @__PURE__ */ jsxs(
|
|
7602
|
+
"div",
|
|
7603
|
+
{
|
|
7604
|
+
className: cn(
|
|
7605
|
+
"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",
|
|
7606
|
+
containerClassName
|
|
7607
|
+
),
|
|
7608
|
+
children: [
|
|
7609
|
+
prefix != null && /* @__PURE__ */ jsx("span", { className: "flex select-none items-center pl-3 text-muted-foreground", children: prefix }),
|
|
7610
|
+
/* @__PURE__ */ jsx(
|
|
7611
|
+
"input",
|
|
7612
|
+
{
|
|
7613
|
+
type,
|
|
7614
|
+
ref,
|
|
7615
|
+
className: cn(
|
|
7616
|
+
"h-full w-full bg-transparent px-3 py-2 outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
|
|
7617
|
+
prefix != null && "pl-2",
|
|
7618
|
+
suffix != null && "pr-2",
|
|
7619
|
+
className
|
|
7620
|
+
),
|
|
7621
|
+
...props
|
|
7622
|
+
}
|
|
7623
|
+
),
|
|
7624
|
+
suffix != null && /* @__PURE__ */ jsx("span", { className: "flex select-none items-center pr-3 text-muted-foreground", children: suffix })
|
|
7625
|
+
]
|
|
7626
|
+
}
|
|
7627
|
+
);
|
|
7628
|
+
}
|
|
7629
|
+
);
|
|
7630
|
+
InputAffix.displayName = "InputAffix";
|
|
7393
7631
|
var SkeletonBase = React26.forwardRef(
|
|
7394
7632
|
({ className, ...rest }, ref) => /* @__PURE__ */ jsx(
|
|
7395
7633
|
"div",
|
|
@@ -9668,573 +9906,12 @@ function pick_x_label_indices(length) {
|
|
|
9668
9906
|
if (length === 2) return [0, 0, 1];
|
|
9669
9907
|
return [0, Math.floor(length / 2), length - 1];
|
|
9670
9908
|
}
|
|
9671
|
-
var PAD_LEFT =
|
|
9672
|
-
var PAD_RIGHT =
|
|
9673
|
-
var PAD_TOP =
|
|
9909
|
+
var PAD_LEFT = 32;
|
|
9910
|
+
var PAD_RIGHT = 8;
|
|
9911
|
+
var PAD_TOP = 10;
|
|
9674
9912
|
var PAD_BOTTOM = 22;
|
|
9675
|
-
var AXIS_LABEL_COLOR = "#8b949e";
|
|
9676
|
-
var GRIDLINE_COLOR = "#2a3441";
|
|
9677
|
-
function compute_geometry(data, width, height) {
|
|
9678
|
-
const vals = data.filter((v) => v !== null && !Number.isNaN(v));
|
|
9679
|
-
if (vals.length === 0) return null;
|
|
9680
|
-
const mn = Math.min(...vals);
|
|
9681
|
-
const mx = Math.max(...vals);
|
|
9682
|
-
const rng = mx - mn || mx * 0.1 + 1;
|
|
9683
|
-
const y_min = Math.max(0, mn - rng * 0.1);
|
|
9684
|
-
const y_max = mx + rng * 0.1;
|
|
9685
|
-
const y_rng = y_max - y_min || 1;
|
|
9686
|
-
const plot_w = width - PAD_LEFT - PAD_RIGHT;
|
|
9687
|
-
const plot_h = height - PAD_TOP - PAD_BOTTOM;
|
|
9688
|
-
return {
|
|
9689
|
-
vbox_w: width,
|
|
9690
|
-
vbox_h: height,
|
|
9691
|
-
y_min,
|
|
9692
|
-
y_max,
|
|
9693
|
-
cx: (i) => data.length <= 1 ? PAD_LEFT + plot_w / 2 : PAD_LEFT + i * plot_w / (data.length - 1),
|
|
9694
|
-
cy: (v) => PAD_TOP + (1 - (v - y_min) / y_rng) * plot_h
|
|
9695
|
-
};
|
|
9696
|
-
}
|
|
9697
|
-
function build_paths(data, g) {
|
|
9698
|
-
let line_d = "";
|
|
9699
|
-
let first_idx = -1;
|
|
9700
|
-
data.forEach((v, i) => {
|
|
9701
|
-
if (v === null || Number.isNaN(v)) return;
|
|
9702
|
-
if (first_idx === -1) first_idx = i;
|
|
9703
|
-
line_d += `${line_d ? " L" : "M"}${g.cx(i).toFixed(1)},${g.cy(v).toFixed(1)}`;
|
|
9704
|
-
});
|
|
9705
|
-
const last_idx = data.length - 1;
|
|
9706
|
-
const last_v = data[last_idx];
|
|
9707
|
-
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` : "";
|
|
9708
|
-
return { line_d, area_d };
|
|
9709
|
-
}
|
|
9710
|
-
function LineChart({
|
|
9711
|
-
data,
|
|
9712
|
-
dates,
|
|
9713
|
-
color: color2,
|
|
9714
|
-
width = 360,
|
|
9715
|
-
height = 130,
|
|
9716
|
-
unit = "",
|
|
9717
|
-
showTooltip = true,
|
|
9718
|
-
className
|
|
9719
|
-
}) {
|
|
9720
|
-
const geo = compute_geometry(data, width, height);
|
|
9721
|
-
const svg_ref = React26.useRef(null);
|
|
9722
|
-
const [hover_idx, set_hover_idx] = React26.useState(null);
|
|
9723
|
-
const handle_mouse_move = React26.useCallback(
|
|
9724
|
-
(e) => {
|
|
9725
|
-
if (!geo) return;
|
|
9726
|
-
const rect = e.currentTarget.getBoundingClientRect();
|
|
9727
|
-
if (rect.width === 0) return;
|
|
9728
|
-
const vbox_x = (e.clientX - rect.left) / rect.width * geo.vbox_w;
|
|
9729
|
-
const plot_w = geo.vbox_w - PAD_LEFT - PAD_RIGHT;
|
|
9730
|
-
if (vbox_x < PAD_LEFT || vbox_x > geo.vbox_w - PAD_RIGHT) {
|
|
9731
|
-
set_hover_idx(null);
|
|
9732
|
-
return;
|
|
9733
|
-
}
|
|
9734
|
-
const ratio = (vbox_x - PAD_LEFT) / plot_w;
|
|
9735
|
-
const idx = Math.round(ratio * (data.length - 1));
|
|
9736
|
-
const clamped = Math.max(0, Math.min(data.length - 1, idx));
|
|
9737
|
-
let resolved = clamped;
|
|
9738
|
-
if (data[resolved] === null || Number.isNaN(data[resolved])) {
|
|
9739
|
-
for (let step = 1; step < data.length; step += 1) {
|
|
9740
|
-
const left_i = clamped - step;
|
|
9741
|
-
const right_i = clamped + step;
|
|
9742
|
-
if (left_i >= 0 && data[left_i] !== null && !Number.isNaN(data[left_i])) {
|
|
9743
|
-
resolved = left_i;
|
|
9744
|
-
break;
|
|
9745
|
-
}
|
|
9746
|
-
if (right_i < data.length && data[right_i] !== null && !Number.isNaN(data[right_i])) {
|
|
9747
|
-
resolved = right_i;
|
|
9748
|
-
break;
|
|
9749
|
-
}
|
|
9750
|
-
}
|
|
9751
|
-
}
|
|
9752
|
-
set_hover_idx(resolved);
|
|
9753
|
-
},
|
|
9754
|
-
[geo, data]
|
|
9755
|
-
);
|
|
9756
|
-
const handle_mouse_leave = React26.useCallback(() => set_hover_idx(null), []);
|
|
9757
|
-
if (!geo) {
|
|
9758
|
-
return /* @__PURE__ */ jsx(
|
|
9759
|
-
"svg",
|
|
9760
|
-
{
|
|
9761
|
-
viewBox: `0 0 ${width} ${height}`,
|
|
9762
|
-
className: cn("cls_hazo_chart cls_hazo_chart_empty", className),
|
|
9763
|
-
style: { width: "100%", height: "auto", display: "block", maxHeight: `${height + 10}px` }
|
|
9764
|
-
}
|
|
9765
|
-
);
|
|
9766
|
-
}
|
|
9767
|
-
const { line_d, area_d } = build_paths(data, geo);
|
|
9768
|
-
const x_label_idx = pick_x_label_indices(data.length);
|
|
9769
|
-
const last_idx = data.length - 1;
|
|
9770
|
-
const last_v = data[last_idx];
|
|
9771
|
-
const has_last = last_v !== null && last_v !== void 0 && !Number.isNaN(last_v);
|
|
9772
|
-
const hover_v = hover_idx !== null ? data[hover_idx] : null;
|
|
9773
|
-
const hover_has_v = hover_v !== null && hover_v !== void 0 && !Number.isNaN(hover_v);
|
|
9774
|
-
return /* @__PURE__ */ jsxs(
|
|
9775
|
-
"svg",
|
|
9776
|
-
{
|
|
9777
|
-
ref: svg_ref,
|
|
9778
|
-
viewBox: `0 0 ${width} ${height}`,
|
|
9779
|
-
onMouseMove: showTooltip ? handle_mouse_move : void 0,
|
|
9780
|
-
onMouseLeave: showTooltip ? handle_mouse_leave : void 0,
|
|
9781
|
-
className: cn("cls_hazo_chart", className),
|
|
9782
|
-
style: {
|
|
9783
|
-
width: "100%",
|
|
9784
|
-
height: "auto",
|
|
9785
|
-
display: "block",
|
|
9786
|
-
maxHeight: `${height + 10}px`,
|
|
9787
|
-
cursor: showTooltip ? "crosshair" : "default"
|
|
9788
|
-
},
|
|
9789
|
-
children: [
|
|
9790
|
-
[0, 1, 2].map((i) => {
|
|
9791
|
-
const y = PAD_TOP + i / 2 * (geo.vbox_h - PAD_TOP - PAD_BOTTOM);
|
|
9792
|
-
return /* @__PURE__ */ jsx(
|
|
9793
|
-
"line",
|
|
9794
|
-
{
|
|
9795
|
-
x1: PAD_LEFT,
|
|
9796
|
-
x2: geo.vbox_w - PAD_RIGHT,
|
|
9797
|
-
y1: y,
|
|
9798
|
-
y2: y,
|
|
9799
|
-
stroke: GRIDLINE_COLOR,
|
|
9800
|
-
strokeWidth: 0.5,
|
|
9801
|
-
strokeDasharray: "2,3"
|
|
9802
|
-
},
|
|
9803
|
-
i
|
|
9804
|
-
);
|
|
9805
|
-
}),
|
|
9806
|
-
area_d && /* @__PURE__ */ jsx("path", { d: area_d, fill: color2, fillOpacity: 0.12, stroke: "none" }),
|
|
9807
|
-
line_d && /* @__PURE__ */ jsx("path", { d: line_d, stroke: color2, strokeWidth: 1.8, fill: "none" }),
|
|
9808
|
-
/* @__PURE__ */ jsx("text", { x: PAD_LEFT - 4, y: PAD_TOP + 3, textAnchor: "end", fill: AXIS_LABEL_COLOR, fontSize: 9, children: format_num(geo.y_max) }),
|
|
9809
|
-
/* @__PURE__ */ jsx(
|
|
9810
|
-
"text",
|
|
9811
|
-
{
|
|
9812
|
-
x: PAD_LEFT - 4,
|
|
9813
|
-
y: PAD_TOP + (geo.vbox_h - PAD_TOP - PAD_BOTTOM) / 2 + 3,
|
|
9814
|
-
textAnchor: "end",
|
|
9815
|
-
fill: AXIS_LABEL_COLOR,
|
|
9816
|
-
fontSize: 9,
|
|
9817
|
-
children: format_num((geo.y_max + geo.y_min) / 2)
|
|
9818
|
-
}
|
|
9819
|
-
),
|
|
9820
|
-
/* @__PURE__ */ jsx(
|
|
9821
|
-
"text",
|
|
9822
|
-
{
|
|
9823
|
-
x: PAD_LEFT - 4,
|
|
9824
|
-
y: geo.vbox_h - PAD_BOTTOM + 3,
|
|
9825
|
-
textAnchor: "end",
|
|
9826
|
-
fill: AXIS_LABEL_COLOR,
|
|
9827
|
-
fontSize: 9,
|
|
9828
|
-
children: format_num(geo.y_min)
|
|
9829
|
-
}
|
|
9830
|
-
),
|
|
9831
|
-
x_label_idx.map((idx, k) => {
|
|
9832
|
-
const anchor = k === 0 ? "start" : k === 1 ? "middle" : "end";
|
|
9833
|
-
const x_pos = geo.cx(idx);
|
|
9834
|
-
return /* @__PURE__ */ jsx(
|
|
9835
|
-
"text",
|
|
9836
|
-
{
|
|
9837
|
-
x: x_pos,
|
|
9838
|
-
y: geo.vbox_h - 6,
|
|
9839
|
-
textAnchor: anchor,
|
|
9840
|
-
fill: AXIS_LABEL_COLOR,
|
|
9841
|
-
fontSize: 9,
|
|
9842
|
-
children: dates[idx] ?? ""
|
|
9843
|
-
},
|
|
9844
|
-
`x_${k}`
|
|
9845
|
-
);
|
|
9846
|
-
}),
|
|
9847
|
-
has_last && hover_idx === null && (() => {
|
|
9848
|
-
const x = geo.cx(last_idx);
|
|
9849
|
-
const y = geo.cy(last_v);
|
|
9850
|
-
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
9851
|
-
/* @__PURE__ */ jsx(
|
|
9852
|
-
"line",
|
|
9853
|
-
{
|
|
9854
|
-
x1: x,
|
|
9855
|
-
x2: PAD_LEFT,
|
|
9856
|
-
y1: y,
|
|
9857
|
-
y2: y,
|
|
9858
|
-
stroke: color2,
|
|
9859
|
-
strokeWidth: 0.5,
|
|
9860
|
-
strokeDasharray: "2,2",
|
|
9861
|
-
opacity: 0.4
|
|
9862
|
-
}
|
|
9863
|
-
),
|
|
9864
|
-
/* @__PURE__ */ jsx("circle", { cx: x, cy: y, r: 3.5, fill: color2, stroke: color2, strokeWidth: 2, fillOpacity: 0.3 }),
|
|
9865
|
-
/* @__PURE__ */ jsx("circle", { cx: x, cy: y, r: 2, fill: color2 }),
|
|
9866
|
-
/* @__PURE__ */ jsxs("text", { x: x - 6, y: y - 6, textAnchor: "end", fill: color2, fontSize: 10, fontWeight: 700, children: [
|
|
9867
|
-
format_num(last_v),
|
|
9868
|
-
unit
|
|
9869
|
-
] })
|
|
9870
|
-
] });
|
|
9871
|
-
})(),
|
|
9872
|
-
showTooltip && hover_idx !== null && hover_has_v && (() => {
|
|
9873
|
-
const x = geo.cx(hover_idx);
|
|
9874
|
-
const y = geo.cy(hover_v);
|
|
9875
|
-
const label = `${format_num(hover_v)}${unit}`;
|
|
9876
|
-
const date = dates[hover_idx] ?? "";
|
|
9877
|
-
const bubble_text_w = Math.max(label.length, date.length) * 5.5 + 12;
|
|
9878
|
-
const bubble_w = Math.max(bubble_text_w, 40);
|
|
9879
|
-
const bubble_h = 26;
|
|
9880
|
-
const flip = x + bubble_w + 6 > geo.vbox_w - PAD_RIGHT;
|
|
9881
|
-
const bubble_x = flip ? x - bubble_w - 6 : x + 6;
|
|
9882
|
-
const bubble_y = Math.max(PAD_TOP, Math.min(y - bubble_h / 2, geo.vbox_h - PAD_BOTTOM - bubble_h));
|
|
9883
|
-
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
9884
|
-
/* @__PURE__ */ jsx(
|
|
9885
|
-
"line",
|
|
9886
|
-
{
|
|
9887
|
-
x1: x,
|
|
9888
|
-
x2: x,
|
|
9889
|
-
y1: PAD_TOP,
|
|
9890
|
-
y2: geo.vbox_h - PAD_BOTTOM,
|
|
9891
|
-
stroke: color2,
|
|
9892
|
-
strokeWidth: 0.5,
|
|
9893
|
-
strokeDasharray: "2,2",
|
|
9894
|
-
opacity: 0.6
|
|
9895
|
-
}
|
|
9896
|
-
),
|
|
9897
|
-
/* @__PURE__ */ jsx("circle", { cx: x, cy: y, r: 3, fill: color2 }),
|
|
9898
|
-
/* @__PURE__ */ jsx(
|
|
9899
|
-
"rect",
|
|
9900
|
-
{
|
|
9901
|
-
x: bubble_x,
|
|
9902
|
-
y: bubble_y,
|
|
9903
|
-
width: bubble_w,
|
|
9904
|
-
height: bubble_h,
|
|
9905
|
-
rx: 3,
|
|
9906
|
-
fill: "#0d1117",
|
|
9907
|
-
stroke: color2,
|
|
9908
|
-
strokeWidth: 0.5,
|
|
9909
|
-
fillOpacity: 0.92
|
|
9910
|
-
}
|
|
9911
|
-
),
|
|
9912
|
-
/* @__PURE__ */ jsx(
|
|
9913
|
-
"text",
|
|
9914
|
-
{
|
|
9915
|
-
x: bubble_x + bubble_w / 2,
|
|
9916
|
-
y: bubble_y + 11,
|
|
9917
|
-
textAnchor: "middle",
|
|
9918
|
-
fill: color2,
|
|
9919
|
-
fontSize: 10,
|
|
9920
|
-
fontWeight: 700,
|
|
9921
|
-
children: label
|
|
9922
|
-
}
|
|
9923
|
-
),
|
|
9924
|
-
/* @__PURE__ */ jsx(
|
|
9925
|
-
"text",
|
|
9926
|
-
{
|
|
9927
|
-
x: bubble_x + bubble_w / 2,
|
|
9928
|
-
y: bubble_y + 22,
|
|
9929
|
-
textAnchor: "middle",
|
|
9930
|
-
fill: AXIS_LABEL_COLOR,
|
|
9931
|
-
fontSize: 8,
|
|
9932
|
-
children: date
|
|
9933
|
-
}
|
|
9934
|
-
)
|
|
9935
|
-
] });
|
|
9936
|
-
})()
|
|
9937
|
-
]
|
|
9938
|
-
}
|
|
9939
|
-
);
|
|
9940
|
-
}
|
|
9941
|
-
var PAD_LEFT2 = 38;
|
|
9942
|
-
var PAD_RIGHT2 = 14;
|
|
9943
|
-
var PAD_TOP2 = 12;
|
|
9944
|
-
var PAD_BOTTOM2 = 22;
|
|
9945
|
-
var AXIS_LABEL_COLOR2 = "#8b949e";
|
|
9946
|
-
var GRIDLINE_COLOR2 = "#2a3441";
|
|
9947
|
-
function compute_geometry2(series, width, height) {
|
|
9948
|
-
const all_vals = [];
|
|
9949
|
-
let n = 0;
|
|
9950
|
-
for (const s of series) {
|
|
9951
|
-
n = Math.max(n, s.data.length);
|
|
9952
|
-
for (const v of s.data) if (v !== null && !Number.isNaN(v)) all_vals.push(v);
|
|
9953
|
-
}
|
|
9954
|
-
if (all_vals.length === 0 || n === 0) return null;
|
|
9955
|
-
const mn = Math.min(...all_vals);
|
|
9956
|
-
const mx = Math.max(...all_vals);
|
|
9957
|
-
const rng = mx - mn || mx * 0.1 + 1;
|
|
9958
|
-
const y_min = Math.max(0, mn - rng * 0.05);
|
|
9959
|
-
const y_max = mx + rng * 0.05;
|
|
9960
|
-
const y_rng = y_max - y_min || 1;
|
|
9961
|
-
const plot_w = width - PAD_LEFT2 - PAD_RIGHT2;
|
|
9962
|
-
const plot_h = height - PAD_TOP2 - PAD_BOTTOM2;
|
|
9963
|
-
return {
|
|
9964
|
-
vbox_w: width,
|
|
9965
|
-
vbox_h: height,
|
|
9966
|
-
y_min,
|
|
9967
|
-
y_max,
|
|
9968
|
-
point_count: n,
|
|
9969
|
-
cx: (i) => n <= 1 ? PAD_LEFT2 + plot_w / 2 : PAD_LEFT2 + i * plot_w / (n - 1),
|
|
9970
|
-
cy: (v) => PAD_TOP2 + (1 - (v - y_min) / y_rng) * plot_h
|
|
9971
|
-
};
|
|
9972
|
-
}
|
|
9973
|
-
function MultiLineChart({
|
|
9974
|
-
series,
|
|
9975
|
-
dates,
|
|
9976
|
-
width = 360,
|
|
9977
|
-
height = 140,
|
|
9978
|
-
showTooltip = true,
|
|
9979
|
-
showLegend = true,
|
|
9980
|
-
className
|
|
9981
|
-
}) {
|
|
9982
|
-
const geo = compute_geometry2(series, width, height);
|
|
9983
|
-
const [hover_idx, set_hover_idx] = React26.useState(null);
|
|
9984
|
-
const handle_mouse_move = React26.useCallback(
|
|
9985
|
-
(e) => {
|
|
9986
|
-
if (!geo) return;
|
|
9987
|
-
const rect = e.currentTarget.getBoundingClientRect();
|
|
9988
|
-
if (rect.width === 0) return;
|
|
9989
|
-
const vbox_x = (e.clientX - rect.left) / rect.width * geo.vbox_w;
|
|
9990
|
-
const plot_w = geo.vbox_w - PAD_LEFT2 - PAD_RIGHT2;
|
|
9991
|
-
if (vbox_x < PAD_LEFT2 || vbox_x > geo.vbox_w - PAD_RIGHT2) {
|
|
9992
|
-
set_hover_idx(null);
|
|
9993
|
-
return;
|
|
9994
|
-
}
|
|
9995
|
-
const ratio = (vbox_x - PAD_LEFT2) / plot_w;
|
|
9996
|
-
const idx = Math.round(ratio * (geo.point_count - 1));
|
|
9997
|
-
set_hover_idx(Math.max(0, Math.min(geo.point_count - 1, idx)));
|
|
9998
|
-
},
|
|
9999
|
-
[geo]
|
|
10000
|
-
);
|
|
10001
|
-
const handle_mouse_leave = React26.useCallback(() => set_hover_idx(null), []);
|
|
10002
|
-
if (!geo) {
|
|
10003
|
-
return /* @__PURE__ */ jsx(
|
|
10004
|
-
"svg",
|
|
10005
|
-
{
|
|
10006
|
-
viewBox: `0 0 ${width} ${height}`,
|
|
10007
|
-
className: cn("cls_hazo_chart cls_hazo_chart_empty", className),
|
|
10008
|
-
style: { width: "100%", height: "auto", display: "block", maxHeight: `${height + 10}px` }
|
|
10009
|
-
}
|
|
10010
|
-
);
|
|
10011
|
-
}
|
|
10012
|
-
const x_label_idx = pick_x_label_indices(geo.point_count);
|
|
10013
|
-
return /* @__PURE__ */ jsxs("div", { className: cn("cls_hazo_chart_wrapper", className), children: [
|
|
10014
|
-
/* @__PURE__ */ jsxs(
|
|
10015
|
-
"svg",
|
|
10016
|
-
{
|
|
10017
|
-
viewBox: `0 0 ${width} ${height}`,
|
|
10018
|
-
onMouseMove: showTooltip ? handle_mouse_move : void 0,
|
|
10019
|
-
onMouseLeave: showTooltip ? handle_mouse_leave : void 0,
|
|
10020
|
-
className: "cls_hazo_chart cls_hazo_chart_multi",
|
|
10021
|
-
style: {
|
|
10022
|
-
width: "100%",
|
|
10023
|
-
height: "auto",
|
|
10024
|
-
display: "block",
|
|
10025
|
-
maxHeight: `${height + 10}px`,
|
|
10026
|
-
cursor: showTooltip ? "crosshair" : "default"
|
|
10027
|
-
},
|
|
10028
|
-
children: [
|
|
10029
|
-
[0, 1, 2].map((i) => {
|
|
10030
|
-
const y = PAD_TOP2 + i / 2 * (geo.vbox_h - PAD_TOP2 - PAD_BOTTOM2);
|
|
10031
|
-
return /* @__PURE__ */ jsx(
|
|
10032
|
-
"line",
|
|
10033
|
-
{
|
|
10034
|
-
x1: PAD_LEFT2,
|
|
10035
|
-
x2: geo.vbox_w - PAD_RIGHT2,
|
|
10036
|
-
y1: y,
|
|
10037
|
-
y2: y,
|
|
10038
|
-
stroke: GRIDLINE_COLOR2,
|
|
10039
|
-
strokeWidth: 0.5,
|
|
10040
|
-
strokeDasharray: "2,3"
|
|
10041
|
-
},
|
|
10042
|
-
i
|
|
10043
|
-
);
|
|
10044
|
-
}),
|
|
10045
|
-
/* @__PURE__ */ jsx("text", { x: PAD_LEFT2 - 4, y: PAD_TOP2 + 3, textAnchor: "end", fill: AXIS_LABEL_COLOR2, fontSize: 9, children: format_num(geo.y_max) }),
|
|
10046
|
-
/* @__PURE__ */ jsx(
|
|
10047
|
-
"text",
|
|
10048
|
-
{
|
|
10049
|
-
x: PAD_LEFT2 - 4,
|
|
10050
|
-
y: PAD_TOP2 + (geo.vbox_h - PAD_TOP2 - PAD_BOTTOM2) / 2 + 3,
|
|
10051
|
-
textAnchor: "end",
|
|
10052
|
-
fill: AXIS_LABEL_COLOR2,
|
|
10053
|
-
fontSize: 9,
|
|
10054
|
-
children: format_num((geo.y_max + geo.y_min) / 2)
|
|
10055
|
-
}
|
|
10056
|
-
),
|
|
10057
|
-
/* @__PURE__ */ 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) }),
|
|
10058
|
-
x_label_idx.map((idx, k) => {
|
|
10059
|
-
const anchor = k === 0 ? "start" : k === 1 ? "middle" : "end";
|
|
10060
|
-
return /* @__PURE__ */ jsx(
|
|
10061
|
-
"text",
|
|
10062
|
-
{
|
|
10063
|
-
x: geo.cx(idx),
|
|
10064
|
-
y: geo.vbox_h - 6,
|
|
10065
|
-
textAnchor: anchor,
|
|
10066
|
-
fill: AXIS_LABEL_COLOR2,
|
|
10067
|
-
fontSize: 9,
|
|
10068
|
-
children: dates[idx] ?? ""
|
|
10069
|
-
},
|
|
10070
|
-
`x_${k}`
|
|
10071
|
-
);
|
|
10072
|
-
}),
|
|
10073
|
-
series.map((s, s_idx) => {
|
|
10074
|
-
let d = "";
|
|
10075
|
-
s.data.forEach((v, i) => {
|
|
10076
|
-
if (v === null || Number.isNaN(v)) return;
|
|
10077
|
-
d += `${d ? " L" : "M"}${geo.cx(i).toFixed(1)},${geo.cy(v).toFixed(1)}`;
|
|
10078
|
-
});
|
|
10079
|
-
const last_idx = s.data.length - 1;
|
|
10080
|
-
const last_v = s.data[last_idx];
|
|
10081
|
-
const has_last = last_v !== null && last_v !== void 0 && !Number.isNaN(last_v);
|
|
10082
|
-
return /* @__PURE__ */ jsxs("g", { children: [
|
|
10083
|
-
d && /* @__PURE__ */ jsx("path", { d, stroke: s.color, strokeWidth: 1.7, fill: "none" }),
|
|
10084
|
-
has_last && hover_idx === null && /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
10085
|
-
/* @__PURE__ */ jsx(
|
|
10086
|
-
"circle",
|
|
10087
|
-
{
|
|
10088
|
-
cx: geo.cx(last_idx),
|
|
10089
|
-
cy: geo.cy(last_v),
|
|
10090
|
-
r: 3,
|
|
10091
|
-
fill: s.color,
|
|
10092
|
-
fillOpacity: 0.3,
|
|
10093
|
-
stroke: s.color,
|
|
10094
|
-
strokeWidth: 1.5
|
|
10095
|
-
}
|
|
10096
|
-
),
|
|
10097
|
-
/* @__PURE__ */ jsx(
|
|
10098
|
-
"text",
|
|
10099
|
-
{
|
|
10100
|
-
x: geo.cx(last_idx) - 5,
|
|
10101
|
-
y: geo.cy(last_v) - 5,
|
|
10102
|
-
textAnchor: "end",
|
|
10103
|
-
fill: s.color,
|
|
10104
|
-
fontSize: 9,
|
|
10105
|
-
fontWeight: 700,
|
|
10106
|
-
children: format_num(last_v)
|
|
10107
|
-
}
|
|
10108
|
-
)
|
|
10109
|
-
] })
|
|
10110
|
-
] }, `series_${s_idx}`);
|
|
10111
|
-
}),
|
|
10112
|
-
showTooltip && hover_idx !== null && (() => {
|
|
10113
|
-
const x = geo.cx(hover_idx);
|
|
10114
|
-
const items = series.map((s) => ({
|
|
10115
|
-
label: s.label,
|
|
10116
|
-
color: s.color,
|
|
10117
|
-
value: s.data[hover_idx] ?? null
|
|
10118
|
-
})).filter((it) => it.value !== null && !Number.isNaN(it.value));
|
|
10119
|
-
if (items.length === 0) return null;
|
|
10120
|
-
const bubble_w = 70;
|
|
10121
|
-
const row_h = 12;
|
|
10122
|
-
const bubble_h = items.length * row_h + 18;
|
|
10123
|
-
const flip = x + bubble_w + 6 > geo.vbox_w - PAD_RIGHT2;
|
|
10124
|
-
const bubble_x = flip ? x - bubble_w - 6 : x + 6;
|
|
10125
|
-
const bubble_y = Math.max(PAD_TOP2, Math.min(PAD_TOP2 + 5, geo.vbox_h - PAD_BOTTOM2 - bubble_h));
|
|
10126
|
-
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
10127
|
-
/* @__PURE__ */ jsx(
|
|
10128
|
-
"line",
|
|
10129
|
-
{
|
|
10130
|
-
x1: x,
|
|
10131
|
-
x2: x,
|
|
10132
|
-
y1: PAD_TOP2,
|
|
10133
|
-
y2: geo.vbox_h - PAD_BOTTOM2,
|
|
10134
|
-
stroke: AXIS_LABEL_COLOR2,
|
|
10135
|
-
strokeWidth: 0.5,
|
|
10136
|
-
strokeDasharray: "2,2",
|
|
10137
|
-
opacity: 0.6
|
|
10138
|
-
}
|
|
10139
|
-
),
|
|
10140
|
-
items.map((it) => /* @__PURE__ */ jsx(
|
|
10141
|
-
"circle",
|
|
10142
|
-
{
|
|
10143
|
-
cx: x,
|
|
10144
|
-
cy: geo.cy(it.value),
|
|
10145
|
-
r: 3,
|
|
10146
|
-
fill: it.color
|
|
10147
|
-
},
|
|
10148
|
-
`hd_${it.label}`
|
|
10149
|
-
)),
|
|
10150
|
-
/* @__PURE__ */ jsx(
|
|
10151
|
-
"rect",
|
|
10152
|
-
{
|
|
10153
|
-
x: bubble_x,
|
|
10154
|
-
y: bubble_y,
|
|
10155
|
-
width: bubble_w,
|
|
10156
|
-
height: bubble_h,
|
|
10157
|
-
rx: 3,
|
|
10158
|
-
fill: "#0d1117",
|
|
10159
|
-
stroke: AXIS_LABEL_COLOR2,
|
|
10160
|
-
strokeWidth: 0.5,
|
|
10161
|
-
fillOpacity: 0.92
|
|
10162
|
-
}
|
|
10163
|
-
),
|
|
10164
|
-
/* @__PURE__ */ jsx("text", { x: bubble_x + 6, y: bubble_y + 10, fill: AXIS_LABEL_COLOR2, fontSize: 8, children: dates[hover_idx] ?? "" }),
|
|
10165
|
-
items.map((it, i) => /* @__PURE__ */ jsxs("g", { children: [
|
|
10166
|
-
/* @__PURE__ */ jsx(
|
|
10167
|
-
"rect",
|
|
10168
|
-
{
|
|
10169
|
-
x: bubble_x + 6,
|
|
10170
|
-
y: bubble_y + 14 + i * row_h,
|
|
10171
|
-
width: 6,
|
|
10172
|
-
height: 6,
|
|
10173
|
-
fill: it.color
|
|
10174
|
-
}
|
|
10175
|
-
),
|
|
10176
|
-
/* @__PURE__ */ jsx(
|
|
10177
|
-
"text",
|
|
10178
|
-
{
|
|
10179
|
-
x: bubble_x + 16,
|
|
10180
|
-
y: bubble_y + 20 + i * row_h,
|
|
10181
|
-
fill: it.color,
|
|
10182
|
-
fontSize: 9,
|
|
10183
|
-
fontWeight: 600,
|
|
10184
|
-
children: format_num(it.value)
|
|
10185
|
-
}
|
|
10186
|
-
)
|
|
10187
|
-
] }, `row_${i}`))
|
|
10188
|
-
] });
|
|
10189
|
-
})()
|
|
10190
|
-
]
|
|
10191
|
-
}
|
|
10192
|
-
),
|
|
10193
|
-
showLegend && /* @__PURE__ */ jsx(
|
|
10194
|
-
"div",
|
|
10195
|
-
{
|
|
10196
|
-
className: "cls_hazo_chart_legend",
|
|
10197
|
-
style: {
|
|
10198
|
-
display: "flex",
|
|
10199
|
-
gap: "12px",
|
|
10200
|
-
justifyContent: "center",
|
|
10201
|
-
marginTop: "4px",
|
|
10202
|
-
fontSize: "10px",
|
|
10203
|
-
color: AXIS_LABEL_COLOR2,
|
|
10204
|
-
flexWrap: "wrap"
|
|
10205
|
-
},
|
|
10206
|
-
children: series.map((s) => /* @__PURE__ */ jsxs(
|
|
10207
|
-
"span",
|
|
10208
|
-
{
|
|
10209
|
-
style: { display: "inline-flex", alignItems: "center", gap: "4px" },
|
|
10210
|
-
children: [
|
|
10211
|
-
/* @__PURE__ */ jsx(
|
|
10212
|
-
"i",
|
|
10213
|
-
{
|
|
10214
|
-
style: {
|
|
10215
|
-
display: "inline-block",
|
|
10216
|
-
width: "8px",
|
|
10217
|
-
height: "8px",
|
|
10218
|
-
background: s.color,
|
|
10219
|
-
borderRadius: "1px"
|
|
10220
|
-
}
|
|
10221
|
-
}
|
|
10222
|
-
),
|
|
10223
|
-
s.label
|
|
10224
|
-
]
|
|
10225
|
-
},
|
|
10226
|
-
s.label
|
|
10227
|
-
))
|
|
10228
|
-
}
|
|
10229
|
-
)
|
|
10230
|
-
] });
|
|
10231
|
-
}
|
|
10232
|
-
var PAD_LEFT3 = 32;
|
|
10233
|
-
var PAD_RIGHT3 = 8;
|
|
10234
|
-
var PAD_TOP3 = 10;
|
|
10235
|
-
var PAD_BOTTOM3 = 22;
|
|
10236
9913
|
var BAR_GAP_RATIO = 0.25;
|
|
10237
|
-
var
|
|
9914
|
+
var AXIS_LABEL_COLOR = "#8b949e";
|
|
10238
9915
|
function StackedBars({
|
|
10239
9916
|
bars,
|
|
10240
9917
|
width = 360,
|
|
@@ -10244,11 +9921,11 @@ function StackedBars({
|
|
|
10244
9921
|
}) {
|
|
10245
9922
|
const totals = bars.map((b) => b.segments.reduce((sum, s) => sum + s.value, 0));
|
|
10246
9923
|
const y_max = Math.max(0, ...totals) || 1;
|
|
10247
|
-
const plot_w = width -
|
|
10248
|
-
const plot_h = height -
|
|
9924
|
+
const plot_w = width - PAD_LEFT - PAD_RIGHT;
|
|
9925
|
+
const plot_h = height - PAD_TOP - PAD_BOTTOM;
|
|
10249
9926
|
const slot_w = bars.length > 0 ? plot_w / bars.length : 0;
|
|
10250
9927
|
const bar_w = slot_w * (1 - BAR_GAP_RATIO);
|
|
10251
|
-
const x_for = (i) =>
|
|
9928
|
+
const x_for = (i) => PAD_LEFT + i * slot_w + (slot_w - bar_w) / 2;
|
|
10252
9929
|
const x_label_idx = pick_x_label_indices(bars.length);
|
|
10253
9930
|
return /* @__PURE__ */ jsxs(
|
|
10254
9931
|
"svg",
|
|
@@ -10258,14 +9935,14 @@ function StackedBars({
|
|
|
10258
9935
|
style: { width: "100%", height: "auto", display: "block", maxHeight: `${height + 10}px` },
|
|
10259
9936
|
children: [
|
|
10260
9937
|
showYAxis && /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
10261
|
-
/* @__PURE__ */ jsx("text", { x:
|
|
9938
|
+
/* @__PURE__ */ jsx("text", { x: PAD_LEFT - 4, y: PAD_TOP + 3, textAnchor: "end", fill: AXIS_LABEL_COLOR, fontSize: 9, children: format_num(y_max) }),
|
|
10262
9939
|
/* @__PURE__ */ jsx(
|
|
10263
9940
|
"text",
|
|
10264
9941
|
{
|
|
10265
|
-
x:
|
|
10266
|
-
y:
|
|
9942
|
+
x: PAD_LEFT - 4,
|
|
9943
|
+
y: PAD_TOP + plot_h / 2 + 3,
|
|
10267
9944
|
textAnchor: "end",
|
|
10268
|
-
fill:
|
|
9945
|
+
fill: AXIS_LABEL_COLOR,
|
|
10269
9946
|
fontSize: 9,
|
|
10270
9947
|
children: format_num(y_max / 2)
|
|
10271
9948
|
}
|
|
@@ -10273,17 +9950,17 @@ function StackedBars({
|
|
|
10273
9950
|
/* @__PURE__ */ jsx(
|
|
10274
9951
|
"text",
|
|
10275
9952
|
{
|
|
10276
|
-
x:
|
|
10277
|
-
y: height -
|
|
9953
|
+
x: PAD_LEFT - 4,
|
|
9954
|
+
y: height - PAD_BOTTOM + 3,
|
|
10278
9955
|
textAnchor: "end",
|
|
10279
|
-
fill:
|
|
9956
|
+
fill: AXIS_LABEL_COLOR,
|
|
10280
9957
|
fontSize: 9,
|
|
10281
9958
|
children: "0"
|
|
10282
9959
|
}
|
|
10283
9960
|
)
|
|
10284
9961
|
] }),
|
|
10285
9962
|
bars.map((bar, i) => {
|
|
10286
|
-
let cursor_y = height -
|
|
9963
|
+
let cursor_y = height - PAD_BOTTOM;
|
|
10287
9964
|
return /* @__PURE__ */ jsx("g", { children: bar.segments.map((seg, s_idx) => {
|
|
10288
9965
|
if (seg.value <= 0) return null;
|
|
10289
9966
|
const seg_h = seg.value / y_max * plot_h;
|
|
@@ -10311,7 +9988,7 @@ function StackedBars({
|
|
|
10311
9988
|
x: x_pos,
|
|
10312
9989
|
y: height - 6,
|
|
10313
9990
|
textAnchor: anchor,
|
|
10314
|
-
fill:
|
|
9991
|
+
fill: AXIS_LABEL_COLOR,
|
|
10315
9992
|
fontSize: 9,
|
|
10316
9993
|
children: bars[idx]?.label ?? ""
|
|
10317
9994
|
},
|
|
@@ -10360,15 +10037,15 @@ function DateRangeSelector({
|
|
|
10360
10037
|
}
|
|
10361
10038
|
);
|
|
10362
10039
|
}
|
|
10363
|
-
var
|
|
10364
|
-
var
|
|
10365
|
-
var
|
|
10366
|
-
var
|
|
10040
|
+
var PAD_LEFT2 = 80;
|
|
10041
|
+
var PAD_RIGHT2 = 72;
|
|
10042
|
+
var PAD_TOP2 = 12;
|
|
10043
|
+
var PAD_BOTTOM2 = 12;
|
|
10367
10044
|
var ROW_H = 44;
|
|
10368
10045
|
var LABEL_H = 14;
|
|
10369
10046
|
var BAR_H = 22;
|
|
10370
|
-
var
|
|
10371
|
-
var
|
|
10047
|
+
var AXIS_LABEL_COLOR2 = "#8b949e";
|
|
10048
|
+
var GRIDLINE_COLOR = "#2a3441";
|
|
10372
10049
|
function step_total(step) {
|
|
10373
10050
|
if (step.value !== void 0) return step.value;
|
|
10374
10051
|
if (step.segments) return step.segments.reduce((s, g) => s + g.value, 0);
|
|
@@ -10388,15 +10065,15 @@ function FunnelChart({
|
|
|
10388
10065
|
const fmt = valueFormat ?? format_num;
|
|
10389
10066
|
const totals = steps.map(step_total);
|
|
10390
10067
|
const value_max = Math.max(1, ...totals);
|
|
10391
|
-
const plot_w = width -
|
|
10392
|
-
const vbox_h = height ??
|
|
10068
|
+
const plot_w = width - PAD_LEFT2 - PAD_RIGHT2;
|
|
10069
|
+
const vbox_h = height ?? PAD_TOP2 + steps.length * ROW_H + PAD_BOTTOM2;
|
|
10393
10070
|
const handle_mouse_move = React26.useCallback(
|
|
10394
10071
|
(e) => {
|
|
10395
10072
|
if (steps.length === 0) return;
|
|
10396
10073
|
const rect = e.currentTarget.getBoundingClientRect();
|
|
10397
10074
|
if (rect.height === 0) return;
|
|
10398
10075
|
const vbox_y = (e.clientY - rect.top) / rect.height * vbox_h;
|
|
10399
|
-
const row_idx = Math.floor((vbox_y -
|
|
10076
|
+
const row_idx = Math.floor((vbox_y - PAD_TOP2) / ROW_H);
|
|
10400
10077
|
if (row_idx < 0 || row_idx >= steps.length) {
|
|
10401
10078
|
set_hover_idx(null);
|
|
10402
10079
|
return;
|
|
@@ -10423,11 +10100,11 @@ function FunnelChart({
|
|
|
10423
10100
|
steps.length > 0 && /* @__PURE__ */ jsx(
|
|
10424
10101
|
"line",
|
|
10425
10102
|
{
|
|
10426
|
-
x1:
|
|
10427
|
-
x2:
|
|
10428
|
-
y1:
|
|
10429
|
-
y2:
|
|
10430
|
-
stroke:
|
|
10103
|
+
x1: PAD_LEFT2 + plot_w / 2,
|
|
10104
|
+
x2: PAD_LEFT2 + plot_w / 2,
|
|
10105
|
+
y1: PAD_TOP2,
|
|
10106
|
+
y2: PAD_TOP2 + steps.length * ROW_H,
|
|
10107
|
+
stroke: GRIDLINE_COLOR,
|
|
10431
10108
|
strokeWidth: 0.5,
|
|
10432
10109
|
strokeDasharray: "2,3"
|
|
10433
10110
|
}
|
|
@@ -10435,8 +10112,8 @@ function FunnelChart({
|
|
|
10435
10112
|
steps.map((step, i) => {
|
|
10436
10113
|
const total = totals[i];
|
|
10437
10114
|
const bar_w = total / value_max * plot_w;
|
|
10438
|
-
const bar_x =
|
|
10439
|
-
const bar_y =
|
|
10115
|
+
const bar_x = PAD_LEFT2 + (plot_w - bar_w) / 2;
|
|
10116
|
+
const bar_y = PAD_TOP2 + i * ROW_H + LABEL_H;
|
|
10440
10117
|
const pct_first = i === 0 ? 100 : Math.round(total / (totals[0] || 1) * 100);
|
|
10441
10118
|
const value_label = i === 0 ? `${fmt(total)} (100%)` : `${fmt(total)} (${pct_first}%)`;
|
|
10442
10119
|
const dropoff = i > 0 ? totals[i - 1] - total : 0;
|
|
@@ -10445,10 +10122,10 @@ function FunnelChart({
|
|
|
10445
10122
|
/* @__PURE__ */ jsx(
|
|
10446
10123
|
"text",
|
|
10447
10124
|
{
|
|
10448
|
-
x:
|
|
10125
|
+
x: PAD_LEFT2 - 6,
|
|
10449
10126
|
y: bar_y + BAR_H / 2 + 4,
|
|
10450
10127
|
textAnchor: "end",
|
|
10451
|
-
fill:
|
|
10128
|
+
fill: AXIS_LABEL_COLOR2,
|
|
10452
10129
|
fontSize: 9,
|
|
10453
10130
|
children: step.label
|
|
10454
10131
|
}
|
|
@@ -10490,7 +10167,7 @@ function FunnelChart({
|
|
|
10490
10167
|
x: label_x,
|
|
10491
10168
|
y: bar_y + BAR_H / 2 + 10,
|
|
10492
10169
|
textAnchor: "start",
|
|
10493
|
-
fill:
|
|
10170
|
+
fill: AXIS_LABEL_COLOR2,
|
|
10494
10171
|
fontSize: 8,
|
|
10495
10172
|
children: `\u2212${fmt(dropoff)}`
|
|
10496
10173
|
}
|
|
@@ -10505,8 +10182,8 @@ function FunnelChart({
|
|
|
10505
10182
|
const pct_prev = i === 0 ? 100 : Math.round(total / (totals[i - 1] || 1) * 100);
|
|
10506
10183
|
const dropoff = i > 0 ? totals[i - 1] - total : 0;
|
|
10507
10184
|
const bar_w = total / value_max * plot_w;
|
|
10508
|
-
const bar_x =
|
|
10509
|
-
const bar_y =
|
|
10185
|
+
const bar_x = PAD_LEFT2 + (plot_w - bar_w) / 2;
|
|
10186
|
+
const bar_y = PAD_TOP2 + i * ROW_H + LABEL_H;
|
|
10510
10187
|
const bubble_anchor_y = bar_y + BAR_H / 2;
|
|
10511
10188
|
const lines = [
|
|
10512
10189
|
{ text: step.label, accent: true },
|
|
@@ -10560,7 +10237,7 @@ function FunnelChart({
|
|
|
10560
10237
|
{
|
|
10561
10238
|
x: bubble_x + 7,
|
|
10562
10239
|
y: bubble_y + pad_v + k * line_h + line_h * 0.75,
|
|
10563
|
-
fill: line.accent ? color2 :
|
|
10240
|
+
fill: line.accent ? color2 : AXIS_LABEL_COLOR2,
|
|
10564
10241
|
fontSize: line.accent ? 10 : 8,
|
|
10565
10242
|
fontWeight: line.accent ? 700 : 400,
|
|
10566
10243
|
children: line.text
|
|
@@ -11030,6 +10707,6 @@ function HazoUiEtaProgress({
|
|
|
11030
10707
|
);
|
|
11031
10708
|
}
|
|
11032
10709
|
|
|
11033
|
-
export { ANIMATION_PRESETS, Accordion, AccordionContent, AccordionItem, AccordionTrigger, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, Button, ButtonGroup, ButtonGroupSeparator, ButtonGroupText, CELEBRATION_GRADIENT, Calendar, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CelebrationProvider, Checkbox, Collapsible, CollapsibleContent2 as CollapsibleContent, CollapsibleTrigger2 as CollapsibleTrigger, CommandNodeExtension, CommandPill, CommandPopover, DateRangeSelector, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, ErrorBanner, ErrorPage, FunnelChart, HazoContextProvider, HazoUiConfirmDialog, HazoUiDialog, DialogClose as HazoUiDialogClose, DialogContent as HazoUiDialogContent, DialogDescription as HazoUiDialogDescription, DialogFooter as HazoUiDialogFooter, DialogHeader as HazoUiDialogHeader, DialogOverlay as HazoUiDialogOverlay, DialogPortal as HazoUiDialogPortal, Dialog as HazoUiDialogRoot, DialogTitle as HazoUiDialogTitle, DialogTrigger as HazoUiDialogTrigger, HazoUiEtaProgress, HazoUiFlexInput, HazoUiFlexRadio, HazoUiKanban, HazoUiKanbanFilter, HazoUiMultiFilterDialog, HazoUiMultiSortDialog, HazoUiPillRadio, HazoUiProgressBar, HazoUiRte, HazoUiTable, HazoUiTextarea, HazoUiTextbox, HazoUiToaster, HoverCard, HoverCardContent, HoverCardTrigger, Input, InverseSparkline, Label3 as Label,
|
|
10710
|
+
export { ANIMATION_PRESETS, Accordion, AccordionContent, AccordionItem, AccordionTrigger, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, Button, ButtonGroup, ButtonGroupSeparator, ButtonGroupText, CELEBRATION_GRADIENT, Calendar, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CelebrationProvider, Checkbox, Collapsible, CollapsibleContent2 as CollapsibleContent, CollapsibleTrigger2 as CollapsibleTrigger, CommandNodeExtension, CommandPill, CommandPopover, DateRangeSelector, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, ErrorBanner, ErrorPage, FunnelChart, HazoContextProvider, HazoUiConfirmDialog, HazoUiDialog, DialogClose as HazoUiDialogClose, DialogContent as HazoUiDialogContent, DialogDescription as HazoUiDialogDescription, DialogFooter as HazoUiDialogFooter, DialogHeader as HazoUiDialogHeader, DialogOverlay as HazoUiDialogOverlay, DialogPortal as HazoUiDialogPortal, Dialog as HazoUiDialogRoot, DialogTitle as HazoUiDialogTitle, DialogTrigger as HazoUiDialogTrigger, HazoUiEtaProgress, HazoUiFlexInput, HazoUiFlexRadio, HazoUiImageCropper, HazoUiImageCropperDialog, HazoUiKanban, HazoUiKanbanFilter, HazoUiMultiFilterDialog, HazoUiMultiSortDialog, HazoUiPillRadio, HazoUiProgressBar, HazoUiRte, HazoUiTable, HazoUiTextarea, HazoUiTextbox, HazoUiToaster, HoverCard, HoverCardContent, HoverCardTrigger, Input, InputAffix, InverseSparkline, Label3 as Label, LoadingTimeout, MarkdownEditor, Popover, PopoverContent, PopoverTrigger, ProgressiveImage, RadioGroup, RadioGroupItem, ScrollArea, ScrollBar, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator3 as Separator, Command as ShadcnCommand, CommandEmpty as ShadcnCommandEmpty, CommandGroup as ShadcnCommandGroup, CommandInput as ShadcnCommandInput, CommandItem as ShadcnCommandItem, CommandList as ShadcnCommandList, Skeleton, SkeletonBar, SkeletonCircle, SkeletonGroup, SkeletonRect, Slider, Sparkline, Spinner, StackedBars, Switch, Table2 as Table, TableBody, TableCaption, TableCell2 as TableCell, TableFooter, TableHead, TableHeader2 as TableHeader, TableRow2 as TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, applyKanbanFilter, buttonGroupVariants, celebrate, cn, computeEta, create_command_suggestion_extension, easeToward, errorToast, format_num, generateUUID, get_hazo_ui_config, get_logger, median, parse_commands_from_text, pick_x_label_indices, reset_hazo_ui_config, resolve_animation_classes, set_hazo_ui_config, set_logger, successToast, text_to_tiptap_content, toggleVariants, useClickOutside, useCopyToClipboard, useDebounce, useErrorDisplay, useEtaProgress, useFullscreen, useIsMobile, useLoadingState, useLocalStorage, useMediaQuery, useSessionStorage, useViewport, useWakeLock, use_fullscreen, use_wake_lock };
|
|
11034
10711
|
//# sourceMappingURL=index.js.map
|
|
11035
10712
|
//# sourceMappingURL=index.js.map
|