@esic-lab/data-core-ui 0.0.53 → 0.0.55

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/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, max) {
1673
- const mergedMax = max || 255;
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, max) {
1967
+ _sc(rgb, value, max2) {
1968
1968
  const clone = this.clone();
1969
- clone[rgb] = limitRange(value, max);
1969
+ clone[rgb] = limitRange(value, max2);
1970
1970
  return clone;
1971
1971
  }
1972
1972
  _c(input) {
@@ -2956,7 +2956,8 @@ function FileUploader({
2956
2956
  value,
2957
2957
  uploadText = "\u0E41\u0E19\u0E1A\u0E44\u0E1F\u0E25\u0E4C",
2958
2958
  uploaderWidth = "w-full",
2959
- attachWidth = "w-full"
2959
+ attachWidth = "w-full",
2960
+ readOnly = false
2960
2961
  }) {
2961
2962
  const [internalFileList, setInternalFileList] = useState12([]);
2962
2963
  const [uploading, setUploading] = useState12(false);
@@ -3028,7 +3029,7 @@ function FileUploader({
3028
3029
  };
3029
3030
  return /* @__PURE__ */ jsxs30("div", { className: "w-full", children: [
3030
3031
  label && /* @__PURE__ */ jsx34("p", { className: "body-1", children: label }),
3031
- /* @__PURE__ */ jsxs30("div", { className: uploaderWidth, children: [
3032
+ !readOnly && /* @__PURE__ */ jsxs30("div", { className: uploaderWidth, children: [
3032
3033
  mode === "upload" ? /* @__PURE__ */ jsx34(
3033
3034
  "button",
3034
3035
  {
@@ -3098,7 +3099,7 @@ function FileUploader({
3098
3099
  /* @__PURE__ */ jsx34("div", { className: "w-[24px] h-[24px] flex items-center justify-center", children: /* @__PURE__ */ jsx34(IconFileDescription, { size: 20 }) }),
3099
3100
  /* @__PURE__ */ jsx34("span", { className: "truncate", children: file.name || file.fileName })
3100
3101
  ] }),
3101
- !disabled && /* @__PURE__ */ jsx34(
3102
+ !readOnly && !disabled && /* @__PURE__ */ jsx34(
3102
3103
  IconTrash2,
3103
3104
  {
3104
3105
  size: 20,
@@ -4287,7 +4288,7 @@ var QRCodeGenerator = ({
4287
4288
  fileBaseName = "qr-code"
4288
4289
  }) => {
4289
4290
  const canvasRef = useRef7(null);
4290
- const [format3, setFormat] = useState19("png");
4291
+ const [format4, setFormat] = useState19("png");
4291
4292
  const [exportSize, setExportSize] = useState19(defaultExportSize);
4292
4293
  const sizeOption = [
4293
4294
  {
@@ -4341,7 +4342,7 @@ var QRCodeGenerator = ({
4341
4342
  }, [url, previewSize]);
4342
4343
  const download = async () => {
4343
4344
  try {
4344
- if (format3 === "svg") {
4345
+ if (format4 === "svg") {
4345
4346
  const svgString = await QRCode.toString(url, {
4346
4347
  type: "svg",
4347
4348
  width: exportSize,
@@ -4357,9 +4358,9 @@ var QRCodeGenerator = ({
4357
4358
  width: exportSize,
4358
4359
  margin: 1
4359
4360
  });
4360
- const mime = format3 === "png" ? "image/png" : "image/jpeg";
4361
- const dataURL = format3 === "jpeg" ? offscreen.toDataURL(mime, 0.92) : offscreen.toDataURL(mime);
4362
- triggerDownload(dataURL, `${fileBaseName}.${format3}`);
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}`);
4363
4364
  }
4364
4365
  } catch (err) {
4365
4366
  console.error("Failed to generate QR export:", err);
@@ -4392,7 +4393,7 @@ var QRCodeGenerator = ({
4392
4393
  SelectField,
4393
4394
  {
4394
4395
  label: "\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A",
4395
- value: format3,
4396
+ value: format4,
4396
4397
  onChange: (e) => setFormat(e.target.value),
4397
4398
  options: typeOption
4398
4399
  }
@@ -4452,9 +4453,164 @@ function TabProject({ tabOption, now, onChange }) {
4452
4453
  }
4453
4454
  );
4454
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("title", { children: "Bar chart" }),
4554
+ /* @__PURE__ */ jsx45("g", { ref: gRef, transform: `translate(${margin.left},${margin.top})` }),
4555
+ /* @__PURE__ */ jsx45("g", { ref: xAxisRef }),
4556
+ /* @__PURE__ */ jsx45("g", { ref: yAxisRef })
4557
+ ] }) });
4558
+ };
4559
+
4560
+ // src/Chart/PieChart/PieChart.tsx
4561
+ import React3, { useRef as useRef9, useEffect as useEffect10 } from "react";
4562
+ import * as d32 from "d3";
4563
+ import { jsx as jsx46, jsxs as jsxs40 } from "react/jsx-runtime";
4564
+ var defaultColors = d32.schemeCategory10;
4565
+ var PieChart = ({
4566
+ title,
4567
+ description,
4568
+ data,
4569
+ width,
4570
+ height,
4571
+ colorPalette = defaultColors
4572
+ }) => {
4573
+ const svgRef = useRef9(null);
4574
+ const [dataSide, setDataSide] = React3.useState([]);
4575
+ useEffect10(() => {
4576
+ if (!svgRef.current) return;
4577
+ d32.select(svgRef.current).selectAll("*").remove();
4578
+ const radius = Math.min(width, height) / 2;
4579
+ const totalValue = d32.sum(data, (d) => d.value) ?? 0;
4580
+ const svg = d32.select(svgRef.current).attr("width", width).attr("height", height).append("g").attr("transform", `translate(${width / 2}, ${height / 2})`);
4581
+ const pie2 = d32.pie().value((d) => d.value);
4582
+ const arc2 = d32.arc().innerRadius(0).outerRadius(radius);
4583
+ const arcs = svg.selectAll(".arc").data(pie2(data)).enter().append("g").attr("class", "arc");
4584
+ arcs.append("path").attr("d", arc2).attr("fill", (d, i) => colorPalette[i]).attr("stroke", "white").attr("stroke-width", 2).attr("stroke-linejoin", "round");
4585
+ setDataSide(
4586
+ data.map((d, i) => ({
4587
+ color: colorPalette[i],
4588
+ label: d.label,
4589
+ value: d.value
4590
+ }))
4591
+ );
4592
+ 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) => {
4593
+ const percentage = (d.data.value / totalValue * 100).toFixed(1);
4594
+ return `${percentage}%`;
4595
+ });
4596
+ }, [data, width, height]);
4597
+ return /* @__PURE__ */ jsxs40("div", { children: [
4598
+ title && /* @__PURE__ */ jsx46("p", { className: "body-2", children: title }),
4599
+ description && /* @__PURE__ */ jsx46("p", { className: "caption-1", children: description }),
4600
+ /* @__PURE__ */ jsxs40("div", { className: "flex", children: [
4601
+ /* @__PURE__ */ jsx46("svg", { ref: svgRef }),
4602
+ /* @__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: [
4603
+ /* @__PURE__ */ jsx46("div", { className: "w-[20px] h-[20px]", style: { backgroundColor: d.color } }),
4604
+ /* @__PURE__ */ jsx46("div", { children: d.label }),
4605
+ /* @__PURE__ */ jsx46("div", { children: d.value })
4606
+ ] }, i)) })
4607
+ ] })
4608
+ ] });
4609
+ };
4455
4610
  export {
4456
4611
  AntDModal,
4457
4612
  AntDataTable,
4613
+ BarChart,
4458
4614
  Breadcrumbs,
4459
4615
  Calendar,
4460
4616
  Checkbox,
@@ -4474,6 +4630,7 @@ export {
4474
4630
  KpiSection,
4475
4631
  Loader,
4476
4632
  MenuNavBar,
4633
+ PieChart,
4477
4634
  PrimaryButton,
4478
4635
  ProfileSelect,
4479
4636
  ProgressBar,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@esic-lab/data-core-ui",
3
- "version": "0.0.53",
3
+ "version": "0.0.55",
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 --dts --dts-resolve --format esm,cjs --out-dir dist && npm run copy-assets",
45
- "copy-assets": "xcopy src\\assets dist\\assets /E /I /Y"
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",