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.cjs
CHANGED
|
@@ -42,7 +42,7 @@ var Link = require('@tiptap/extension-link');
|
|
|
42
42
|
var TextAlign = require('@tiptap/extension-text-align');
|
|
43
43
|
var Highlight = require('@tiptap/extension-highlight');
|
|
44
44
|
var Color = require('@tiptap/extension-color');
|
|
45
|
-
var
|
|
45
|
+
var Image2 = require('@tiptap/extension-image');
|
|
46
46
|
var Placeholder = require('@tiptap/extension-placeholder');
|
|
47
47
|
var HorizontalRule = require('@tiptap/extension-horizontal-rule');
|
|
48
48
|
var extensionTable = require('@tiptap/extension-table');
|
|
@@ -61,6 +61,8 @@ require('@uiw/react-markdown-preview/markdown.css');
|
|
|
61
61
|
var Suggestion = require('@tiptap/suggestion');
|
|
62
62
|
var state = require('@tiptap/pm/state');
|
|
63
63
|
var reactDom = require('react-dom');
|
|
64
|
+
var Cropper = require('react-easy-crop');
|
|
65
|
+
var SliderPrimitive = require('@radix-ui/react-slider');
|
|
64
66
|
var vaul = require('vaul');
|
|
65
67
|
var AccordionPrimitive = require('@radix-ui/react-accordion');
|
|
66
68
|
var CheckboxPrimitive = require('@radix-ui/react-checkbox');
|
|
@@ -122,7 +124,7 @@ var Link__default = /*#__PURE__*/_interopDefault(Link);
|
|
|
122
124
|
var TextAlign__default = /*#__PURE__*/_interopDefault(TextAlign);
|
|
123
125
|
var Highlight__default = /*#__PURE__*/_interopDefault(Highlight);
|
|
124
126
|
var Color__default = /*#__PURE__*/_interopDefault(Color);
|
|
125
|
-
var
|
|
127
|
+
var Image2__default = /*#__PURE__*/_interopDefault(Image2);
|
|
126
128
|
var Placeholder__default = /*#__PURE__*/_interopDefault(Placeholder);
|
|
127
129
|
var HorizontalRule__default = /*#__PURE__*/_interopDefault(HorizontalRule);
|
|
128
130
|
var TableRow__default = /*#__PURE__*/_interopDefault(TableRow);
|
|
@@ -132,6 +134,8 @@ var TaskList__default = /*#__PURE__*/_interopDefault(TaskList);
|
|
|
132
134
|
var TaskItem__default = /*#__PURE__*/_interopDefault(TaskItem);
|
|
133
135
|
var TabsPrimitive__namespace = /*#__PURE__*/_interopNamespace(TabsPrimitive);
|
|
134
136
|
var Suggestion__default = /*#__PURE__*/_interopDefault(Suggestion);
|
|
137
|
+
var Cropper__default = /*#__PURE__*/_interopDefault(Cropper);
|
|
138
|
+
var SliderPrimitive__namespace = /*#__PURE__*/_interopNamespace(SliderPrimitive);
|
|
135
139
|
var AccordionPrimitive__namespace = /*#__PURE__*/_interopNamespace(AccordionPrimitive);
|
|
136
140
|
var CheckboxPrimitive__namespace = /*#__PURE__*/_interopNamespace(CheckboxPrimitive);
|
|
137
141
|
var DropdownMenuPrimitive__namespace = /*#__PURE__*/_interopNamespace(DropdownMenuPrimitive);
|
|
@@ -4364,7 +4368,7 @@ var HazoUiRte = ({
|
|
|
4364
4368
|
multicolor: true
|
|
4365
4369
|
}),
|
|
4366
4370
|
Color__default.default,
|
|
4367
|
-
|
|
4371
|
+
Image2__default.default.configure({
|
|
4368
4372
|
inline: true,
|
|
4369
4373
|
allowBase64: true,
|
|
4370
4374
|
HTMLAttributes: {
|
|
@@ -6912,6 +6916,210 @@ function HazoUiConfirmDialog({
|
|
|
6912
6916
|
)
|
|
6913
6917
|
] }) });
|
|
6914
6918
|
}
|
|
6919
|
+
var Slider = React26__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6920
|
+
SliderPrimitive__namespace.Root,
|
|
6921
|
+
{
|
|
6922
|
+
ref,
|
|
6923
|
+
className: cn("relative flex w-full touch-none select-none items-center", className),
|
|
6924
|
+
...props,
|
|
6925
|
+
children: [
|
|
6926
|
+
/* @__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" }) }),
|
|
6927
|
+
/* @__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" })
|
|
6928
|
+
]
|
|
6929
|
+
}
|
|
6930
|
+
));
|
|
6931
|
+
Slider.displayName = SliderPrimitive__namespace.Root.displayName;
|
|
6932
|
+
async function getCroppedImg(imageSrc, areaPixels, outputSize, quality) {
|
|
6933
|
+
const img = await new Promise((resolve, reject) => {
|
|
6934
|
+
const image = new Image();
|
|
6935
|
+
image.crossOrigin = "anonymous";
|
|
6936
|
+
image.onload = () => resolve(image);
|
|
6937
|
+
image.onerror = (e) => reject(e);
|
|
6938
|
+
image.src = imageSrc;
|
|
6939
|
+
});
|
|
6940
|
+
const canvas = document.createElement("canvas");
|
|
6941
|
+
canvas.width = outputSize;
|
|
6942
|
+
canvas.height = outputSize;
|
|
6943
|
+
const ctx = canvas.getContext("2d");
|
|
6944
|
+
if (!ctx) {
|
|
6945
|
+
throw new Error("HazoUiImageCropper: canvas 2d context unavailable");
|
|
6946
|
+
}
|
|
6947
|
+
ctx.drawImage(
|
|
6948
|
+
img,
|
|
6949
|
+
areaPixels.x,
|
|
6950
|
+
areaPixels.y,
|
|
6951
|
+
areaPixels.width,
|
|
6952
|
+
areaPixels.height,
|
|
6953
|
+
0,
|
|
6954
|
+
0,
|
|
6955
|
+
outputSize,
|
|
6956
|
+
outputSize
|
|
6957
|
+
);
|
|
6958
|
+
return new Promise((resolve, reject) => {
|
|
6959
|
+
canvas.toBlob(
|
|
6960
|
+
(blob) => {
|
|
6961
|
+
if (blob) {
|
|
6962
|
+
resolve(blob);
|
|
6963
|
+
} else {
|
|
6964
|
+
reject(new Error("HazoUiImageCropper: canvas.toBlob returned null"));
|
|
6965
|
+
}
|
|
6966
|
+
},
|
|
6967
|
+
"image/webp",
|
|
6968
|
+
quality
|
|
6969
|
+
);
|
|
6970
|
+
});
|
|
6971
|
+
}
|
|
6972
|
+
var HazoUiImageCropper = React26__namespace.forwardRef(function HazoUiImageCropper2({
|
|
6973
|
+
imageSrc,
|
|
6974
|
+
onCropped,
|
|
6975
|
+
outputSize = 512,
|
|
6976
|
+
quality = 0.9,
|
|
6977
|
+
zoomLabel = "Zoom",
|
|
6978
|
+
className
|
|
6979
|
+
}, ref) {
|
|
6980
|
+
const [crop, set_crop] = React26__namespace.useState({
|
|
6981
|
+
x: 0,
|
|
6982
|
+
y: 0
|
|
6983
|
+
});
|
|
6984
|
+
const [zoom, set_zoom] = React26__namespace.useState(1);
|
|
6985
|
+
const cropped_area_pixels_ref = React26__namespace.useRef(null);
|
|
6986
|
+
const handle_crop_complete = React26__namespace.useCallback(
|
|
6987
|
+
(_croppedArea, croppedAreaPixels) => {
|
|
6988
|
+
cropped_area_pixels_ref.current = croppedAreaPixels;
|
|
6989
|
+
},
|
|
6990
|
+
[]
|
|
6991
|
+
);
|
|
6992
|
+
React26__namespace.useImperativeHandle(
|
|
6993
|
+
ref,
|
|
6994
|
+
() => ({
|
|
6995
|
+
getCroppedBlob: async () => {
|
|
6996
|
+
if (!cropped_area_pixels_ref.current) {
|
|
6997
|
+
throw new Error(
|
|
6998
|
+
"HazoUiImageCropper: crop area not yet initialised \u2014 wait for the cropper to mount before calling getCroppedBlob."
|
|
6999
|
+
);
|
|
7000
|
+
}
|
|
7001
|
+
const blob = await getCroppedImg(
|
|
7002
|
+
imageSrc,
|
|
7003
|
+
cropped_area_pixels_ref.current,
|
|
7004
|
+
outputSize,
|
|
7005
|
+
quality
|
|
7006
|
+
);
|
|
7007
|
+
await onCropped?.(blob);
|
|
7008
|
+
return blob;
|
|
7009
|
+
}
|
|
7010
|
+
}),
|
|
7011
|
+
[imageSrc, onCropped, outputSize, quality]
|
|
7012
|
+
);
|
|
7013
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("cls_image_cropper_root flex flex-col gap-4", className), children: [
|
|
7014
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7015
|
+
"div",
|
|
7016
|
+
{
|
|
7017
|
+
className: "cls_cropper_stage relative w-full overflow-hidden rounded-lg bg-muted",
|
|
7018
|
+
style: { height: "320px" },
|
|
7019
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
7020
|
+
Cropper__default.default,
|
|
7021
|
+
{
|
|
7022
|
+
image: imageSrc,
|
|
7023
|
+
crop,
|
|
7024
|
+
zoom,
|
|
7025
|
+
aspect: 1,
|
|
7026
|
+
cropShape: "round",
|
|
7027
|
+
showGrid: false,
|
|
7028
|
+
onCropChange: set_crop,
|
|
7029
|
+
onZoomChange: set_zoom,
|
|
7030
|
+
onCropComplete: handle_crop_complete
|
|
7031
|
+
}
|
|
7032
|
+
)
|
|
7033
|
+
}
|
|
7034
|
+
),
|
|
7035
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "cls_zoom_control flex flex-col gap-1.5", children: [
|
|
7036
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7037
|
+
"label",
|
|
7038
|
+
{
|
|
7039
|
+
className: "cls_zoom_label text-sm font-medium text-foreground",
|
|
7040
|
+
id: "hazo-cropper-zoom-label",
|
|
7041
|
+
children: zoomLabel
|
|
7042
|
+
}
|
|
7043
|
+
),
|
|
7044
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7045
|
+
Slider,
|
|
7046
|
+
{
|
|
7047
|
+
"aria-labelledby": "hazo-cropper-zoom-label",
|
|
7048
|
+
min: 1,
|
|
7049
|
+
max: 3,
|
|
7050
|
+
step: 0.1,
|
|
7051
|
+
value: [zoom],
|
|
7052
|
+
onValueChange: (values) => set_zoom(values[0])
|
|
7053
|
+
}
|
|
7054
|
+
)
|
|
7055
|
+
] })
|
|
7056
|
+
] });
|
|
7057
|
+
});
|
|
7058
|
+
HazoUiImageCropper.displayName = "HazoUiImageCropper";
|
|
7059
|
+
function HazoUiImageCropperDialog({
|
|
7060
|
+
open,
|
|
7061
|
+
onOpenChange,
|
|
7062
|
+
file,
|
|
7063
|
+
onConfirm,
|
|
7064
|
+
onCancel,
|
|
7065
|
+
title = "Crop photo",
|
|
7066
|
+
confirmLabel = "Save",
|
|
7067
|
+
cancelLabel = "Cancel",
|
|
7068
|
+
zoomLabel = "Zoom",
|
|
7069
|
+
outputSize = 512,
|
|
7070
|
+
quality = 0.9
|
|
7071
|
+
}) {
|
|
7072
|
+
const cropper_ref = React26__namespace.useRef(null);
|
|
7073
|
+
const [image_src, set_image_src] = React26__namespace.useState(null);
|
|
7074
|
+
const [is_confirming, set_is_confirming] = React26__namespace.useState(false);
|
|
7075
|
+
React26__namespace.useEffect(() => {
|
|
7076
|
+
if (!file) {
|
|
7077
|
+
set_image_src(null);
|
|
7078
|
+
return;
|
|
7079
|
+
}
|
|
7080
|
+
const url = URL.createObjectURL(file);
|
|
7081
|
+
set_image_src(url);
|
|
7082
|
+
return () => {
|
|
7083
|
+
URL.revokeObjectURL(url);
|
|
7084
|
+
};
|
|
7085
|
+
}, [file]);
|
|
7086
|
+
const handle_confirm = async () => {
|
|
7087
|
+
if (!cropper_ref.current) return;
|
|
7088
|
+
set_is_confirming(true);
|
|
7089
|
+
try {
|
|
7090
|
+
const blob = await cropper_ref.current.getCroppedBlob();
|
|
7091
|
+
await onConfirm(blob);
|
|
7092
|
+
onOpenChange(false);
|
|
7093
|
+
} finally {
|
|
7094
|
+
set_is_confirming(false);
|
|
7095
|
+
}
|
|
7096
|
+
};
|
|
7097
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
7098
|
+
HazoUiDialog,
|
|
7099
|
+
{
|
|
7100
|
+
open,
|
|
7101
|
+
onOpenChange,
|
|
7102
|
+
title,
|
|
7103
|
+
actionButtonText: confirmLabel,
|
|
7104
|
+
cancelButtonText: cancelLabel,
|
|
7105
|
+
onConfirm: handle_confirm,
|
|
7106
|
+
onCancel,
|
|
7107
|
+
actionButtonLoading: is_confirming,
|
|
7108
|
+
sizeWidth: "min(90vw, 520px)",
|
|
7109
|
+
contentClassName: "cls_image_cropper_dialog_body",
|
|
7110
|
+
children: image_src && /* @__PURE__ */ jsxRuntime.jsx(
|
|
7111
|
+
HazoUiImageCropper,
|
|
7112
|
+
{
|
|
7113
|
+
ref: cropper_ref,
|
|
7114
|
+
imageSrc: image_src,
|
|
7115
|
+
outputSize,
|
|
7116
|
+
quality,
|
|
7117
|
+
zoomLabel
|
|
7118
|
+
}
|
|
7119
|
+
)
|
|
7120
|
+
}
|
|
7121
|
+
);
|
|
7122
|
+
}
|
|
6915
7123
|
var Drawer = ({
|
|
6916
7124
|
shouldScaleBackground = true,
|
|
6917
7125
|
...props
|
|
@@ -7458,6 +7666,38 @@ function ButtonGroupText({ className, asChild = false, ...props }) {
|
|
|
7458
7666
|
function ButtonGroupSeparator({ className, orientation = "vertical", ...props }) {
|
|
7459
7667
|
return /* @__PURE__ */ jsxRuntime.jsx(Separator3, { orientation, className: cn("bg-input relative !m-0 self-stretch data-[orientation=vertical]:h-auto", className), ...props });
|
|
7460
7668
|
}
|
|
7669
|
+
var InputAffix = React26__namespace.forwardRef(
|
|
7670
|
+
({ className, containerClassName, prefix, suffix, type = "text", ...props }, ref) => {
|
|
7671
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7672
|
+
"div",
|
|
7673
|
+
{
|
|
7674
|
+
className: cn(
|
|
7675
|
+
"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",
|
|
7676
|
+
containerClassName
|
|
7677
|
+
),
|
|
7678
|
+
children: [
|
|
7679
|
+
prefix != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex select-none items-center pl-3 text-muted-foreground", children: prefix }),
|
|
7680
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7681
|
+
"input",
|
|
7682
|
+
{
|
|
7683
|
+
type,
|
|
7684
|
+
ref,
|
|
7685
|
+
className: cn(
|
|
7686
|
+
"h-full w-full bg-transparent px-3 py-2 outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
|
|
7687
|
+
prefix != null && "pl-2",
|
|
7688
|
+
suffix != null && "pr-2",
|
|
7689
|
+
className
|
|
7690
|
+
),
|
|
7691
|
+
...props
|
|
7692
|
+
}
|
|
7693
|
+
),
|
|
7694
|
+
suffix != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex select-none items-center pr-3 text-muted-foreground", children: suffix })
|
|
7695
|
+
]
|
|
7696
|
+
}
|
|
7697
|
+
);
|
|
7698
|
+
}
|
|
7699
|
+
);
|
|
7700
|
+
InputAffix.displayName = "InputAffix";
|
|
7461
7701
|
var SkeletonBase = React26__namespace.forwardRef(
|
|
7462
7702
|
({ className, ...rest }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
7463
7703
|
"div",
|
|
@@ -9736,573 +9976,12 @@ function pick_x_label_indices(length) {
|
|
|
9736
9976
|
if (length === 2) return [0, 0, 1];
|
|
9737
9977
|
return [0, Math.floor(length / 2), length - 1];
|
|
9738
9978
|
}
|
|
9739
|
-
var PAD_LEFT =
|
|
9740
|
-
var PAD_RIGHT =
|
|
9741
|
-
var PAD_TOP =
|
|
9979
|
+
var PAD_LEFT = 32;
|
|
9980
|
+
var PAD_RIGHT = 8;
|
|
9981
|
+
var PAD_TOP = 10;
|
|
9742
9982
|
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
9983
|
var BAR_GAP_RATIO = 0.25;
|
|
10305
|
-
var
|
|
9984
|
+
var AXIS_LABEL_COLOR = "#8b949e";
|
|
10306
9985
|
function StackedBars({
|
|
10307
9986
|
bars,
|
|
10308
9987
|
width = 360,
|
|
@@ -10312,11 +9991,11 @@ function StackedBars({
|
|
|
10312
9991
|
}) {
|
|
10313
9992
|
const totals = bars.map((b) => b.segments.reduce((sum, s) => sum + s.value, 0));
|
|
10314
9993
|
const y_max = Math.max(0, ...totals) || 1;
|
|
10315
|
-
const plot_w = width -
|
|
10316
|
-
const plot_h = height -
|
|
9994
|
+
const plot_w = width - PAD_LEFT - PAD_RIGHT;
|
|
9995
|
+
const plot_h = height - PAD_TOP - PAD_BOTTOM;
|
|
10317
9996
|
const slot_w = bars.length > 0 ? plot_w / bars.length : 0;
|
|
10318
9997
|
const bar_w = slot_w * (1 - BAR_GAP_RATIO);
|
|
10319
|
-
const x_for = (i) =>
|
|
9998
|
+
const x_for = (i) => PAD_LEFT + i * slot_w + (slot_w - bar_w) / 2;
|
|
10320
9999
|
const x_label_idx = pick_x_label_indices(bars.length);
|
|
10321
10000
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10322
10001
|
"svg",
|
|
@@ -10326,14 +10005,14 @@ function StackedBars({
|
|
|
10326
10005
|
style: { width: "100%", height: "auto", display: "block", maxHeight: `${height + 10}px` },
|
|
10327
10006
|
children: [
|
|
10328
10007
|
showYAxis && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
10329
|
-
/* @__PURE__ */ jsxRuntime.jsx("text", { x:
|
|
10008
|
+
/* @__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
10009
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10331
10010
|
"text",
|
|
10332
10011
|
{
|
|
10333
|
-
x:
|
|
10334
|
-
y:
|
|
10012
|
+
x: PAD_LEFT - 4,
|
|
10013
|
+
y: PAD_TOP + plot_h / 2 + 3,
|
|
10335
10014
|
textAnchor: "end",
|
|
10336
|
-
fill:
|
|
10015
|
+
fill: AXIS_LABEL_COLOR,
|
|
10337
10016
|
fontSize: 9,
|
|
10338
10017
|
children: format_num(y_max / 2)
|
|
10339
10018
|
}
|
|
@@ -10341,17 +10020,17 @@ function StackedBars({
|
|
|
10341
10020
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10342
10021
|
"text",
|
|
10343
10022
|
{
|
|
10344
|
-
x:
|
|
10345
|
-
y: height -
|
|
10023
|
+
x: PAD_LEFT - 4,
|
|
10024
|
+
y: height - PAD_BOTTOM + 3,
|
|
10346
10025
|
textAnchor: "end",
|
|
10347
|
-
fill:
|
|
10026
|
+
fill: AXIS_LABEL_COLOR,
|
|
10348
10027
|
fontSize: 9,
|
|
10349
10028
|
children: "0"
|
|
10350
10029
|
}
|
|
10351
10030
|
)
|
|
10352
10031
|
] }),
|
|
10353
10032
|
bars.map((bar, i) => {
|
|
10354
|
-
let cursor_y = height -
|
|
10033
|
+
let cursor_y = height - PAD_BOTTOM;
|
|
10355
10034
|
return /* @__PURE__ */ jsxRuntime.jsx("g", { children: bar.segments.map((seg, s_idx) => {
|
|
10356
10035
|
if (seg.value <= 0) return null;
|
|
10357
10036
|
const seg_h = seg.value / y_max * plot_h;
|
|
@@ -10379,7 +10058,7 @@ function StackedBars({
|
|
|
10379
10058
|
x: x_pos,
|
|
10380
10059
|
y: height - 6,
|
|
10381
10060
|
textAnchor: anchor,
|
|
10382
|
-
fill:
|
|
10061
|
+
fill: AXIS_LABEL_COLOR,
|
|
10383
10062
|
fontSize: 9,
|
|
10384
10063
|
children: bars[idx]?.label ?? ""
|
|
10385
10064
|
},
|
|
@@ -10428,15 +10107,15 @@ function DateRangeSelector({
|
|
|
10428
10107
|
}
|
|
10429
10108
|
);
|
|
10430
10109
|
}
|
|
10431
|
-
var
|
|
10432
|
-
var
|
|
10433
|
-
var
|
|
10434
|
-
var
|
|
10110
|
+
var PAD_LEFT2 = 80;
|
|
10111
|
+
var PAD_RIGHT2 = 72;
|
|
10112
|
+
var PAD_TOP2 = 12;
|
|
10113
|
+
var PAD_BOTTOM2 = 12;
|
|
10435
10114
|
var ROW_H = 44;
|
|
10436
10115
|
var LABEL_H = 14;
|
|
10437
10116
|
var BAR_H = 22;
|
|
10438
|
-
var
|
|
10439
|
-
var
|
|
10117
|
+
var AXIS_LABEL_COLOR2 = "#8b949e";
|
|
10118
|
+
var GRIDLINE_COLOR = "#2a3441";
|
|
10440
10119
|
function step_total(step) {
|
|
10441
10120
|
if (step.value !== void 0) return step.value;
|
|
10442
10121
|
if (step.segments) return step.segments.reduce((s, g) => s + g.value, 0);
|
|
@@ -10456,15 +10135,15 @@ function FunnelChart({
|
|
|
10456
10135
|
const fmt = valueFormat ?? format_num;
|
|
10457
10136
|
const totals = steps.map(step_total);
|
|
10458
10137
|
const value_max = Math.max(1, ...totals);
|
|
10459
|
-
const plot_w = width -
|
|
10460
|
-
const vbox_h = height ??
|
|
10138
|
+
const plot_w = width - PAD_LEFT2 - PAD_RIGHT2;
|
|
10139
|
+
const vbox_h = height ?? PAD_TOP2 + steps.length * ROW_H + PAD_BOTTOM2;
|
|
10461
10140
|
const handle_mouse_move = React26__namespace.useCallback(
|
|
10462
10141
|
(e) => {
|
|
10463
10142
|
if (steps.length === 0) return;
|
|
10464
10143
|
const rect = e.currentTarget.getBoundingClientRect();
|
|
10465
10144
|
if (rect.height === 0) return;
|
|
10466
10145
|
const vbox_y = (e.clientY - rect.top) / rect.height * vbox_h;
|
|
10467
|
-
const row_idx = Math.floor((vbox_y -
|
|
10146
|
+
const row_idx = Math.floor((vbox_y - PAD_TOP2) / ROW_H);
|
|
10468
10147
|
if (row_idx < 0 || row_idx >= steps.length) {
|
|
10469
10148
|
set_hover_idx(null);
|
|
10470
10149
|
return;
|
|
@@ -10491,11 +10170,11 @@ function FunnelChart({
|
|
|
10491
10170
|
steps.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
10492
10171
|
"line",
|
|
10493
10172
|
{
|
|
10494
|
-
x1:
|
|
10495
|
-
x2:
|
|
10496
|
-
y1:
|
|
10497
|
-
y2:
|
|
10498
|
-
stroke:
|
|
10173
|
+
x1: PAD_LEFT2 + plot_w / 2,
|
|
10174
|
+
x2: PAD_LEFT2 + plot_w / 2,
|
|
10175
|
+
y1: PAD_TOP2,
|
|
10176
|
+
y2: PAD_TOP2 + steps.length * ROW_H,
|
|
10177
|
+
stroke: GRIDLINE_COLOR,
|
|
10499
10178
|
strokeWidth: 0.5,
|
|
10500
10179
|
strokeDasharray: "2,3"
|
|
10501
10180
|
}
|
|
@@ -10503,8 +10182,8 @@ function FunnelChart({
|
|
|
10503
10182
|
steps.map((step, i) => {
|
|
10504
10183
|
const total = totals[i];
|
|
10505
10184
|
const bar_w = total / value_max * plot_w;
|
|
10506
|
-
const bar_x =
|
|
10507
|
-
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;
|
|
10508
10187
|
const pct_first = i === 0 ? 100 : Math.round(total / (totals[0] || 1) * 100);
|
|
10509
10188
|
const value_label = i === 0 ? `${fmt(total)} (100%)` : `${fmt(total)} (${pct_first}%)`;
|
|
10510
10189
|
const dropoff = i > 0 ? totals[i - 1] - total : 0;
|
|
@@ -10513,10 +10192,10 @@ function FunnelChart({
|
|
|
10513
10192
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10514
10193
|
"text",
|
|
10515
10194
|
{
|
|
10516
|
-
x:
|
|
10195
|
+
x: PAD_LEFT2 - 6,
|
|
10517
10196
|
y: bar_y + BAR_H / 2 + 4,
|
|
10518
10197
|
textAnchor: "end",
|
|
10519
|
-
fill:
|
|
10198
|
+
fill: AXIS_LABEL_COLOR2,
|
|
10520
10199
|
fontSize: 9,
|
|
10521
10200
|
children: step.label
|
|
10522
10201
|
}
|
|
@@ -10558,7 +10237,7 @@ function FunnelChart({
|
|
|
10558
10237
|
x: label_x,
|
|
10559
10238
|
y: bar_y + BAR_H / 2 + 10,
|
|
10560
10239
|
textAnchor: "start",
|
|
10561
|
-
fill:
|
|
10240
|
+
fill: AXIS_LABEL_COLOR2,
|
|
10562
10241
|
fontSize: 8,
|
|
10563
10242
|
children: `\u2212${fmt(dropoff)}`
|
|
10564
10243
|
}
|
|
@@ -10573,8 +10252,8 @@ function FunnelChart({
|
|
|
10573
10252
|
const pct_prev = i === 0 ? 100 : Math.round(total / (totals[i - 1] || 1) * 100);
|
|
10574
10253
|
const dropoff = i > 0 ? totals[i - 1] - total : 0;
|
|
10575
10254
|
const bar_w = total / value_max * plot_w;
|
|
10576
|
-
const bar_x =
|
|
10577
|
-
const bar_y =
|
|
10255
|
+
const bar_x = PAD_LEFT2 + (plot_w - bar_w) / 2;
|
|
10256
|
+
const bar_y = PAD_TOP2 + i * ROW_H + LABEL_H;
|
|
10578
10257
|
const bubble_anchor_y = bar_y + BAR_H / 2;
|
|
10579
10258
|
const lines = [
|
|
10580
10259
|
{ text: step.label, accent: true },
|
|
@@ -10628,7 +10307,7 @@ function FunnelChart({
|
|
|
10628
10307
|
{
|
|
10629
10308
|
x: bubble_x + 7,
|
|
10630
10309
|
y: bubble_y + pad_v + k * line_h + line_h * 0.75,
|
|
10631
|
-
fill: line.accent ? color2 :
|
|
10310
|
+
fill: line.accent ? color2 : AXIS_LABEL_COLOR2,
|
|
10632
10311
|
fontSize: line.accent ? 10 : 8,
|
|
10633
10312
|
fontWeight: line.accent ? 700 : 400,
|
|
10634
10313
|
children: line.text
|
|
@@ -11184,6 +10863,8 @@ exports.HazoUiDialogTrigger = DialogTrigger;
|
|
|
11184
10863
|
exports.HazoUiEtaProgress = HazoUiEtaProgress;
|
|
11185
10864
|
exports.HazoUiFlexInput = HazoUiFlexInput;
|
|
11186
10865
|
exports.HazoUiFlexRadio = HazoUiFlexRadio;
|
|
10866
|
+
exports.HazoUiImageCropper = HazoUiImageCropper;
|
|
10867
|
+
exports.HazoUiImageCropperDialog = HazoUiImageCropperDialog;
|
|
11187
10868
|
exports.HazoUiKanban = HazoUiKanban;
|
|
11188
10869
|
exports.HazoUiKanbanFilter = HazoUiKanbanFilter;
|
|
11189
10870
|
exports.HazoUiMultiFilterDialog = HazoUiMultiFilterDialog;
|
|
@@ -11199,12 +10880,11 @@ exports.HoverCard = HoverCard;
|
|
|
11199
10880
|
exports.HoverCardContent = HoverCardContent;
|
|
11200
10881
|
exports.HoverCardTrigger = HoverCardTrigger;
|
|
11201
10882
|
exports.Input = Input;
|
|
10883
|
+
exports.InputAffix = InputAffix;
|
|
11202
10884
|
exports.InverseSparkline = InverseSparkline;
|
|
11203
10885
|
exports.Label = Label3;
|
|
11204
|
-
exports.LineChart = LineChart;
|
|
11205
10886
|
exports.LoadingTimeout = LoadingTimeout;
|
|
11206
10887
|
exports.MarkdownEditor = MarkdownEditor;
|
|
11207
|
-
exports.MultiLineChart = MultiLineChart;
|
|
11208
10888
|
exports.Popover = Popover;
|
|
11209
10889
|
exports.PopoverContent = PopoverContent;
|
|
11210
10890
|
exports.PopoverTrigger = PopoverTrigger;
|
|
@@ -11235,6 +10915,7 @@ exports.SkeletonBar = SkeletonBar;
|
|
|
11235
10915
|
exports.SkeletonCircle = SkeletonCircle;
|
|
11236
10916
|
exports.SkeletonGroup = SkeletonGroup;
|
|
11237
10917
|
exports.SkeletonRect = SkeletonRect;
|
|
10918
|
+
exports.Slider = Slider;
|
|
11238
10919
|
exports.Sparkline = Sparkline;
|
|
11239
10920
|
exports.Spinner = Spinner;
|
|
11240
10921
|
exports.StackedBars = StackedBars;
|