@quantumwake/terminal-ux-dashboard-components 0.1.19 → 0.1.20

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.cjs CHANGED
@@ -276,8 +276,54 @@ var DEFAULT_CHART_STYLE = {
276
276
  titleAlign: "left",
277
277
  titleBold: false,
278
278
  titleBackground: "",
279
- titleColor: ""
279
+ titleColor: "",
280
+ // Chart frame + series color model.
281
+ height: 0,
282
+ margin: null,
283
+ maxXTicks: 0,
284
+ seriesColors: []
280
285
  };
286
+ var DEFAULT_SERIES_COLORS = [
287
+ "#3987e5",
288
+ // blue
289
+ "#d95926",
290
+ // orange
291
+ "#199e70",
292
+ // aqua
293
+ "#c98500",
294
+ // yellow
295
+ "#d55181",
296
+ // magenta
297
+ "#008300",
298
+ // green
299
+ "#9085e9",
300
+ // violet
301
+ "#e66767"
302
+ // red
303
+ ];
304
+ var SERIES_OVERFLOW_COLOR = "#707078";
305
+ var seriesColor = (i, style) => {
306
+ const s = withStyleDefaults(style);
307
+ const palette = s.seriesColors.length ? s.seriesColors : DEFAULT_SERIES_COLORS;
308
+ return i < palette.length ? palette[i] : SERIES_OVERFLOW_COLOR;
309
+ };
310
+ var chartSizing = (style, defaultMargin) => {
311
+ const s = withStyleDefaults(style);
312
+ return {
313
+ frameClass: s.height > 0 ? "w-full" : "h-full w-full min-h-[160px]",
314
+ frameStyle: s.height > 0 ? { height: s.height } : {},
315
+ margin: { ...defaultMargin, ...s.margin || {} }
316
+ };
317
+ };
318
+ function thinTicks(values, max) {
319
+ if (max <= 0 || values.length <= max) return void 0;
320
+ if (max === 1) return [values[values.length - 1]];
321
+ const picked = [];
322
+ for (let i = 0; i < max; i++) {
323
+ picked.push(values[Math.round(i * (values.length - 1) / (max - 1))]);
324
+ }
325
+ return [...new Set(picked)];
326
+ }
281
327
  var LEGEND_ANCHORS = ["right", "top-left", "top-right", "bottom-left", "bottom-right", "none"];
282
328
  var withStyleDefaults = (style) => ({
283
329
  ...DEFAULT_CHART_STYLE,
@@ -536,15 +582,17 @@ function BarView({ records, groupColumn, valueColumn, aggFn = "count", data: pre
536
582
  return Object.entries(groups).map(([key, recs]) => ({ group: key, value: aggregate(recs, valueColumn, aggFn) })).sort((a, b) => b.value - a.value).slice(0, 50);
537
583
  }, [records, groupColumn, valueColumn, aggFn, presetData]);
538
584
  const data = presetData || computed;
539
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full w-full min-h-[160px]", children: /* @__PURE__ */ jsxRuntime.jsx(
585
+ const s = withStyleDefaults(style);
586
+ const { frameClass, frameStyle, margin } = chartSizing(style, { top: 20, right: 20, bottom: 60, left: 60 });
587
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: frameClass, style: frameStyle, children: /* @__PURE__ */ jsxRuntime.jsx(
540
588
  bar.ResponsiveBar,
541
589
  {
542
590
  data,
543
591
  keys: ["value"],
544
592
  indexBy: "group",
545
- margin: { top: 20, right: 20, bottom: 60, left: 60 },
593
+ margin,
546
594
  padding: 0.3,
547
- colors: ["rgba(74, 222, 128, 0.8)"],
595
+ colors: [s.seriesColors[0] || "rgba(74, 222, 128, 0.8)"],
548
596
  borderColor: { from: "color", modifiers: [["darker", 1.6]] },
549
597
  axisBottom: makeAxis(style, "x", groupColumn),
550
598
  axisLeft: makeAxis(style, "y", valueColumn, { numeric: true }),
@@ -568,16 +616,19 @@ function PieView({ records, groupColumn, data: presetData, style }) {
568
616
  }, [records, groupColumn, presetData]);
569
617
  const data = presetData || computed;
570
618
  const legend = legendConfig(style);
571
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full w-full min-h-[160px]", children: /* @__PURE__ */ jsxRuntime.jsx(
619
+ const s = withStyleDefaults(style);
620
+ const { frameClass, frameStyle, margin } = chartSizing(style, { top: 20, right: 120, bottom: 20, left: 20 });
621
+ const colorById = new Map(data.map((d, i) => [d.id, seriesColor(i, s)]));
622
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: frameClass, style: frameStyle, children: /* @__PURE__ */ jsxRuntime.jsx(
572
623
  pie.ResponsivePie,
573
624
  {
574
625
  data,
575
- margin: { top: 20, right: 120, bottom: 20, left: 20 },
626
+ margin,
576
627
  innerRadius: 0.4,
577
628
  padAngle: 1,
578
629
  cornerRadius: 3,
579
630
  activeOuterRadiusOffset: 8,
580
- colors: { scheme: "set2" },
631
+ colors: ((d) => colorById.get(d.id)),
581
632
  borderWidth: 1,
582
633
  borderColor: { from: "color", modifiers: [["darker", 0.2]] },
583
634
  arcLinkLabelsSkipAngle: 10,
@@ -604,29 +655,54 @@ function LineView({ records, xColumn, yColumn, data: presetData, style }) {
604
655
  }];
605
656
  }, [records, xColumn, yColumn, presetData]);
606
657
  const data = presetData || computed;
607
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full w-full min-h-[160px]", children: /* @__PURE__ */ jsxRuntime.jsx(
658
+ const s = withStyleDefaults(style);
659
+ const { frameClass, frameStyle, margin } = chartSizing(style, { top: 20, right: 20, bottom: 60, left: 60 });
660
+ const colorById = new Map(data.map((serie, i) => [
661
+ serie.id,
662
+ s.seriesColors.length || data.length > 1 ? seriesColor(i, s) : "rgba(96, 165, 250, 0.9)"
663
+ ]));
664
+ const tickValues = thinTicks(data[0]?.data.map((d) => d.x) ?? [], s.maxXTicks);
665
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: frameClass, style: frameStyle, children: /* @__PURE__ */ jsxRuntime.jsx(
608
666
  line.ResponsiveLine,
609
667
  {
610
668
  data,
611
- margin: { top: 20, right: 20, bottom: 60, left: 60 },
669
+ margin,
612
670
  xScale: { type: "point" },
613
671
  yScale: { type: "linear", min: "auto", max: "auto" },
614
672
  curve: "monotoneX",
615
673
  enableArea: true,
616
674
  areaOpacity: 0.15,
617
- colors: ["rgba(96, 165, 250, 0.9)"],
675
+ colors: ((serie) => colorById.get(serie.id)),
618
676
  pointSize: (data[0]?.data.length ?? 0) > 50 ? 0 : 6,
619
677
  pointColor: { theme: "background" },
620
678
  pointBorderWidth: 2,
621
679
  pointBorderColor: { from: "serieColor" },
622
680
  enableGridX: false,
623
- axisBottom: makeAxis(style, "x", xColumn),
681
+ axisBottom: { ...makeAxis(style, "x", xColumn), ...tickValues ? { tickValues } : {} },
624
682
  axisLeft: makeAxis(style, "y", yColumn, { numeric: true }),
625
683
  useMesh: true,
626
684
  theme: buildNivoTheme(style)
627
685
  }
628
686
  ) });
629
687
  }
688
+ function SparklineView({ data, height = 56, color = "#3987e5" }) {
689
+ const gradientId = react.useId();
690
+ const width = 260;
691
+ const pts = data && data.length ? data : [0];
692
+ const max = Math.max(...pts, 1);
693
+ const dx = pts.length > 1 ? width / (pts.length - 1) : width;
694
+ const xy = (v, i) => [i * dx, height - v / max * (height - 4) - 2];
695
+ const line = pts.map((v, i) => `${i === 0 ? "M" : "L"} ${xy(v, i)[0].toFixed(1)} ${xy(v, i)[1].toFixed(1)}`).join(" ");
696
+ const area = `${line} L ${width} ${height} L 0 ${height} Z`;
697
+ return /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: `0 0 ${width} ${height}`, height, className: "w-full", preserveAspectRatio: "none", children: [
698
+ /* @__PURE__ */ jsxRuntime.jsx("defs", { children: /* @__PURE__ */ jsxRuntime.jsxs("linearGradient", { id: gradientId, x1: "0", y1: "0", x2: "0", y2: "1", children: [
699
+ /* @__PURE__ */ jsxRuntime.jsx("stop", { offset: "0%", stopColor: color, stopOpacity: "0.25" }),
700
+ /* @__PURE__ */ jsxRuntime.jsx("stop", { offset: "100%", stopColor: color, stopOpacity: "0" })
701
+ ] }) }),
702
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: area, fill: `url(#${gradientId})` }),
703
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: line, fill: "none", stroke: color, strokeWidth: "2", vectorEffect: "non-scaling-stroke" })
704
+ ] });
705
+ }
630
706
  function ScatterView({ records, xColumn, yColumn, data: presetData, style }) {
631
707
  const computed = react.useMemo(() => {
632
708
  if (presetData || !records) return [];
@@ -634,14 +710,20 @@ function ScatterView({ records, xColumn, yColumn, data: presetData, style }) {
634
710
  return [{ id: `${xColumn} vs ${yColumn}`, data: points }];
635
711
  }, [records, xColumn, yColumn, presetData]);
636
712
  const data = presetData || computed;
637
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full w-full min-h-[160px]", children: /* @__PURE__ */ jsxRuntime.jsx(
713
+ const s = withStyleDefaults(style);
714
+ const { frameClass, frameStyle, margin } = chartSizing(style, { top: 20, right: 20, bottom: 60, left: 60 });
715
+ const colorById = new Map(data.map((serie, i) => [
716
+ serie.id,
717
+ s.seriesColors.length || data.length > 1 ? seriesColor(i, s) : "rgba(167, 139, 250, 0.7)"
718
+ ]));
719
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: frameClass, style: frameStyle, children: /* @__PURE__ */ jsxRuntime.jsx(
638
720
  scatterplot.ResponsiveScatterPlot,
639
721
  {
640
722
  data,
641
- margin: { top: 20, right: 20, bottom: 60, left: 60 },
723
+ margin,
642
724
  xScale: { type: "linear", min: "auto", max: "auto" },
643
725
  yScale: { type: "linear", min: "auto", max: "auto" },
644
- colors: ["rgba(167, 139, 250, 0.7)"],
726
+ colors: ((serie) => colorById.get(serie.serieId ?? serie.id ?? "")),
645
727
  nodeSize: 6,
646
728
  axisBottom: makeAxis(style, "x", xColumn, { numeric: true }),
647
729
  axisLeft: makeAxis(style, "y", yColumn, { numeric: true }),
@@ -737,8 +819,8 @@ function HeatmapView({
737
819
  if (!data.length || !data[0].data.length) {
738
820
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-8 text-center text-midnight-text-muted", children: "Not enough distinct values for a heatmap" });
739
821
  }
740
- const margin = showTotals ? { top: 60, right: 70, bottom: 60, left: 100 } : { top: 60, right: 20, bottom: 20, left: 100 };
741
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full w-full min-h-[160px]", children: /* @__PURE__ */ jsxRuntime.jsx(
822
+ const { frameClass, frameStyle, margin } = chartSizing(style, showTotals ? { top: 60, right: 70, bottom: 60, left: 100 } : { top: 60, right: 20, bottom: 20, left: 100 });
823
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: frameClass, style: frameStyle, children: /* @__PURE__ */ jsxRuntime.jsx(
742
824
  heatmap.ResponsiveHeatMap,
743
825
  {
744
826
  data,
@@ -892,11 +974,12 @@ function HeatmapPlusView({
892
974
  }
893
975
  const { nivoData, t } = built;
894
976
  const tAt = (serieId, x) => t.get(cellKey(serieId, x)) ?? 0;
895
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full w-full min-h-[160px]", children: /* @__PURE__ */ jsxRuntime.jsx(
977
+ const { frameClass, frameStyle, margin } = chartSizing(style, { top: 60, right: 20, bottom: showMargins ? 60 : 20, left: 100 });
978
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: frameClass, style: frameStyle, children: /* @__PURE__ */ jsxRuntime.jsx(
896
979
  heatmap.ResponsiveHeatMap,
897
980
  {
898
981
  data: nivoData,
899
- margin: { top: 60, right: 20, bottom: showMargins ? 60 : 20, left: 100 },
982
+ margin,
900
983
  valueFormat: ((v) => fmtNum2(v)),
901
984
  axisTop: { tickSize: 5, tickPadding: 5, tickRotation: s.xTickRotation, legend: s.showXLegend ? s.xAxisLabel || colColumn : "", legendPosition: s.xLegendPosition, legendOffset: -50 },
902
985
  axisLeft: { tickSize: 5, tickPadding: 5, legend: s.showYLegend ? s.yAxisLabel || rowColumn : "", legendPosition: s.yLegendPosition, legendOffset: -80 },
@@ -2912,6 +2995,7 @@ exports.BarView = BarView;
2912
2995
  exports.ChartBuilder = ChartBuilder;
2913
2996
  exports.ChartStyleControls = ChartStyleControls;
2914
2997
  exports.DEFAULT_CHART_STYLE = DEFAULT_CHART_STYLE;
2998
+ exports.DEFAULT_SERIES_COLORS = DEFAULT_SERIES_COLORS;
2915
2999
  exports.DashboardProvider = DashboardProvider;
2916
3000
  exports.DashboardRenderer = DashboardRenderer;
2917
3001
  exports.DataExplorer = DataExplorer;
@@ -2925,13 +3009,16 @@ exports.MetricView = MetricView;
2925
3009
  exports.PanelChart = PanelChart;
2926
3010
  exports.PieView = PieView;
2927
3011
  exports.PivotView = PivotView;
3012
+ exports.SERIES_OVERFLOW_COLOR = SERIES_OVERFLOW_COLOR;
2928
3013
  exports.ScatterView = ScatterView;
3014
+ exports.SparklineView = SparklineView;
2929
3015
  exports.SqlConsole = SqlConsole;
2930
3016
  exports.aggExpr = aggExpr;
2931
3017
  exports.aggregate = aggregate;
2932
3018
  exports.axisLegend = axisLegend;
2933
3019
  exports.buildChartSQL = buildChartSQL;
2934
3020
  exports.buildNivoTheme = buildNivoTheme;
3021
+ exports.chartSizing = chartSizing;
2935
3022
  exports.compileWhere = compileWhere;
2936
3023
  exports.groupBy = groupBy;
2937
3024
  exports.heatColor = heatColor;
@@ -2940,7 +3027,9 @@ exports.legendConfig = legendConfig;
2940
3027
  exports.normalizeCells = normalizeCells;
2941
3028
  exports.qIdent = qIdent;
2942
3029
  exports.qLit = qLit;
3030
+ exports.seriesColor = seriesColor;
2943
3031
  exports.shapeChartData = shapeChartData;
3032
+ exports.thinTicks = thinTicks;
2944
3033
  exports.useCapabilities = useCapabilities;
2945
3034
  exports.useDashboard = useDashboard;
2946
3035
  exports.withStyleDefaults = withStyleDefaults;