@esic-lab/data-core-ui 0.0.54 → 0.0.56
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/assets/STO-logo.svg +92 -92
- package/dist/index.css +5 -1
- package/dist/index.js +169 -12
- package/dist/index.mjs +167 -12
- package/package.json +5 -3
- package/dist/index.d.mts +0 -591
- package/dist/index.d.ts +0 -591
package/dist/index.js
CHANGED
|
@@ -357,6 +357,7 @@ var index_exports = {};
|
|
|
357
357
|
__export(index_exports, {
|
|
358
358
|
AntDModal: () => AntDModal,
|
|
359
359
|
AntDataTable: () => AntDataTable,
|
|
360
|
+
BarChart: () => BarChart,
|
|
360
361
|
Breadcrumbs: () => Breadcrumbs,
|
|
361
362
|
Calendar: () => Calendar,
|
|
362
363
|
Checkbox: () => Checkbox,
|
|
@@ -376,6 +377,7 @@ __export(index_exports, {
|
|
|
376
377
|
KpiSection: () => KpiSection,
|
|
377
378
|
Loader: () => Loader,
|
|
378
379
|
MenuNavBar: () => MenuNavBar,
|
|
380
|
+
PieChart: () => PieChart,
|
|
379
381
|
PrimaryButton: () => PrimaryButton,
|
|
380
382
|
ProfileSelect: () => ProfileSelect,
|
|
381
383
|
ProgressBar: () => ProgressBar,
|
|
@@ -1243,7 +1245,7 @@ function InputFieldNumber({
|
|
|
1243
1245
|
addonAfter,
|
|
1244
1246
|
defaultValue,
|
|
1245
1247
|
className,
|
|
1246
|
-
max,
|
|
1248
|
+
max: max2,
|
|
1247
1249
|
min,
|
|
1248
1250
|
controls,
|
|
1249
1251
|
size,
|
|
@@ -1276,7 +1278,7 @@ function InputFieldNumber({
|
|
|
1276
1278
|
addonBefore,
|
|
1277
1279
|
addonAfter,
|
|
1278
1280
|
defaultValue,
|
|
1279
|
-
max,
|
|
1281
|
+
max: max2,
|
|
1280
1282
|
min,
|
|
1281
1283
|
controls,
|
|
1282
1284
|
size,
|
|
@@ -1730,8 +1732,8 @@ function splitColorStr(str, parseNum) {
|
|
|
1730
1732
|
return numList;
|
|
1731
1733
|
}
|
|
1732
1734
|
var parseHSVorHSL = (num, _, index) => index === 0 ? num : num / 100;
|
|
1733
|
-
function limitRange(value,
|
|
1734
|
-
const mergedMax =
|
|
1735
|
+
function limitRange(value, max2) {
|
|
1736
|
+
const mergedMax = max2 || 255;
|
|
1735
1737
|
if (value > mergedMax) {
|
|
1736
1738
|
return mergedMax;
|
|
1737
1739
|
}
|
|
@@ -2025,9 +2027,9 @@ var FastColor = class _FastColor {
|
|
|
2025
2027
|
}
|
|
2026
2028
|
// ====================== Privates ======================
|
|
2027
2029
|
/** Return a new FastColor object with one channel changed */
|
|
2028
|
-
_sc(rgb, value,
|
|
2030
|
+
_sc(rgb, value, max2) {
|
|
2029
2031
|
const clone = this.clone();
|
|
2030
|
-
clone[rgb] = limitRange(value,
|
|
2032
|
+
clone[rgb] = limitRange(value, max2);
|
|
2031
2033
|
return clone;
|
|
2032
2034
|
}
|
|
2033
2035
|
_c(input) {
|
|
@@ -4343,7 +4345,7 @@ var QRCodeGenerator = ({
|
|
|
4343
4345
|
fileBaseName = "qr-code"
|
|
4344
4346
|
}) => {
|
|
4345
4347
|
const canvasRef = (0, import_react21.useRef)(null);
|
|
4346
|
-
const [
|
|
4348
|
+
const [format4, setFormat] = (0, import_react21.useState)("png");
|
|
4347
4349
|
const [exportSize, setExportSize] = (0, import_react21.useState)(defaultExportSize);
|
|
4348
4350
|
const sizeOption = [
|
|
4349
4351
|
{
|
|
@@ -4397,7 +4399,7 @@ var QRCodeGenerator = ({
|
|
|
4397
4399
|
}, [url, previewSize]);
|
|
4398
4400
|
const download = async () => {
|
|
4399
4401
|
try {
|
|
4400
|
-
if (
|
|
4402
|
+
if (format4 === "svg") {
|
|
4401
4403
|
const svgString = await import_qrcode.default.toString(url, {
|
|
4402
4404
|
type: "svg",
|
|
4403
4405
|
width: exportSize,
|
|
@@ -4413,9 +4415,9 @@ var QRCodeGenerator = ({
|
|
|
4413
4415
|
width: exportSize,
|
|
4414
4416
|
margin: 1
|
|
4415
4417
|
});
|
|
4416
|
-
const mime =
|
|
4417
|
-
const dataURL =
|
|
4418
|
-
triggerDownload(dataURL, `${fileBaseName}.${
|
|
4418
|
+
const mime = format4 === "png" ? "image/png" : "image/jpeg";
|
|
4419
|
+
const dataURL = format4 === "jpeg" ? offscreen.toDataURL(mime, 0.92) : offscreen.toDataURL(mime);
|
|
4420
|
+
triggerDownload(dataURL, `${fileBaseName}.${format4}`);
|
|
4419
4421
|
}
|
|
4420
4422
|
} catch (err) {
|
|
4421
4423
|
console.error("Failed to generate QR export:", err);
|
|
@@ -4448,7 +4450,7 @@ var QRCodeGenerator = ({
|
|
|
4448
4450
|
SelectField,
|
|
4449
4451
|
{
|
|
4450
4452
|
label: "\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A",
|
|
4451
|
-
value:
|
|
4453
|
+
value: format4,
|
|
4452
4454
|
onChange: (e) => setFormat(e.target.value),
|
|
4453
4455
|
options: typeOption
|
|
4454
4456
|
}
|
|
@@ -4508,10 +4510,164 @@ function TabProject({ tabOption, now, onChange }) {
|
|
|
4508
4510
|
}
|
|
4509
4511
|
);
|
|
4510
4512
|
}
|
|
4513
|
+
|
|
4514
|
+
// src/Chart/BarChart/BarChart.tsx
|
|
4515
|
+
var import_react22 = require("react");
|
|
4516
|
+
var d3 = __toESM(require("d3"));
|
|
4517
|
+
var import_jsx_runtime45 = require("react/jsx-runtime");
|
|
4518
|
+
var defaultMargin = { top: 30, right: 200, bottom: 36, left: 50 };
|
|
4519
|
+
var defaultColorPalette = [
|
|
4520
|
+
"#4E79A7",
|
|
4521
|
+
"#F28E2B",
|
|
4522
|
+
"#E15759",
|
|
4523
|
+
"#76B7B2",
|
|
4524
|
+
"#59A14F",
|
|
4525
|
+
"#EDC949",
|
|
4526
|
+
"#AF7AA1",
|
|
4527
|
+
"#FF9DA7",
|
|
4528
|
+
"#9C755F",
|
|
4529
|
+
"#BAB0AC"
|
|
4530
|
+
];
|
|
4531
|
+
var BarChart = ({
|
|
4532
|
+
data,
|
|
4533
|
+
height = 300,
|
|
4534
|
+
margin = defaultMargin,
|
|
4535
|
+
yLabel,
|
|
4536
|
+
xLabel,
|
|
4537
|
+
colorPalette = defaultColorPalette
|
|
4538
|
+
}) => {
|
|
4539
|
+
const svgRef = (0, import_react22.useRef)(null);
|
|
4540
|
+
const gRef = (0, import_react22.useRef)(null);
|
|
4541
|
+
const xAxisRef = (0, import_react22.useRef)(null);
|
|
4542
|
+
const yAxisRef = (0, import_react22.useRef)(null);
|
|
4543
|
+
const containerRef = (0, import_react22.useRef)(null);
|
|
4544
|
+
const widthRef = (0, import_react22.useRef)(0);
|
|
4545
|
+
(0, import_react22.useEffect)(() => {
|
|
4546
|
+
if (!containerRef.current) return;
|
|
4547
|
+
const ro = new ResizeObserver((entries) => {
|
|
4548
|
+
const cr = entries[0].contentRect;
|
|
4549
|
+
widthRef.current = cr.width;
|
|
4550
|
+
render();
|
|
4551
|
+
});
|
|
4552
|
+
ro.observe(containerRef.current);
|
|
4553
|
+
return () => ro.disconnect();
|
|
4554
|
+
}, []);
|
|
4555
|
+
const xDomain = (0, import_react22.useMemo)(() => data.map((d) => d.x), [data]);
|
|
4556
|
+
const yDomain = (0, import_react22.useMemo)(() => {
|
|
4557
|
+
const maxY = d3.max(data, (d) => d.y);
|
|
4558
|
+
return [0, (maxY !== void 0 ? maxY : 0) + (maxY !== void 0 ? maxY : 0) * 0.1];
|
|
4559
|
+
}, [data]);
|
|
4560
|
+
const render = () => {
|
|
4561
|
+
const svg = d3.select(svgRef.current);
|
|
4562
|
+
const g = d3.select(gRef.current);
|
|
4563
|
+
const xAxisG = d3.select(xAxisRef.current);
|
|
4564
|
+
const yAxisG = d3.select(yAxisRef.current);
|
|
4565
|
+
const width = Math.max(200, widthRef.current || 600);
|
|
4566
|
+
const innerW = width - margin.left - margin.right;
|
|
4567
|
+
const innerH = height - margin.top - margin.bottom;
|
|
4568
|
+
svg.attr("width", width).attr("height", height);
|
|
4569
|
+
const x = d3.scaleBand().domain(xDomain).range([0, innerW]).padding(0.2);
|
|
4570
|
+
const y = d3.scaleLinear().domain(yDomain).nice().range([innerH, 0]);
|
|
4571
|
+
const xAxis = d3.axisBottom(x).tickSizeOuter(0).tickSize(0).tickFormat((d) => d);
|
|
4572
|
+
const yAxis = d3.axisLeft(y).ticks(5).tickFormat(d3.format("~s"));
|
|
4573
|
+
const grid = d3.axisLeft(y).ticks(5).tickSize(-innerW).scale(y);
|
|
4574
|
+
const gridG = svg.append("g").attr("class", "grid").attr("transform", `translate(${margin.left}, ${margin.top})`).call(grid).style("font-size", "14px");
|
|
4575
|
+
gridG.selectAll("path").remove();
|
|
4576
|
+
const barsG = svg.append("g").attr("class", "bars");
|
|
4577
|
+
svg.selectAll(".grid").data([0]).join("g").attr("class", "grid").attr("transform", `translate(${margin.left}, ${margin.top})`).call(grid).style("font-size", "14px").call((g2) => g2.selectAll("path").remove()).call(
|
|
4578
|
+
(g2) => g2.selectAll("line").style("stroke", "gray").style("stroke-opacity", 0.1)
|
|
4579
|
+
// keep faint
|
|
4580
|
+
);
|
|
4581
|
+
svg.select(".grid").lower();
|
|
4582
|
+
xAxisG.attr("transform", `translate(${margin.left},${height - margin.bottom})`).call(xAxis).selectAll("text").style("text-anchor", "middle").attr("dy", "1.5em").attr("fill", "currentColor").style("font-size", "14px").style("font-family", "Arial, sans-serif");
|
|
4583
|
+
yAxisG.selectAll(".y-axis-label").data(yLabel ? [yLabel] : []).join(
|
|
4584
|
+
(enter) => enter.append("text").attr("class", "y-axis-label").attr("fill", "currentColor").attr("x", -margin.left + 8).attr("y", -margin.top + 20).attr("text-anchor", "start").style("font-size", "14px").style("font-family", "Arial").text((d) => d),
|
|
4585
|
+
(update) => update.text((d) => d)
|
|
4586
|
+
);
|
|
4587
|
+
xAxisG.selectAll(".x-axis-label").data(xLabel ? [xLabel] : []).join(
|
|
4588
|
+
(enter) => enter.append("text").attr("class", "x-axis-label").attr("fill", "currentColor").attr("x", width).attr("y", height - margin.bottom).attr("text-anchor", "middle").style("font-size", "14px").style("font-family", "Arial").text((d) => d),
|
|
4589
|
+
(update) => update.text((d) => d).attr("x", width)
|
|
4590
|
+
);
|
|
4591
|
+
const t = svg.transition().duration(400);
|
|
4592
|
+
const bars = g.selectAll("rect.bar").data(data, (d) => d.x);
|
|
4593
|
+
bars.join(
|
|
4594
|
+
(enter) => enter.append("rect").attr("class", "bar").attr("x", (d) => margin.left).attr("width", x.bandwidth()).attr("y", () => margin.top + y(0)).attr("height", () => innerH - y(0)).attr("rx", 5).attr("ry", 5).style("fill", (d, i) => colorPalette[i % colorPalette.length]).append("title").text((d) => `${d.x}: ${d.y}`).merge(bars).attr("width", x.bandwidth()).attr("y", (d) => y(d.y)).attr("height", (d) => innerH - y(d.y)).call((enter2) => enter2.raise()),
|
|
4595
|
+
// Bring the new bars to the front
|
|
4596
|
+
(update) => update.call((update2) => update2.raise()).transition(t).attr("x", (d) => x(d.x) ?? 0).attr("width", x.bandwidth()).attr("y", (d) => y(d.y)).attr("height", (d) => innerH - y(d.y)).style("fill", (d, i) => colorPalette[i % colorPalette.length]),
|
|
4597
|
+
// Update color on update
|
|
4598
|
+
(exit) => exit.transition(t).attr("y", margin.top + y(0)).attr("height", innerH - y(0)).remove()
|
|
4599
|
+
);
|
|
4600
|
+
g.selectAll("text.bar-label").data(data).join(
|
|
4601
|
+
(enter) => enter.append("text").attr("class", "bar-label").attr("x", (d) => (x(d.x) ?? 0) + x.bandwidth() / 2).attr("y", (d) => y(d.y) - 6).attr("text-anchor", "middle").style("font-size", "50px").style("font-weight", "bold").style("font-family", "Arial, sans-serif").style("fill", (d, i) => colorPalette[i % colorPalette.length]).text((d) => d.y),
|
|
4602
|
+
(update) => update.transition(t).attr("x", (d) => (x(d.x) ?? 0) + x.bandwidth() / 2).attr("y", (d) => y(d.y) - 6).text((d) => d.y),
|
|
4603
|
+
(exit) => exit.remove()
|
|
4604
|
+
);
|
|
4605
|
+
};
|
|
4606
|
+
(0, import_react22.useEffect)(() => {
|
|
4607
|
+
render();
|
|
4608
|
+
}, [data, height, margin, xDomain.toString(), yDomain.toString()]);
|
|
4609
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { ref: containerRef, style: { width: "100%" }, children: /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("svg", { ref: svgRef, role: "img", "aria-label": "Bar chart", style: { display: "block", width: "100%", height }, children: [
|
|
4610
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("g", { ref: gRef, transform: `translate(${margin.left},${margin.top})` }),
|
|
4611
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("g", { ref: xAxisRef }),
|
|
4612
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("g", { ref: yAxisRef })
|
|
4613
|
+
] }) });
|
|
4614
|
+
};
|
|
4615
|
+
|
|
4616
|
+
// src/Chart/PieChart/PieChart.tsx
|
|
4617
|
+
var import_react23 = __toESM(require("react"));
|
|
4618
|
+
var d32 = __toESM(require("d3"));
|
|
4619
|
+
var import_jsx_runtime46 = require("react/jsx-runtime");
|
|
4620
|
+
var defaultColors = d32.schemeCategory10;
|
|
4621
|
+
var PieChart = ({
|
|
4622
|
+
title,
|
|
4623
|
+
description,
|
|
4624
|
+
data,
|
|
4625
|
+
width,
|
|
4626
|
+
height,
|
|
4627
|
+
colorPalette = defaultColors
|
|
4628
|
+
}) => {
|
|
4629
|
+
const svgRef = (0, import_react23.useRef)(null);
|
|
4630
|
+
const [dataSide, setDataSide] = import_react23.default.useState([]);
|
|
4631
|
+
(0, import_react23.useEffect)(() => {
|
|
4632
|
+
if (!svgRef.current) return;
|
|
4633
|
+
d32.select(svgRef.current).selectAll("*").remove();
|
|
4634
|
+
const radius = Math.min(width, height) / 2;
|
|
4635
|
+
const totalValue = d32.sum(data, (d) => d.value) ?? 0;
|
|
4636
|
+
const svg = d32.select(svgRef.current).attr("width", width).attr("height", height).append("g").attr("transform", `translate(${width / 2}, ${height / 2})`);
|
|
4637
|
+
const pie2 = d32.pie().value((d) => d.value);
|
|
4638
|
+
const arc2 = d32.arc().innerRadius(0).outerRadius(radius);
|
|
4639
|
+
const arcs = svg.selectAll(".arc").data(pie2(data)).enter().append("g").attr("class", "arc");
|
|
4640
|
+
arcs.append("path").attr("d", arc2).attr("fill", (d, i) => colorPalette[i]).attr("stroke", "white").attr("stroke-width", 2).attr("stroke-linejoin", "round");
|
|
4641
|
+
setDataSide(
|
|
4642
|
+
data.map((d, i) => ({
|
|
4643
|
+
color: colorPalette[i],
|
|
4644
|
+
label: d.label,
|
|
4645
|
+
value: d.value
|
|
4646
|
+
}))
|
|
4647
|
+
);
|
|
4648
|
+
arcs.append("text").attr("transform", (d) => `translate(${arc2.centroid(d)})`).attr("dy", ".35em").attr("text-anchor", "middle").style("fill", "white").style("font-family", "Kanit").style("font-size", "20px").style("font-style", "normal").style("font-weight", "500px").text((d) => {
|
|
4649
|
+
const percentage = (d.data.value / totalValue * 100).toFixed(1);
|
|
4650
|
+
return `${percentage}%`;
|
|
4651
|
+
});
|
|
4652
|
+
}, [data, width, height]);
|
|
4653
|
+
return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { children: [
|
|
4654
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("p", { className: "body-2", children: title }),
|
|
4655
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("p", { className: "caption-1", children: description }),
|
|
4656
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex", children: [
|
|
4657
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)("svg", { ref: svgRef }),
|
|
4658
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "flex flex-col gap-2 body-3 pl-[200px]", children: dataSide.map((d, i) => /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "grid grid-cols-3 gap-2 items-center", children: [
|
|
4659
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "w-[20px] h-[20px]", style: { backgroundColor: d.color } }),
|
|
4660
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { children: d.label }),
|
|
4661
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { children: d.value })
|
|
4662
|
+
] }, i)) })
|
|
4663
|
+
] })
|
|
4664
|
+
] });
|
|
4665
|
+
};
|
|
4511
4666
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4512
4667
|
0 && (module.exports = {
|
|
4513
4668
|
AntDModal,
|
|
4514
4669
|
AntDataTable,
|
|
4670
|
+
BarChart,
|
|
4515
4671
|
Breadcrumbs,
|
|
4516
4672
|
Calendar,
|
|
4517
4673
|
Checkbox,
|
|
@@ -4531,6 +4687,7 @@ function TabProject({ tabOption, now, onChange }) {
|
|
|
4531
4687
|
KpiSection,
|
|
4532
4688
|
Loader,
|
|
4533
4689
|
MenuNavBar,
|
|
4690
|
+
PieChart,
|
|
4534
4691
|
PrimaryButton,
|
|
4535
4692
|
ProfileSelect,
|
|
4536
4693
|
ProgressBar,
|
package/dist/index.mjs
CHANGED
|
@@ -1182,7 +1182,7 @@ function InputFieldNumber({
|
|
|
1182
1182
|
addonAfter,
|
|
1183
1183
|
defaultValue,
|
|
1184
1184
|
className,
|
|
1185
|
-
max,
|
|
1185
|
+
max: max2,
|
|
1186
1186
|
min,
|
|
1187
1187
|
controls,
|
|
1188
1188
|
size,
|
|
@@ -1215,7 +1215,7 @@ function InputFieldNumber({
|
|
|
1215
1215
|
addonBefore,
|
|
1216
1216
|
addonAfter,
|
|
1217
1217
|
defaultValue,
|
|
1218
|
-
max,
|
|
1218
|
+
max: max2,
|
|
1219
1219
|
min,
|
|
1220
1220
|
controls,
|
|
1221
1221
|
size,
|
|
@@ -1669,8 +1669,8 @@ function splitColorStr(str, parseNum) {
|
|
|
1669
1669
|
return numList;
|
|
1670
1670
|
}
|
|
1671
1671
|
var parseHSVorHSL = (num, _, index) => index === 0 ? num : num / 100;
|
|
1672
|
-
function limitRange(value,
|
|
1673
|
-
const mergedMax =
|
|
1672
|
+
function limitRange(value, max2) {
|
|
1673
|
+
const mergedMax = max2 || 255;
|
|
1674
1674
|
if (value > mergedMax) {
|
|
1675
1675
|
return mergedMax;
|
|
1676
1676
|
}
|
|
@@ -1964,9 +1964,9 @@ var FastColor = class _FastColor {
|
|
|
1964
1964
|
}
|
|
1965
1965
|
// ====================== Privates ======================
|
|
1966
1966
|
/** Return a new FastColor object with one channel changed */
|
|
1967
|
-
_sc(rgb, value,
|
|
1967
|
+
_sc(rgb, value, max2) {
|
|
1968
1968
|
const clone = this.clone();
|
|
1969
|
-
clone[rgb] = limitRange(value,
|
|
1969
|
+
clone[rgb] = limitRange(value, max2);
|
|
1970
1970
|
return clone;
|
|
1971
1971
|
}
|
|
1972
1972
|
_c(input) {
|
|
@@ -4288,7 +4288,7 @@ var QRCodeGenerator = ({
|
|
|
4288
4288
|
fileBaseName = "qr-code"
|
|
4289
4289
|
}) => {
|
|
4290
4290
|
const canvasRef = useRef7(null);
|
|
4291
|
-
const [
|
|
4291
|
+
const [format4, setFormat] = useState19("png");
|
|
4292
4292
|
const [exportSize, setExportSize] = useState19(defaultExportSize);
|
|
4293
4293
|
const sizeOption = [
|
|
4294
4294
|
{
|
|
@@ -4342,7 +4342,7 @@ var QRCodeGenerator = ({
|
|
|
4342
4342
|
}, [url, previewSize]);
|
|
4343
4343
|
const download = async () => {
|
|
4344
4344
|
try {
|
|
4345
|
-
if (
|
|
4345
|
+
if (format4 === "svg") {
|
|
4346
4346
|
const svgString = await QRCode.toString(url, {
|
|
4347
4347
|
type: "svg",
|
|
4348
4348
|
width: exportSize,
|
|
@@ -4358,9 +4358,9 @@ var QRCodeGenerator = ({
|
|
|
4358
4358
|
width: exportSize,
|
|
4359
4359
|
margin: 1
|
|
4360
4360
|
});
|
|
4361
|
-
const mime =
|
|
4362
|
-
const dataURL =
|
|
4363
|
-
triggerDownload(dataURL, `${fileBaseName}.${
|
|
4361
|
+
const mime = format4 === "png" ? "image/png" : "image/jpeg";
|
|
4362
|
+
const dataURL = format4 === "jpeg" ? offscreen.toDataURL(mime, 0.92) : offscreen.toDataURL(mime);
|
|
4363
|
+
triggerDownload(dataURL, `${fileBaseName}.${format4}`);
|
|
4364
4364
|
}
|
|
4365
4365
|
} catch (err) {
|
|
4366
4366
|
console.error("Failed to generate QR export:", err);
|
|
@@ -4393,7 +4393,7 @@ var QRCodeGenerator = ({
|
|
|
4393
4393
|
SelectField,
|
|
4394
4394
|
{
|
|
4395
4395
|
label: "\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A",
|
|
4396
|
-
value:
|
|
4396
|
+
value: format4,
|
|
4397
4397
|
onChange: (e) => setFormat(e.target.value),
|
|
4398
4398
|
options: typeOption
|
|
4399
4399
|
}
|
|
@@ -4453,9 +4453,163 @@ function TabProject({ tabOption, now, onChange }) {
|
|
|
4453
4453
|
}
|
|
4454
4454
|
);
|
|
4455
4455
|
}
|
|
4456
|
+
|
|
4457
|
+
// src/Chart/BarChart/BarChart.tsx
|
|
4458
|
+
import { useEffect as useEffect9, useMemo as useMemo2, useRef as useRef8 } from "react";
|
|
4459
|
+
import * as d3 from "d3";
|
|
4460
|
+
import { jsx as jsx45, jsxs as jsxs39 } from "react/jsx-runtime";
|
|
4461
|
+
var defaultMargin = { top: 30, right: 200, bottom: 36, left: 50 };
|
|
4462
|
+
var defaultColorPalette = [
|
|
4463
|
+
"#4E79A7",
|
|
4464
|
+
"#F28E2B",
|
|
4465
|
+
"#E15759",
|
|
4466
|
+
"#76B7B2",
|
|
4467
|
+
"#59A14F",
|
|
4468
|
+
"#EDC949",
|
|
4469
|
+
"#AF7AA1",
|
|
4470
|
+
"#FF9DA7",
|
|
4471
|
+
"#9C755F",
|
|
4472
|
+
"#BAB0AC"
|
|
4473
|
+
];
|
|
4474
|
+
var BarChart = ({
|
|
4475
|
+
data,
|
|
4476
|
+
height = 300,
|
|
4477
|
+
margin = defaultMargin,
|
|
4478
|
+
yLabel,
|
|
4479
|
+
xLabel,
|
|
4480
|
+
colorPalette = defaultColorPalette
|
|
4481
|
+
}) => {
|
|
4482
|
+
const svgRef = useRef8(null);
|
|
4483
|
+
const gRef = useRef8(null);
|
|
4484
|
+
const xAxisRef = useRef8(null);
|
|
4485
|
+
const yAxisRef = useRef8(null);
|
|
4486
|
+
const containerRef = useRef8(null);
|
|
4487
|
+
const widthRef = useRef8(0);
|
|
4488
|
+
useEffect9(() => {
|
|
4489
|
+
if (!containerRef.current) return;
|
|
4490
|
+
const ro = new ResizeObserver((entries) => {
|
|
4491
|
+
const cr = entries[0].contentRect;
|
|
4492
|
+
widthRef.current = cr.width;
|
|
4493
|
+
render();
|
|
4494
|
+
});
|
|
4495
|
+
ro.observe(containerRef.current);
|
|
4496
|
+
return () => ro.disconnect();
|
|
4497
|
+
}, []);
|
|
4498
|
+
const xDomain = useMemo2(() => data.map((d) => d.x), [data]);
|
|
4499
|
+
const yDomain = useMemo2(() => {
|
|
4500
|
+
const maxY = d3.max(data, (d) => d.y);
|
|
4501
|
+
return [0, (maxY !== void 0 ? maxY : 0) + (maxY !== void 0 ? maxY : 0) * 0.1];
|
|
4502
|
+
}, [data]);
|
|
4503
|
+
const render = () => {
|
|
4504
|
+
const svg = d3.select(svgRef.current);
|
|
4505
|
+
const g = d3.select(gRef.current);
|
|
4506
|
+
const xAxisG = d3.select(xAxisRef.current);
|
|
4507
|
+
const yAxisG = d3.select(yAxisRef.current);
|
|
4508
|
+
const width = Math.max(200, widthRef.current || 600);
|
|
4509
|
+
const innerW = width - margin.left - margin.right;
|
|
4510
|
+
const innerH = height - margin.top - margin.bottom;
|
|
4511
|
+
svg.attr("width", width).attr("height", height);
|
|
4512
|
+
const x = d3.scaleBand().domain(xDomain).range([0, innerW]).padding(0.2);
|
|
4513
|
+
const y = d3.scaleLinear().domain(yDomain).nice().range([innerH, 0]);
|
|
4514
|
+
const xAxis = d3.axisBottom(x).tickSizeOuter(0).tickSize(0).tickFormat((d) => d);
|
|
4515
|
+
const yAxis = d3.axisLeft(y).ticks(5).tickFormat(d3.format("~s"));
|
|
4516
|
+
const grid = d3.axisLeft(y).ticks(5).tickSize(-innerW).scale(y);
|
|
4517
|
+
const gridG = svg.append("g").attr("class", "grid").attr("transform", `translate(${margin.left}, ${margin.top})`).call(grid).style("font-size", "14px");
|
|
4518
|
+
gridG.selectAll("path").remove();
|
|
4519
|
+
const barsG = svg.append("g").attr("class", "bars");
|
|
4520
|
+
svg.selectAll(".grid").data([0]).join("g").attr("class", "grid").attr("transform", `translate(${margin.left}, ${margin.top})`).call(grid).style("font-size", "14px").call((g2) => g2.selectAll("path").remove()).call(
|
|
4521
|
+
(g2) => g2.selectAll("line").style("stroke", "gray").style("stroke-opacity", 0.1)
|
|
4522
|
+
// keep faint
|
|
4523
|
+
);
|
|
4524
|
+
svg.select(".grid").lower();
|
|
4525
|
+
xAxisG.attr("transform", `translate(${margin.left},${height - margin.bottom})`).call(xAxis).selectAll("text").style("text-anchor", "middle").attr("dy", "1.5em").attr("fill", "currentColor").style("font-size", "14px").style("font-family", "Arial, sans-serif");
|
|
4526
|
+
yAxisG.selectAll(".y-axis-label").data(yLabel ? [yLabel] : []).join(
|
|
4527
|
+
(enter) => enter.append("text").attr("class", "y-axis-label").attr("fill", "currentColor").attr("x", -margin.left + 8).attr("y", -margin.top + 20).attr("text-anchor", "start").style("font-size", "14px").style("font-family", "Arial").text((d) => d),
|
|
4528
|
+
(update) => update.text((d) => d)
|
|
4529
|
+
);
|
|
4530
|
+
xAxisG.selectAll(".x-axis-label").data(xLabel ? [xLabel] : []).join(
|
|
4531
|
+
(enter) => enter.append("text").attr("class", "x-axis-label").attr("fill", "currentColor").attr("x", width).attr("y", height - margin.bottom).attr("text-anchor", "middle").style("font-size", "14px").style("font-family", "Arial").text((d) => d),
|
|
4532
|
+
(update) => update.text((d) => d).attr("x", width)
|
|
4533
|
+
);
|
|
4534
|
+
const t = svg.transition().duration(400);
|
|
4535
|
+
const bars = g.selectAll("rect.bar").data(data, (d) => d.x);
|
|
4536
|
+
bars.join(
|
|
4537
|
+
(enter) => enter.append("rect").attr("class", "bar").attr("x", (d) => margin.left).attr("width", x.bandwidth()).attr("y", () => margin.top + y(0)).attr("height", () => innerH - y(0)).attr("rx", 5).attr("ry", 5).style("fill", (d, i) => colorPalette[i % colorPalette.length]).append("title").text((d) => `${d.x}: ${d.y}`).merge(bars).attr("width", x.bandwidth()).attr("y", (d) => y(d.y)).attr("height", (d) => innerH - y(d.y)).call((enter2) => enter2.raise()),
|
|
4538
|
+
// Bring the new bars to the front
|
|
4539
|
+
(update) => update.call((update2) => update2.raise()).transition(t).attr("x", (d) => x(d.x) ?? 0).attr("width", x.bandwidth()).attr("y", (d) => y(d.y)).attr("height", (d) => innerH - y(d.y)).style("fill", (d, i) => colorPalette[i % colorPalette.length]),
|
|
4540
|
+
// Update color on update
|
|
4541
|
+
(exit) => exit.transition(t).attr("y", margin.top + y(0)).attr("height", innerH - y(0)).remove()
|
|
4542
|
+
);
|
|
4543
|
+
g.selectAll("text.bar-label").data(data).join(
|
|
4544
|
+
(enter) => enter.append("text").attr("class", "bar-label").attr("x", (d) => (x(d.x) ?? 0) + x.bandwidth() / 2).attr("y", (d) => y(d.y) - 6).attr("text-anchor", "middle").style("font-size", "50px").style("font-weight", "bold").style("font-family", "Arial, sans-serif").style("fill", (d, i) => colorPalette[i % colorPalette.length]).text((d) => d.y),
|
|
4545
|
+
(update) => update.transition(t).attr("x", (d) => (x(d.x) ?? 0) + x.bandwidth() / 2).attr("y", (d) => y(d.y) - 6).text((d) => d.y),
|
|
4546
|
+
(exit) => exit.remove()
|
|
4547
|
+
);
|
|
4548
|
+
};
|
|
4549
|
+
useEffect9(() => {
|
|
4550
|
+
render();
|
|
4551
|
+
}, [data, height, margin, xDomain.toString(), yDomain.toString()]);
|
|
4552
|
+
return /* @__PURE__ */ jsx45("div", { ref: containerRef, style: { width: "100%" }, children: /* @__PURE__ */ jsxs39("svg", { ref: svgRef, role: "img", "aria-label": "Bar chart", style: { display: "block", width: "100%", height }, children: [
|
|
4553
|
+
/* @__PURE__ */ jsx45("g", { ref: gRef, transform: `translate(${margin.left},${margin.top})` }),
|
|
4554
|
+
/* @__PURE__ */ jsx45("g", { ref: xAxisRef }),
|
|
4555
|
+
/* @__PURE__ */ jsx45("g", { ref: yAxisRef })
|
|
4556
|
+
] }) });
|
|
4557
|
+
};
|
|
4558
|
+
|
|
4559
|
+
// src/Chart/PieChart/PieChart.tsx
|
|
4560
|
+
import React3, { useRef as useRef9, useEffect as useEffect10 } from "react";
|
|
4561
|
+
import * as d32 from "d3";
|
|
4562
|
+
import { jsx as jsx46, jsxs as jsxs40 } from "react/jsx-runtime";
|
|
4563
|
+
var defaultColors = d32.schemeCategory10;
|
|
4564
|
+
var PieChart = ({
|
|
4565
|
+
title,
|
|
4566
|
+
description,
|
|
4567
|
+
data,
|
|
4568
|
+
width,
|
|
4569
|
+
height,
|
|
4570
|
+
colorPalette = defaultColors
|
|
4571
|
+
}) => {
|
|
4572
|
+
const svgRef = useRef9(null);
|
|
4573
|
+
const [dataSide, setDataSide] = React3.useState([]);
|
|
4574
|
+
useEffect10(() => {
|
|
4575
|
+
if (!svgRef.current) return;
|
|
4576
|
+
d32.select(svgRef.current).selectAll("*").remove();
|
|
4577
|
+
const radius = Math.min(width, height) / 2;
|
|
4578
|
+
const totalValue = d32.sum(data, (d) => d.value) ?? 0;
|
|
4579
|
+
const svg = d32.select(svgRef.current).attr("width", width).attr("height", height).append("g").attr("transform", `translate(${width / 2}, ${height / 2})`);
|
|
4580
|
+
const pie2 = d32.pie().value((d) => d.value);
|
|
4581
|
+
const arc2 = d32.arc().innerRadius(0).outerRadius(radius);
|
|
4582
|
+
const arcs = svg.selectAll(".arc").data(pie2(data)).enter().append("g").attr("class", "arc");
|
|
4583
|
+
arcs.append("path").attr("d", arc2).attr("fill", (d, i) => colorPalette[i]).attr("stroke", "white").attr("stroke-width", 2).attr("stroke-linejoin", "round");
|
|
4584
|
+
setDataSide(
|
|
4585
|
+
data.map((d, i) => ({
|
|
4586
|
+
color: colorPalette[i],
|
|
4587
|
+
label: d.label,
|
|
4588
|
+
value: d.value
|
|
4589
|
+
}))
|
|
4590
|
+
);
|
|
4591
|
+
arcs.append("text").attr("transform", (d) => `translate(${arc2.centroid(d)})`).attr("dy", ".35em").attr("text-anchor", "middle").style("fill", "white").style("font-family", "Kanit").style("font-size", "20px").style("font-style", "normal").style("font-weight", "500px").text((d) => {
|
|
4592
|
+
const percentage = (d.data.value / totalValue * 100).toFixed(1);
|
|
4593
|
+
return `${percentage}%`;
|
|
4594
|
+
});
|
|
4595
|
+
}, [data, width, height]);
|
|
4596
|
+
return /* @__PURE__ */ jsxs40("div", { children: [
|
|
4597
|
+
title && /* @__PURE__ */ jsx46("p", { className: "body-2", children: title }),
|
|
4598
|
+
description && /* @__PURE__ */ jsx46("p", { className: "caption-1", children: description }),
|
|
4599
|
+
/* @__PURE__ */ jsxs40("div", { className: "flex", children: [
|
|
4600
|
+
/* @__PURE__ */ jsx46("svg", { ref: svgRef }),
|
|
4601
|
+
/* @__PURE__ */ jsx46("div", { className: "flex flex-col gap-2 body-3 pl-[200px]", children: dataSide.map((d, i) => /* @__PURE__ */ jsxs40("div", { className: "grid grid-cols-3 gap-2 items-center", children: [
|
|
4602
|
+
/* @__PURE__ */ jsx46("div", { className: "w-[20px] h-[20px]", style: { backgroundColor: d.color } }),
|
|
4603
|
+
/* @__PURE__ */ jsx46("div", { children: d.label }),
|
|
4604
|
+
/* @__PURE__ */ jsx46("div", { children: d.value })
|
|
4605
|
+
] }, i)) })
|
|
4606
|
+
] })
|
|
4607
|
+
] });
|
|
4608
|
+
};
|
|
4456
4609
|
export {
|
|
4457
4610
|
AntDModal,
|
|
4458
4611
|
AntDataTable,
|
|
4612
|
+
BarChart,
|
|
4459
4613
|
Breadcrumbs,
|
|
4460
4614
|
Calendar,
|
|
4461
4615
|
Checkbox,
|
|
@@ -4475,6 +4629,7 @@ export {
|
|
|
4475
4629
|
KpiSection,
|
|
4476
4630
|
Loader,
|
|
4477
4631
|
MenuNavBar,
|
|
4632
|
+
PieChart,
|
|
4478
4633
|
PrimaryButton,
|
|
4479
4634
|
ProfileSelect,
|
|
4480
4635
|
ProgressBar,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@esic-lab/data-core-ui",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.56",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"module": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -41,8 +41,10 @@
|
|
|
41
41
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
42
42
|
"storybook": "storybook dev -p 6006",
|
|
43
43
|
"build-storybook": "storybook build",
|
|
44
|
-
"build": "tsup src/index.ts --
|
|
45
|
-
"
|
|
44
|
+
"build": "tsup src/index.ts --format esm,cjs --out-dir dist && npm run copy-assets",
|
|
45
|
+
"build:dts": "tsup src/index.ts --dts --dts-resolve --out-dir dist",
|
|
46
|
+
"copy-assets": "xcopy src\\assets dist\\assets /E /I /Y",
|
|
47
|
+
"type-check": "tsc --noEmit"
|
|
46
48
|
},
|
|
47
49
|
"peerDependencies": {
|
|
48
50
|
"react": ">=18.0.0",
|