@ayseaistudio/ui-components 3.11.9 → 3.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/BarChart/BarChart.d.ts +34 -0
- package/dist/BarChart/BarChart.js +257 -0
- package/dist/BarChart/index.d.ts +2 -0
- package/dist/BarChart/index.js +1 -0
- package/dist/BarChart/style.css +317 -0
- package/dist/LineBarHorizontal/LineBarHorizontal.d.ts +25 -0
- package/dist/LineBarHorizontal/LineBarHorizontal.js +16 -0
- package/dist/LineBarHorizontal/index.d.ts +1 -0
- package/dist/LineBarHorizontal/index.js +1 -0
- package/dist/LineBarHorizontal/style.css +44 -0
- package/dist/LineBarVertical/LineBarVertical.d.ts +14 -0
- package/dist/LineBarVertical/LineBarVertical.js +10 -0
- package/dist/LineBarVertical/index.d.ts +1 -0
- package/dist/LineBarVertical/index.js +1 -0
- package/dist/LineBarVertical/style.css +33 -0
- package/dist/PieChart/PieChart.d.ts +38 -0
- package/dist/PieChart/PieChart.js +285 -0
- package/dist/PieChart/index.d.ts +1 -0
- package/dist/PieChart/index.js +1 -0
- package/dist/PieChart/style.css +59 -0
- package/dist/ValueDots/ValueDots.d.ts +15 -0
- package/dist/ValueDots/ValueDots.js +33 -0
- package/dist/ValueDots/index.d.ts +1 -0
- package/dist/ValueDots/index.js +1 -0
- package/dist/ValueDots/style.css +129 -0
- package/dist/ValueLabel/ValueLabel.d.ts +23 -0
- package/dist/ValueLabel/ValueLabel.js +14 -0
- package/dist/ValueLabel/index.d.ts +1 -0
- package/dist/ValueLabel/index.js +1 -0
- package/dist/ValueLabel/style.css +23 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +7 -0
- package/package.json +1 -1
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
.line-bar-horizontal {
|
|
2
|
+
align-items: flex-start;
|
|
3
|
+
border-radius: 8px;
|
|
4
|
+
box-shadow: inset 0px 0px 10px #ffffff40;
|
|
5
|
+
display: flex;
|
|
6
|
+
height: 160px;
|
|
7
|
+
justify-content: center;
|
|
8
|
+
overflow: hidden;
|
|
9
|
+
padding: 8px;
|
|
10
|
+
position: relative;
|
|
11
|
+
width: 100%;
|
|
12
|
+
min-width: 0;
|
|
13
|
+
max-width: 100%;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.line-bar-horizontal .instance-node {
|
|
17
|
+
flex: 1 !important;
|
|
18
|
+
text-align: center !important;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.line-bar-horizontal .label-14 {
|
|
22
|
+
display: flex !important;
|
|
23
|
+
flex: 1 !important;
|
|
24
|
+
flex-grow: 1 !important;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.line-bar-horizontal.color-primary {
|
|
28
|
+
background-color: #b1e635;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.line-bar-horizontal.color-fourth {
|
|
32
|
+
background-color: #2424241a;
|
|
33
|
+
border: 1px solid;
|
|
34
|
+
border-color: #d1d1d1;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
.line-bar-horizontal.color-secondary {
|
|
39
|
+
background-color: rgba(113, 163, 13, 1);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.line-bar-horizontal.color-tertiary {
|
|
43
|
+
background-color: rgba(70, 98, 18, 1);
|
|
44
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import PropTypes from "prop-types";
|
|
2
|
+
import "./style.css";
|
|
3
|
+
interface Props {
|
|
4
|
+
colour: "primary" | "secondary" | "fourth";
|
|
5
|
+
className: any;
|
|
6
|
+
label?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare const LineBarVertical: {
|
|
9
|
+
({ colour, className, label }: Props): React.JSX.Element;
|
|
10
|
+
propTypes: {
|
|
11
|
+
colour: PropTypes.Requireable<string>;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
import { Label } from "../Label";
|
|
4
|
+
import "./style.css";
|
|
5
|
+
export const LineBarVertical = ({ colour, className, label }) => {
|
|
6
|
+
return (_jsxs("div", { className: `line-bar-vertical-wrapper ${className}`, children: [_jsx("div", { className: `line-bar-vertical colour-${colour} ${className}` }), label && (_jsx(Label, { bold: "on", className: "line-bar-vertical-label", color: "black", divClassName: "design-component-instance-node", size: "small", spacing: "on", stroke: "off", text: label, version: "primary" }))] }));
|
|
7
|
+
};
|
|
8
|
+
LineBarVertical.propTypes = {
|
|
9
|
+
colour: PropTypes.oneOf(["primary", "secondary", "fourth"]),
|
|
10
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { LineBarVertical } from "./LineBarVertical";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { LineBarVertical } from "./LineBarVertical";
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
.line-bar-vertical-wrapper {
|
|
2
|
+
align-items: center;
|
|
3
|
+
display: inline-flex;
|
|
4
|
+
flex-direction: column;
|
|
5
|
+
gap: 4px;
|
|
6
|
+
position: relative;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.line-bar-vertical {
|
|
10
|
+
border-radius: 36px;
|
|
11
|
+
box-shadow: inset 0px 0px 10px #ffffff40;
|
|
12
|
+
height: 20px;
|
|
13
|
+
position: relative;
|
|
14
|
+
width: 200px;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.line-bar-vertical.colour-secondary {
|
|
18
|
+
background-color: #71a30d;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.line-bar-vertical.colour-fourth {
|
|
22
|
+
background-color: #2424241a;
|
|
23
|
+
border: 1px solid;
|
|
24
|
+
border-color: #d1d1d1;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.line-bar-vertical.colour-primary {
|
|
28
|
+
background-color: #b1e635;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.line-bar-vertical-label {
|
|
32
|
+
padding: 2px !important;
|
|
33
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type MouseEvent } from "react";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
import "./style.css";
|
|
4
|
+
type SliceHoverPayload = {
|
|
5
|
+
index: number;
|
|
6
|
+
value: number;
|
|
7
|
+
label?: string;
|
|
8
|
+
};
|
|
9
|
+
interface Props {
|
|
10
|
+
className?: string;
|
|
11
|
+
data?: number[];
|
|
12
|
+
labels?: string[];
|
|
13
|
+
backgroundColors?: string[];
|
|
14
|
+
size?: number;
|
|
15
|
+
variant?: "pie" | "donut";
|
|
16
|
+
enableTooltip?: boolean;
|
|
17
|
+
tooltipFormatter?: (payload: SliceHoverPayload) => string;
|
|
18
|
+
onSliceHover?: (payload: SliceHoverPayload | null, event?: MouseEvent<SVGPathElement | SVGSVGElement>) => void;
|
|
19
|
+
enableLegend?: boolean;
|
|
20
|
+
legendInteractive?: boolean;
|
|
21
|
+
}
|
|
22
|
+
export declare const PieChart: {
|
|
23
|
+
({ className, data, labels, backgroundColors, size, variant, enableTooltip, tooltipFormatter, onSliceHover, enableLegend, legendInteractive, }: Props): React.JSX.Element;
|
|
24
|
+
propTypes: {
|
|
25
|
+
className: PropTypes.Requireable<string>;
|
|
26
|
+
data: PropTypes.Requireable<(number | null | undefined)[]>;
|
|
27
|
+
labels: PropTypes.Requireable<(string | null | undefined)[]>;
|
|
28
|
+
backgroundColors: PropTypes.Requireable<(string | null | undefined)[]>;
|
|
29
|
+
size: PropTypes.Requireable<number>;
|
|
30
|
+
variant: PropTypes.Requireable<string>;
|
|
31
|
+
enableTooltip: PropTypes.Requireable<boolean>;
|
|
32
|
+
tooltipFormatter: PropTypes.Requireable<(...args: any[]) => any>;
|
|
33
|
+
onSliceHover: PropTypes.Requireable<(...args: any[]) => any>;
|
|
34
|
+
enableLegend: PropTypes.Requireable<boolean>;
|
|
35
|
+
legendInteractive: PropTypes.Requireable<boolean>;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
export {};
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useId, useRef, useState } from "react";
|
|
3
|
+
import PropTypes from "prop-types";
|
|
4
|
+
import { InfoTooltip } from "../InfoTooltip";
|
|
5
|
+
import { ValueLabel } from "../ValueLabel";
|
|
6
|
+
import "./style.css";
|
|
7
|
+
const DEFAULT_COLORS = [
|
|
8
|
+
"#B1E635",
|
|
9
|
+
"#71A30D",
|
|
10
|
+
"#466212",
|
|
11
|
+
"#99C24D",
|
|
12
|
+
"#567C16",
|
|
13
|
+
];
|
|
14
|
+
export const PieChart = ({ className = "", data, labels, backgroundColors, size = 158, variant = "donut", enableTooltip = false, tooltipFormatter, onSliceHover, enableLegend = false, legendInteractive = false, }) => {
|
|
15
|
+
const [hoveredSlice, setHoveredSlice] = useState(null);
|
|
16
|
+
const [tooltipPos, setTooltipPos] = useState({ x: 0, y: 0 });
|
|
17
|
+
const svgRef = useRef(null);
|
|
18
|
+
const wrapperRef = useRef(null);
|
|
19
|
+
const [hiddenIndexes, setHiddenIndexes] = useState(new Set());
|
|
20
|
+
const [tooltipOpen, setTooltipOpen] = useState(false);
|
|
21
|
+
const hideTimerRef = useRef(null);
|
|
22
|
+
const animRafRef = useRef(null);
|
|
23
|
+
const [isVisible, setIsVisible] = useState(false);
|
|
24
|
+
const [animatedValues, setAnimatedValues] = useState(() => (data ?? []).map((v) => v ?? 0));
|
|
25
|
+
const uniqueId = useId();
|
|
26
|
+
const maskId = `pie-mask-${uniqueId}`;
|
|
27
|
+
const [introProgress, setIntroProgress] = useState(0); // 0 -> 1
|
|
28
|
+
const introPlayedRef = useRef(false);
|
|
29
|
+
const handleLegendClick = (index) => {
|
|
30
|
+
if (!legendInteractive)
|
|
31
|
+
return;
|
|
32
|
+
const totalItems = (data ?? []).length;
|
|
33
|
+
const activeItems = totalItems - hiddenIndexes.size;
|
|
34
|
+
// Son kalan legend'ı kapatmayı engelle
|
|
35
|
+
if (activeItems === 1 && !hiddenIndexes.has(index)) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
setHiddenIndexes((prev) => {
|
|
39
|
+
const next = new Set(prev);
|
|
40
|
+
if (next.has(index))
|
|
41
|
+
next.delete(index);
|
|
42
|
+
else
|
|
43
|
+
next.add(index);
|
|
44
|
+
return next;
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
const rawData = data ?? [];
|
|
48
|
+
const rawLabels = labels ?? [];
|
|
49
|
+
const rawColors = backgroundColors ?? [];
|
|
50
|
+
const rawDataSafe = (data ?? []).map((v) => v ?? 0);
|
|
51
|
+
const isEmpty = rawDataSafe.length === 0 || rawDataSafe.every((v) => v === 0);
|
|
52
|
+
const hasData = !isEmpty;
|
|
53
|
+
const chartData = animatedValues;
|
|
54
|
+
const chartLabels = rawLabels;
|
|
55
|
+
const chartColors = rawData.map((_, index) => rawColors[index] ?? DEFAULT_COLORS[index % DEFAULT_COLORS.length]);
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
if (!wrapperRef.current)
|
|
58
|
+
return;
|
|
59
|
+
setIsVisible(false);
|
|
60
|
+
const reduceMotion = typeof window !== "undefined" &&
|
|
61
|
+
window.matchMedia &&
|
|
62
|
+
window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
63
|
+
if (reduceMotion) {
|
|
64
|
+
setIsVisible(true);
|
|
65
|
+
setIntroProgress(1);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const io = new IntersectionObserver(([entry]) => {
|
|
69
|
+
if (entry.isIntersecting) {
|
|
70
|
+
setIsVisible(true);
|
|
71
|
+
if (!reduceMotion && !introPlayedRef.current) {
|
|
72
|
+
introPlayedRef.current = true;
|
|
73
|
+
setIntroProgress(0);
|
|
74
|
+
requestAnimationFrame(() => setIntroProgress(1));
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
setIntroProgress(1);
|
|
78
|
+
}
|
|
79
|
+
io.disconnect();
|
|
80
|
+
}
|
|
81
|
+
}, { threshold: 0.25 });
|
|
82
|
+
io.observe(wrapperRef.current);
|
|
83
|
+
return () => io.disconnect();
|
|
84
|
+
}, []);
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
const rawData = (data ?? []).map((v) => v ?? 0);
|
|
87
|
+
const target = rawData.map((v, i) => (hiddenIndexes.has(i) ? 0 : v));
|
|
88
|
+
setAnimatedValues((prev) => {
|
|
89
|
+
if (prev.length !== target.length)
|
|
90
|
+
return target;
|
|
91
|
+
return prev;
|
|
92
|
+
});
|
|
93
|
+
const DURATION = 420; // 300-600 arası oynat
|
|
94
|
+
const start = performance.now();
|
|
95
|
+
const easeOutCubic = (t) => 1 - Math.pow(1 - t, 3);
|
|
96
|
+
// önceki değerleri snapshot al
|
|
97
|
+
const from = animatedValues.length === target.length ? animatedValues : target;
|
|
98
|
+
if (animRafRef.current)
|
|
99
|
+
cancelAnimationFrame(animRafRef.current);
|
|
100
|
+
const tick = (now) => {
|
|
101
|
+
const t = Math.min(1, (now - start) / DURATION);
|
|
102
|
+
const e = easeOutCubic(t);
|
|
103
|
+
const next = target.map((to, i) => {
|
|
104
|
+
const fr = from[i] ?? 0;
|
|
105
|
+
return fr + (to - fr) * e;
|
|
106
|
+
});
|
|
107
|
+
setAnimatedValues(next);
|
|
108
|
+
if (t < 1) {
|
|
109
|
+
animRafRef.current = requestAnimationFrame(tick);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
animRafRef.current = null;
|
|
113
|
+
setAnimatedValues(target);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
animRafRef.current = requestAnimationFrame(tick);
|
|
117
|
+
return () => {
|
|
118
|
+
if (animRafRef.current)
|
|
119
|
+
cancelAnimationFrame(animRafRef.current);
|
|
120
|
+
};
|
|
121
|
+
}, [data, hiddenIndexes]);
|
|
122
|
+
useEffect(() => {
|
|
123
|
+
return () => {
|
|
124
|
+
if (animRafRef.current)
|
|
125
|
+
cancelAnimationFrame(animRafRef.current);
|
|
126
|
+
if (hideTimerRef.current)
|
|
127
|
+
window.clearTimeout(hideTimerRef.current);
|
|
128
|
+
};
|
|
129
|
+
}, []);
|
|
130
|
+
const radius = size / 2;
|
|
131
|
+
const center = radius;
|
|
132
|
+
const innerRadius = variant === "pie" ? 0 : radius * 0.35;
|
|
133
|
+
const circumference = 2 * Math.PI * radius;
|
|
134
|
+
const dashOffset = circumference * (1 - introProgress);
|
|
135
|
+
if (!hasData) {
|
|
136
|
+
const EMPTY_COLOR = "rgba(200, 200, 200, 1)";
|
|
137
|
+
return (_jsx("div", { ref: wrapperRef, className: `pie-chart-wrapper ${className} ${isVisible ? "is-visible" : ""}`, children: _jsxs("svg", { ref: svgRef, className: "pie-chart-customers", width: size, height: size, viewBox: `0 0 ${size} ${size}`, role: "img", "aria-label": "No data", children: [_jsx("defs", { children: _jsxs("mask", { id: maskId, children: [_jsx("rect", { x: "0", y: "0", width: size, height: size, fill: "black" }), _jsx("circle", { cx: center, cy: center, r: radius, fill: "none", stroke: "white", strokeWidth: radius * 2, strokeDasharray: circumference, strokeDashoffset: dashOffset, style: {
|
|
138
|
+
transition: "stroke-dashoffset 1200ms cubic-bezier(0.2, 0.9, 0.2, 1)",
|
|
139
|
+
transformOrigin: "50% 50%",
|
|
140
|
+
transform: "rotate(-90deg)",
|
|
141
|
+
} })] }) }), _jsx("g", { mask: `url(#${maskId})`, children: _jsx("circle", { cx: center, cy: center, r: radius, fill: EMPTY_COLOR }) }), variant === "donut" && (_jsx("circle", { cx: center, cy: center, r: innerRadius, fill: "white" }))] }) }));
|
|
142
|
+
}
|
|
143
|
+
const total = chartData.reduce((sum, value) => sum + (value || 0), 0) || 1;
|
|
144
|
+
let cumulativeAngle = -90;
|
|
145
|
+
const FULL_CIRCLE_EPS = 359.999;
|
|
146
|
+
const slices = chartData.map((value, index) => {
|
|
147
|
+
const sliceAngle = (value / total) * 360;
|
|
148
|
+
const color = chartColors[index];
|
|
149
|
+
const isTiny = value <= total * 0.002;
|
|
150
|
+
const opacity = value <= 0.0001 ? 0 : 1;
|
|
151
|
+
if (sliceAngle >= FULL_CIRCLE_EPS) {
|
|
152
|
+
const handleEnter = (event) => {
|
|
153
|
+
const payload = {
|
|
154
|
+
index,
|
|
155
|
+
value,
|
|
156
|
+
label: chartLabels[index],
|
|
157
|
+
};
|
|
158
|
+
if (enableTooltip && wrapperRef.current) {
|
|
159
|
+
const rect = wrapperRef.current.getBoundingClientRect();
|
|
160
|
+
if (hideTimerRef.current) {
|
|
161
|
+
window.clearTimeout(hideTimerRef.current);
|
|
162
|
+
hideTimerRef.current = null;
|
|
163
|
+
}
|
|
164
|
+
setHoveredSlice(payload);
|
|
165
|
+
setTooltipPos({
|
|
166
|
+
x: event.clientX - rect.left,
|
|
167
|
+
y: event.clientY - rect.top - 20,
|
|
168
|
+
});
|
|
169
|
+
requestAnimationFrame(() => setTooltipOpen(true));
|
|
170
|
+
}
|
|
171
|
+
onSliceHover?.(payload, event);
|
|
172
|
+
};
|
|
173
|
+
const handleLeave = (event) => {
|
|
174
|
+
if (enableTooltip) {
|
|
175
|
+
setTooltipOpen(false);
|
|
176
|
+
hideTimerRef.current = window.setTimeout(() => {
|
|
177
|
+
setHoveredSlice(null);
|
|
178
|
+
}, 220);
|
|
179
|
+
}
|
|
180
|
+
onSliceHover?.(null, event);
|
|
181
|
+
};
|
|
182
|
+
return (_jsx("circle", { cx: center, cy: center, r: radius, fill: color, style: {
|
|
183
|
+
opacity,
|
|
184
|
+
transition: "opacity 220ms ease",
|
|
185
|
+
pointerEvents: opacity === 0 ? "none" : "auto",
|
|
186
|
+
}, onMouseEnter: handleEnter, onMouseLeave: handleLeave }, index));
|
|
187
|
+
}
|
|
188
|
+
const startAngle = cumulativeAngle;
|
|
189
|
+
const endAngle = cumulativeAngle + sliceAngle;
|
|
190
|
+
cumulativeAngle = endAngle;
|
|
191
|
+
const largeArcFlag = sliceAngle > 180 ? 1 : 0;
|
|
192
|
+
const startRadians = (Math.PI / 180) * startAngle;
|
|
193
|
+
const endRadians = (Math.PI / 180) * endAngle;
|
|
194
|
+
const x1 = center + radius * Math.cos(startRadians);
|
|
195
|
+
const y1 = center + radius * Math.sin(startRadians);
|
|
196
|
+
const x2 = center + radius * Math.cos(endRadians);
|
|
197
|
+
const y2 = center + radius * Math.sin(endRadians);
|
|
198
|
+
const pathData = [
|
|
199
|
+
`M ${center} ${center}`,
|
|
200
|
+
`L ${x1} ${y1}`,
|
|
201
|
+
`A ${radius} ${radius} 0 ${largeArcFlag} 1 ${x2} ${y2}`,
|
|
202
|
+
"Z",
|
|
203
|
+
].join(" ");
|
|
204
|
+
const handleEnter = (event) => {
|
|
205
|
+
if (isTiny)
|
|
206
|
+
return;
|
|
207
|
+
const payload = {
|
|
208
|
+
index,
|
|
209
|
+
value,
|
|
210
|
+
label: chartLabels[index],
|
|
211
|
+
};
|
|
212
|
+
if (enableTooltip && wrapperRef.current) {
|
|
213
|
+
const rect = wrapperRef.current.getBoundingClientRect();
|
|
214
|
+
if (hideTimerRef.current) {
|
|
215
|
+
window.clearTimeout(hideTimerRef.current);
|
|
216
|
+
hideTimerRef.current = null;
|
|
217
|
+
}
|
|
218
|
+
setHoveredSlice(payload);
|
|
219
|
+
setTooltipPos({
|
|
220
|
+
x: event.clientX - rect.left,
|
|
221
|
+
y: event.clientY - rect.top - 20,
|
|
222
|
+
});
|
|
223
|
+
requestAnimationFrame(() => setTooltipOpen(true));
|
|
224
|
+
}
|
|
225
|
+
onSliceHover?.(payload, event);
|
|
226
|
+
};
|
|
227
|
+
const handleLeave = (event) => {
|
|
228
|
+
if (enableTooltip) {
|
|
229
|
+
setTooltipOpen(false);
|
|
230
|
+
hideTimerRef.current = window.setTimeout(() => {
|
|
231
|
+
setHoveredSlice(null);
|
|
232
|
+
}, 220);
|
|
233
|
+
}
|
|
234
|
+
onSliceHover?.(null, event);
|
|
235
|
+
};
|
|
236
|
+
return (_jsx("path", { d: pathData, fill: color, style: {
|
|
237
|
+
opacity,
|
|
238
|
+
transition: "opacity 220ms ease",
|
|
239
|
+
pointerEvents: opacity === 0 ? "none" : "auto",
|
|
240
|
+
}, onMouseEnter: handleEnter, onMouseLeave: handleLeave }, index));
|
|
241
|
+
});
|
|
242
|
+
const tooltipText = enableTooltip && hoveredSlice
|
|
243
|
+
? tooltipFormatter
|
|
244
|
+
? tooltipFormatter(hoveredSlice)
|
|
245
|
+
: `${hoveredSlice.label ?? ""}: ${hoveredSlice.value}`
|
|
246
|
+
: "";
|
|
247
|
+
return (_jsxs("div", { ref: wrapperRef, className: `pie-chart-wrapper ${className} ${isVisible ? "is-visible" : ""}`, children: [enableTooltip && hoveredSlice && (_jsx("div", { className: `pie-chart-tooltip ${tooltipOpen ? "pie-chart-tooltip-visible" : ""}`, style: { left: `${tooltipPos.x}px`, top: `${tooltipPos.y}px` }, children: _jsx(InfoTooltip, { text: tooltipText, withIcon: false, className: "pie-chart-tooltip-content" }) })), _jsxs("svg", { ref: svgRef, className: "pie-chart-customers", width: size, height: size, viewBox: `0 0 ${size} ${size}`, role: "img", "aria-label": chartLabels.join(", "), onMouseLeave: (event) => {
|
|
248
|
+
if (enableTooltip) {
|
|
249
|
+
setTooltipOpen(false);
|
|
250
|
+
hideTimerRef.current = window.setTimeout(() => {
|
|
251
|
+
setHoveredSlice(null);
|
|
252
|
+
}, 220);
|
|
253
|
+
}
|
|
254
|
+
onSliceHover?.(null, event);
|
|
255
|
+
}, children: [_jsx("defs", { children: _jsxs("mask", { id: maskId, children: [_jsx("rect", { x: "0", y: "0", width: size, height: size, fill: "black" }), _jsx("circle", { cx: center, cy: center, r: radius, fill: "none", stroke: "white", strokeWidth: radius * 2, strokeDasharray: circumference, strokeDashoffset: dashOffset, style: {
|
|
256
|
+
transition: "stroke-dashoffset 1200ms cubic-bezier(0.2, 0.9, 0.2, 1)",
|
|
257
|
+
transformOrigin: "50% 50%",
|
|
258
|
+
transform: "rotate(-90deg)",
|
|
259
|
+
} })] }) }), _jsx("g", { mask: `url(#${maskId})`, children: slices }), variant === "donut" && (_jsx("circle", { cx: center, cy: center, r: innerRadius, fill: "white" }))] }), enableLegend && hasData && rawLabels.length > 0 && (_jsx("div", { className: "pie-chart-legend", children: rawLabels.map((label, index) => {
|
|
260
|
+
const legendValues = [
|
|
261
|
+
"four-hundred",
|
|
262
|
+
"five-hundred",
|
|
263
|
+
"six-hundred",
|
|
264
|
+
"seven-hundred",
|
|
265
|
+
"eight-hundred",
|
|
266
|
+
"nine-hundred",
|
|
267
|
+
];
|
|
268
|
+
const valueDotsValue = legendValues[index % legendValues.length];
|
|
269
|
+
const isStriked = hiddenIndexes.has(index);
|
|
270
|
+
return (_jsx(ValueLabel, { className: "value-label-instance", labelText: label, spacing: "ON", stroke: "ON", twoDot: "OFF", valueDotsSize: "x-small", valueDotsValue: valueDotsValue, isStriked: isStriked, onClick: () => handleLegendClick(index) }, index));
|
|
271
|
+
}) }))] }));
|
|
272
|
+
};
|
|
273
|
+
PieChart.propTypes = {
|
|
274
|
+
className: PropTypes.string,
|
|
275
|
+
data: PropTypes.arrayOf(PropTypes.number),
|
|
276
|
+
labels: PropTypes.arrayOf(PropTypes.string),
|
|
277
|
+
backgroundColors: PropTypes.arrayOf(PropTypes.string),
|
|
278
|
+
size: PropTypes.number,
|
|
279
|
+
variant: PropTypes.oneOf(["pie", "donut"]),
|
|
280
|
+
enableTooltip: PropTypes.bool,
|
|
281
|
+
tooltipFormatter: PropTypes.func,
|
|
282
|
+
onSliceHover: PropTypes.func,
|
|
283
|
+
enableLegend: PropTypes.bool,
|
|
284
|
+
legendInteractive: PropTypes.bool,
|
|
285
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { PieChart } from "./PieChart";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { PieChart } from "./PieChart";
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
.pie-chart-wrapper {
|
|
2
|
+
position: relative;
|
|
3
|
+
display: flex;
|
|
4
|
+
flex-direction: column;
|
|
5
|
+
width: 100%;
|
|
6
|
+
align-items: center;
|
|
7
|
+
justify-content: space-between;
|
|
8
|
+
height: 100%;
|
|
9
|
+
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.pie-chart-legend {
|
|
13
|
+
display: flex;
|
|
14
|
+
flex-wrap: wrap;
|
|
15
|
+
width: 100%;
|
|
16
|
+
gap: 8px;
|
|
17
|
+
align-items: center;
|
|
18
|
+
justify-content: flex-start;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.pie-chart-wrapper .pie-chart-tooltip {
|
|
22
|
+
position: absolute;
|
|
23
|
+
pointer-events: none;
|
|
24
|
+
z-index: 2;
|
|
25
|
+
opacity: 0;
|
|
26
|
+
transform: translate(-50%, -55%) scale(0.96);
|
|
27
|
+
filter: blur(1px);
|
|
28
|
+
transition:
|
|
29
|
+
opacity 220ms cubic-bezier(0.16, 1, 0.3, 1),
|
|
30
|
+
transform 220ms cubic-bezier(0.16, 1, 0.3, 1),
|
|
31
|
+
filter 220ms cubic-bezier(0.16, 1, 0.3, 1);
|
|
32
|
+
will-change: opacity, transform, filter;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.pie-chart-wrapper .pie-chart-tooltip-visible {
|
|
36
|
+
opacity: 1;
|
|
37
|
+
transform: translate(-50%, -75%) scale(1);
|
|
38
|
+
filter: blur(0);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.pie-chart-customers {
|
|
42
|
+
opacity: 0;
|
|
43
|
+
transform: translateY(6px);
|
|
44
|
+
transition: opacity 0.35s ease, transform 0.35s ease;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.pie-chart-wrapper.is-visible .pie-chart-customers {
|
|
48
|
+
opacity: 1;
|
|
49
|
+
transform: translateY(0);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/* reduce motion */
|
|
53
|
+
@media (prefers-reduced-motion: reduce) {
|
|
54
|
+
.pie-chart-customers {
|
|
55
|
+
transition: none;
|
|
56
|
+
transform: none;
|
|
57
|
+
opacity: 1;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import PropTypes from "prop-types";
|
|
2
|
+
import "./style.css";
|
|
3
|
+
interface Props {
|
|
4
|
+
size: "XX-small" | "x-small" | "small";
|
|
5
|
+
value: "none" | "one-thousand" | "nine-hundred-and-fifty" | "ten" | "three-hundred" | "eight-hundred" | "five" | "five-hundred" | "sixty" | "thirty" | "twenty" | "two-hundred" | "forty" | "six-hundred" | "nine-hundred" | "four-hundred" | "fifty_1" | "eighty" | "one-hundred" | "fifty" | "seven-hundred" | "seventy";
|
|
6
|
+
className?: any;
|
|
7
|
+
}
|
|
8
|
+
export declare const ValueDots: {
|
|
9
|
+
({ size, value, className }: Props): React.JSX.Element;
|
|
10
|
+
propTypes: {
|
|
11
|
+
size: PropTypes.Requireable<string>;
|
|
12
|
+
value: PropTypes.Requireable<string>;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
import "./style.css";
|
|
4
|
+
export const ValueDots = ({ size, value, className }) => {
|
|
5
|
+
return _jsx("div", { className: `value-dots ${value} ${size} ${className}` });
|
|
6
|
+
};
|
|
7
|
+
ValueDots.propTypes = {
|
|
8
|
+
size: PropTypes.oneOf(["XX-small", "x-small", "small"]),
|
|
9
|
+
value: PropTypes.oneOf([
|
|
10
|
+
"none",
|
|
11
|
+
"one-thousand",
|
|
12
|
+
"nine-hundred-and-fifty",
|
|
13
|
+
"ten",
|
|
14
|
+
"three-hundred",
|
|
15
|
+
"eight-hundred",
|
|
16
|
+
"five",
|
|
17
|
+
"five-hundred",
|
|
18
|
+
"sixty",
|
|
19
|
+
"thirty",
|
|
20
|
+
"twenty",
|
|
21
|
+
"two-hundred",
|
|
22
|
+
"forty",
|
|
23
|
+
"six-hundred",
|
|
24
|
+
"nine-hundred",
|
|
25
|
+
"four-hundred",
|
|
26
|
+
"fifty_1",
|
|
27
|
+
"eighty",
|
|
28
|
+
"one-hundred",
|
|
29
|
+
"fifty",
|
|
30
|
+
"seven-hundred",
|
|
31
|
+
"seventy",
|
|
32
|
+
]),
|
|
33
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ValueDots } from "./ValueDots";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ValueDots } from "./ValueDots";
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
.value-dots {
|
|
2
|
+
border: 1px solid;
|
|
3
|
+
border-radius: 96px;
|
|
4
|
+
position: relative;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.value-dots.three-hundred {
|
|
8
|
+
background-color: #caf264;
|
|
9
|
+
border-color: #24242433;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.value-dots.six-hundred {
|
|
13
|
+
background-color: #71a30d;
|
|
14
|
+
border-color: #24242433;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.value-dots.forty {
|
|
18
|
+
background-color: #71a30d66;
|
|
19
|
+
border-color: #24242433;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.value-dots.seventy {
|
|
23
|
+
background-color: #71a30db2;
|
|
24
|
+
border-color: #24242433;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.value-dots.eight-hundred {
|
|
28
|
+
background-color: #466212;
|
|
29
|
+
border-color: #24242433;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.value-dots.twenty {
|
|
33
|
+
background-color: #71a30d33;
|
|
34
|
+
border-color: #24242433;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.value-dots.seven-hundred {
|
|
38
|
+
background-color: #567c0f;
|
|
39
|
+
border-color: #24242433;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.value-dots.two-hundred {
|
|
43
|
+
background-color: #e1f99d;
|
|
44
|
+
border-color: #24242433;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.value-dots.sixty {
|
|
48
|
+
background-color: #71a30d99;
|
|
49
|
+
border-color: #24242433;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.value-dots.one-hundred {
|
|
53
|
+
background-color: #f0fccb;
|
|
54
|
+
border-color: #24242433;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.value-dots.x-small {
|
|
58
|
+
height: 8px;
|
|
59
|
+
width: 8px;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.value-dots.five-hundred {
|
|
63
|
+
background-color: #98d317;
|
|
64
|
+
border-color: #24242433;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.value-dots.XX-small {
|
|
68
|
+
height: 6px;
|
|
69
|
+
width: 6px;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.value-dots.nine-hundred-and-fifty {
|
|
73
|
+
background-color: #1d2e05;
|
|
74
|
+
border-color: #24242433;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.value-dots.none {
|
|
78
|
+
border-color: #d1d1d1;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.value-dots.nine-hundred {
|
|
82
|
+
background-color: #3b5314;
|
|
83
|
+
border-color: #24242433;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.value-dots.eighty {
|
|
87
|
+
background-color: #71a30dcc;
|
|
88
|
+
border-color: #24242433;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.value-dots.thirty {
|
|
92
|
+
background-color: #71a30d4c;
|
|
93
|
+
border-color: #24242433;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.value-dots.fifty_1 {
|
|
97
|
+
background-color: #f9fee7;
|
|
98
|
+
border-color: #24242433;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.value-dots.five {
|
|
102
|
+
background-color: #71a30d0d;
|
|
103
|
+
border-color: #24242433;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.value-dots.fifty {
|
|
107
|
+
background-color: #71a30d80;
|
|
108
|
+
border-color: #24242433;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.value-dots.small {
|
|
112
|
+
height: 14px;
|
|
113
|
+
width: 14px;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.value-dots.ten {
|
|
117
|
+
background-color: #71a30d1a;
|
|
118
|
+
border-color: #24242433;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.value-dots.one-thousand {
|
|
122
|
+
background-color: #3d3d3d;
|
|
123
|
+
border-color: #24242433;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.value-dots.four-hundred {
|
|
127
|
+
background-color: #b1e635;
|
|
128
|
+
border-color: #24242433;
|
|
129
|
+
}
|