drizzle-cube 0.1.68 → 0.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.
Files changed (107) hide show
  1. package/dist/adapters/{compiler-CghsDLXl.cjs → compiler-DP1pPIcg.cjs} +9 -9
  2. package/dist/adapters/{compiler-BnHK-nxh.js → compiler-gcKytLwd.js} +12 -13
  3. package/dist/adapters/express/index.cjs +1 -1
  4. package/dist/adapters/express/index.js +1 -1
  5. package/dist/adapters/fastify/index.cjs +1 -1
  6. package/dist/adapters/fastify/index.js +1 -1
  7. package/dist/adapters/hono/index.cjs +1 -1
  8. package/dist/adapters/hono/index.js +1 -1
  9. package/dist/adapters/nextjs/index.cjs +1 -1
  10. package/dist/adapters/nextjs/index.js +1 -1
  11. package/dist/client/charts/ChartLoader.d.ts +56 -0
  12. package/dist/client/charts/lazyChartConfigRegistry.d.ts +90 -0
  13. package/dist/client/charts.d.ts +6 -0
  14. package/dist/client/charts.js +38 -15
  15. package/dist/client/charts.js.map +1 -1
  16. package/dist/client/chunks/chart-activitygridchart-BRk9BNnp.js +3713 -0
  17. package/dist/client/chunks/chart-activitygridchart-BRk9BNnp.js.map +1 -0
  18. package/dist/client/chunks/chart-activitygridchart-config-D9CgNH02.js +51 -0
  19. package/dist/client/chunks/chart-activitygridchart-config-D9CgNH02.js.map +1 -0
  20. package/dist/client/chunks/chart-areachart-Beu8sO9v.js +204 -0
  21. package/dist/client/chunks/chart-areachart-Beu8sO9v.js.map +1 -0
  22. package/dist/client/chunks/chart-areachart-config-InZgxubz.js +66 -0
  23. package/dist/client/chunks/chart-areachart-config-InZgxubz.js.map +1 -0
  24. package/dist/client/chunks/chart-barchart-BzoejYkT.js +177 -0
  25. package/dist/client/chunks/chart-barchart-BzoejYkT.js.map +1 -0
  26. package/dist/client/chunks/chart-barchart-config-DxatOnVV.js +59 -0
  27. package/dist/client/chunks/chart-barchart-config-DxatOnVV.js.map +1 -0
  28. package/dist/client/chunks/chart-bubblechart-Dg7sT_Mm.js +210 -0
  29. package/dist/client/chunks/chart-bubblechart-Dg7sT_Mm.js.map +1 -0
  30. package/dist/client/chunks/chart-bubblechart-config-CcZTMTCx.js +59 -0
  31. package/dist/client/chunks/chart-bubblechart-config-CcZTMTCx.js.map +1 -0
  32. package/dist/client/chunks/chart-chartcontainer-CdwzIKP1.js +103 -0
  33. package/dist/client/chunks/chart-chartcontainer-CdwzIKP1.js.map +1 -0
  34. package/dist/client/chunks/chart-charttooltip-NrFVM1cJ.js +26 -0
  35. package/dist/client/chunks/chart-charttooltip-NrFVM1cJ.js.map +1 -0
  36. package/dist/client/chunks/chart-datatable-BvV7gLPZ.js +57 -0
  37. package/dist/client/chunks/chart-datatable-BvV7gLPZ.js.map +1 -0
  38. package/dist/client/chunks/chart-datatable-config-D7mojhYA.js +22 -0
  39. package/dist/client/chunks/chart-datatable-config-D7mojhYA.js.map +1 -0
  40. package/dist/client/chunks/chart-kpidelta-config-icJXuFxe.js +99 -0
  41. package/dist/client/chunks/chart-kpidelta-config-icJXuFxe.js.map +1 -0
  42. package/dist/client/chunks/chart-kpidelta-p1lVVG5v.js +434 -0
  43. package/dist/client/chunks/chart-kpidelta-p1lVVG5v.js.map +1 -0
  44. package/dist/client/chunks/chart-kpinumber-BFtxFeqq.js +398 -0
  45. package/dist/client/chunks/chart-kpinumber-BFtxFeqq.js.map +1 -0
  46. package/dist/client/chunks/chart-kpinumber-config-T39g03ud.js +77 -0
  47. package/dist/client/chunks/chart-kpinumber-config-T39g03ud.js.map +1 -0
  48. package/dist/client/chunks/chart-kpitext-CX1s1u8B.js +165 -0
  49. package/dist/client/chunks/chart-kpitext-CX1s1u8B.js.map +1 -0
  50. package/dist/client/chunks/chart-kpitext-config-BbJGXAVk.js +49 -0
  51. package/dist/client/chunks/chart-kpitext-config-BbJGXAVk.js.map +1 -0
  52. package/dist/client/chunks/chart-linechart-Dgb10zbj.js +155 -0
  53. package/dist/client/chunks/chart-linechart-Dgb10zbj.js.map +1 -0
  54. package/dist/client/chunks/chart-linechart-config-BS1qVC8K.js +54 -0
  55. package/dist/client/chunks/chart-linechart-config-BS1qVC8K.js.map +1 -0
  56. package/dist/client/chunks/chart-markdownchart-C3FAQFuO.js +254 -0
  57. package/dist/client/chunks/chart-markdownchart-C3FAQFuO.js.map +1 -0
  58. package/dist/client/chunks/chart-markdownchart-config-DMCD8phf.js +62 -0
  59. package/dist/client/chunks/chart-markdownchart-config-DMCD8phf.js.map +1 -0
  60. package/dist/client/chunks/chart-piechart-B-0BQh-d.js +121 -0
  61. package/dist/client/chunks/chart-piechart-B-0BQh-d.js.map +1 -0
  62. package/dist/client/chunks/chart-piechart-config-6ZK8XaSX.js +32 -0
  63. package/dist/client/chunks/chart-piechart-config-6ZK8XaSX.js.map +1 -0
  64. package/dist/client/chunks/chart-radarchart-BwZM1yTd.js +124 -0
  65. package/dist/client/chunks/chart-radarchart-BwZM1yTd.js.map +1 -0
  66. package/dist/client/chunks/chart-radarchart-config-CCWOkkwO.js +38 -0
  67. package/dist/client/chunks/chart-radarchart-config-CCWOkkwO.js.map +1 -0
  68. package/dist/client/chunks/chart-radialbarchart-CythI1zx.js +109 -0
  69. package/dist/client/chunks/chart-radialbarchart-CythI1zx.js.map +1 -0
  70. package/dist/client/chunks/chart-radialbarchart-config-DicXYrMW.js +31 -0
  71. package/dist/client/chunks/chart-radialbarchart-config-DicXYrMW.js.map +1 -0
  72. package/dist/client/chunks/chart-scatterchart-config-DgYa-5vm.js +41 -0
  73. package/dist/client/chunks/chart-scatterchart-config-DgYa-5vm.js.map +1 -0
  74. package/dist/client/chunks/chart-scatterchart-om9-qmtE.js +201 -0
  75. package/dist/client/chunks/chart-scatterchart-om9-qmtE.js.map +1 -0
  76. package/dist/client/chunks/chart-treemapchart-Dc35Miif.js +253 -0
  77. package/dist/client/chunks/chart-treemapchart-Dc35Miif.js.map +1 -0
  78. package/dist/client/chunks/chart-treemapchart-config-DGhteyBe.js +40 -0
  79. package/dist/client/chunks/chart-treemapchart-config-DGhteyBe.js.map +1 -0
  80. package/dist/client/chunks/charts-DL9XOlaK.js +286 -0
  81. package/dist/client/chunks/charts-DL9XOlaK.js.map +1 -0
  82. package/dist/client/chunks/{icons-Bky5w1eH.js → icons-D-n_woAP.js} +833 -783
  83. package/dist/client/chunks/icons-D-n_woAP.js.map +1 -0
  84. package/dist/client/chunks/index-DpEuGmcW.js +8707 -0
  85. package/dist/client/chunks/index-DpEuGmcW.js.map +1 -0
  86. package/dist/client/components/QueryBuilder/ShareWarningModal.d.ts +9 -0
  87. package/dist/client/components/QueryBuilder/shareUtils.d.ts +59 -0
  88. package/dist/client/components/QueryBuilder/types.d.ts +21 -1
  89. package/dist/client/components.js +11 -11
  90. package/dist/client/hooks.js +3 -3
  91. package/dist/client/index.d.ts +18 -1
  92. package/dist/client/index.js +9135 -39
  93. package/dist/client/index.js.map +1 -1
  94. package/dist/client/providers.js +4 -4
  95. package/dist/client/styles.css +1 -1
  96. package/dist/client-bundle-stats.html +1 -1
  97. package/dist/server/index.cjs +16 -16
  98. package/dist/server/index.d.ts +0 -286
  99. package/dist/server/index.js +767 -881
  100. package/package.json +8 -2
  101. package/dist/client/chunks/charts-jwgcWeFt.js +0 -2580
  102. package/dist/client/chunks/charts-jwgcWeFt.js.map +0 -1
  103. package/dist/client/chunks/components-fN-QOY6G.js +0 -21835
  104. package/dist/client/chunks/components-fN-QOY6G.js.map +0 -1
  105. package/dist/client/chunks/icons-Bky5w1eH.js.map +0 -1
  106. package/dist/client/chunks/providers-D7zRgZrO.js +0 -308
  107. package/dist/client/chunks/providers-D7zRgZrO.js.map +0 -1
@@ -0,0 +1,59 @@
1
+ import { jsx as s } from "react/jsx-runtime";
2
+ import { I as i, b as a } from "./icons-D-n_woAP.js";
3
+ const r = {
4
+ icon: ({ className: e }) => /* @__PURE__ */ s(i, { icon: a, className: e }),
5
+ description: "Compare values across categories",
6
+ useCase: "Best for comparing discrete categories, showing rankings, or displaying changes over time",
7
+ dropZones: [
8
+ {
9
+ key: "xAxis",
10
+ label: "X-Axis (Categories)",
11
+ description: "Dimensions and time dimensions for grouping",
12
+ mandatory: !1,
13
+ acceptTypes: ["dimension", "timeDimension"],
14
+ emptyText: "Drop dimensions & time dimensions here"
15
+ },
16
+ {
17
+ key: "yAxis",
18
+ label: "Y-Axis (Values)",
19
+ description: "Measures for bar heights",
20
+ mandatory: !0,
21
+ acceptTypes: ["measure"],
22
+ emptyText: "Drop measures here"
23
+ },
24
+ {
25
+ key: "series",
26
+ label: "Series (Split into Multiple Series)",
27
+ description: "Dimensions to create separate data series",
28
+ mandatory: !1,
29
+ acceptTypes: ["dimension"],
30
+ emptyText: "Drop dimensions here to split data into series"
31
+ }
32
+ ],
33
+ displayOptions: ["showLegend", "showGrid", "showTooltip", "hideHeader"],
34
+ displayOptionsConfig: [
35
+ {
36
+ key: "stackType",
37
+ label: "Stacking",
38
+ type: "select",
39
+ defaultValue: "none",
40
+ options: [
41
+ { value: "none", label: "None" },
42
+ { value: "normal", label: "Stacked" },
43
+ { value: "percent", label: "Stacked 100%" }
44
+ ],
45
+ description: "How to stack multiple bar series"
46
+ },
47
+ {
48
+ key: "target",
49
+ label: "Target Values",
50
+ type: "string",
51
+ placeholder: "e.g., 100 or 50,75 for spread",
52
+ description: "Single value or comma-separated values to spread across X-axis"
53
+ }
54
+ ]
55
+ };
56
+ export {
57
+ r as barChartConfig
58
+ };
59
+ //# sourceMappingURL=chart-barchart-config-DxatOnVV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chart-barchart-config-DxatOnVV.js","sources":["../../../src/client/components/charts/BarChart.config.tsx"],"sourcesContent":["import type { ChartTypeConfig } from '../../charts/chartConfigs'\nimport { Icon } from '@iconify/react'\nimport chartBarIcon from '@iconify-icons/tabler/chart-bar'\n\n/**\n * Configuration for the bar chart type\n */\nexport const barChartConfig: ChartTypeConfig = {\n icon: ({ className }) => <Icon icon={chartBarIcon} className={className} />,\n description: 'Compare values across categories',\n useCase: 'Best for comparing discrete categories, showing rankings, or displaying changes over time',\n dropZones: [\n {\n key: 'xAxis',\n label: 'X-Axis (Categories)',\n description: 'Dimensions and time dimensions for grouping',\n mandatory: false,\n acceptTypes: ['dimension', 'timeDimension'],\n emptyText: 'Drop dimensions & time dimensions here'\n },\n {\n key: 'yAxis',\n label: 'Y-Axis (Values)',\n description: 'Measures for bar heights',\n mandatory: true,\n acceptTypes: ['measure'],\n emptyText: 'Drop measures here'\n },\n {\n key: 'series',\n label: 'Series (Split into Multiple Series)',\n description: 'Dimensions to create separate data series',\n mandatory: false,\n acceptTypes: ['dimension'],\n emptyText: 'Drop dimensions here to split data into series'\n }\n ],\n displayOptions: ['showLegend', 'showGrid', 'showTooltip', 'hideHeader'],\n displayOptionsConfig: [\n {\n key: 'stackType',\n label: 'Stacking',\n type: 'select',\n defaultValue: 'none',\n options: [\n { value: 'none', label: 'None' },\n { value: 'normal', label: 'Stacked' },\n { value: 'percent', label: 'Stacked 100%' }\n ],\n description: 'How to stack multiple bar series'\n },\n {\n key: 'target',\n label: 'Target Values',\n type: 'string',\n placeholder: 'e.g., 100 or 50,75 for spread',\n description: 'Single value or comma-separated values to spread across X-axis'\n }\n ]\n}"],"names":["barChartConfig","className","jsx","Icon","chartBarIcon"],"mappings":";;AAOO,MAAMA,IAAkC;AAAA,EAC7C,MAAM,CAAC,EAAE,WAAAC,EAAA,MAAgB,gBAAAC,EAACC,GAAA,EAAK,MAAMC,GAAc,WAAAH,GAAsB;AAAA,EACzE,aAAa;AAAA,EACb,SAAS;AAAA,EACT,WAAW;AAAA,IACT;AAAA,MACE,KAAK;AAAA,MACL,OAAO;AAAA,MACP,aAAa;AAAA,MACb,WAAW;AAAA,MACX,aAAa,CAAC,aAAa,eAAe;AAAA,MAC1C,WAAW;AAAA,IAAA;AAAA,IAEb;AAAA,MACE,KAAK;AAAA,MACL,OAAO;AAAA,MACP,aAAa;AAAA,MACb,WAAW;AAAA,MACX,aAAa,CAAC,SAAS;AAAA,MACvB,WAAW;AAAA,IAAA;AAAA,IAEb;AAAA,MACE,KAAK;AAAA,MACL,OAAO;AAAA,MACP,aAAa;AAAA,MACb,WAAW;AAAA,MACX,aAAa,CAAC,WAAW;AAAA,MACzB,WAAW;AAAA,IAAA;AAAA,EACb;AAAA,EAEF,gBAAgB,CAAC,cAAc,YAAY,eAAe,YAAY;AAAA,EACtE,sBAAsB;AAAA,IACpB;AAAA,MACE,KAAK;AAAA,MACL,OAAO;AAAA,MACP,MAAM;AAAA,MACN,cAAc;AAAA,MACd,SAAS;AAAA,QACP,EAAE,OAAO,QAAQ,OAAO,OAAA;AAAA,QACxB,EAAE,OAAO,UAAU,OAAO,UAAA;AAAA,QAC1B,EAAE,OAAO,WAAW,OAAO,eAAA;AAAA,MAAe;AAAA,MAE5C,aAAa;AAAA,IAAA;AAAA,IAEf;AAAA,MACE,KAAK;AAAA,MACL,OAAO;AAAA,MACP,MAAM;AAAA,MACN,aAAa;AAAA,MACb,aAAa;AAAA,IAAA;AAAA,EACf;AAEJ;"}
@@ -0,0 +1,210 @@
1
+ import { jsx as p, jsxs as K } from "react/jsx-runtime";
2
+ import { useRef as ae, useState as O, useEffect as P, useLayoutEffect as ge } from "react";
3
+ import { u as fe, g as be, w as we, s as D, b as Se, c as oe, i as Ae, p as ce, C as de, l as ue, e as me, d as ve, m as ze, q as Te, h as ye, o as pe, a as ee, j as xe, k as he } from "./chart-activitygridchart-BRk9BNnp.js";
4
+ function Re({
5
+ data: $,
6
+ chartConfig: s,
7
+ displayConfig: b = {},
8
+ queryObject: H,
9
+ height: q = "100%",
10
+ colorPalette: L
11
+ }) {
12
+ const U = ae(null), w = ae(null), [, te] = O(null), [F, E] = O({ width: 0, height: 0 }), [N, W] = O(!1), [se, re] = O("light"), { getFieldLabel: S } = fe();
13
+ P(() => (re(be()), we((o) => {
14
+ re(o);
15
+ })), []);
16
+ const n = {
17
+ showLegend: b?.showLegend ?? !0,
18
+ showGrid: b?.showGrid ?? !0,
19
+ showTooltip: b?.showTooltip ?? !0,
20
+ minBubbleSize: b?.minBubbleSize ?? 5,
21
+ maxBubbleSize: b?.maxBubbleSize ?? 50,
22
+ bubbleOpacity: b?.bubbleOpacity ?? 0.7
23
+ };
24
+ return ge(() => {
25
+ let l = 0;
26
+ const o = 10;
27
+ let d, u;
28
+ const i = () => {
29
+ if (w.current) {
30
+ const { width: h, height: a } = w.current.getBoundingClientRect();
31
+ if (h > 0 && a > 0)
32
+ return E({ width: h, height: a }), W(!0), !0;
33
+ }
34
+ return !1;
35
+ };
36
+ if (!i() && l < o) {
37
+ const h = () => {
38
+ !i() && l < o && (l++, u = setTimeout(() => {
39
+ d = requestAnimationFrame(h);
40
+ }, 50 * l));
41
+ };
42
+ d = requestAnimationFrame(h);
43
+ }
44
+ return () => {
45
+ d && cancelAnimationFrame(d), u && clearTimeout(u);
46
+ };
47
+ }, []), P(() => {
48
+ let l = null;
49
+ const o = () => {
50
+ if (w.current) {
51
+ const { width: d, height: u } = w.current.getBoundingClientRect();
52
+ d > 0 && u > 0 && (E({ width: d, height: u }), N || W(!0));
53
+ }
54
+ };
55
+ return w.current && (l = new ResizeObserver((d) => {
56
+ for (const u of d) {
57
+ const { width: i, height: A } = u.contentRect;
58
+ i > 0 && A > 0 && (E({ width: i, height: A }), N || W(!0));
59
+ }
60
+ }), l.observe(w.current), o()), window.addEventListener("resize", o), () => {
61
+ l && l.disconnect(), window.removeEventListener("resize", o);
62
+ };
63
+ }, [N]), P(() => {
64
+ if (!$ || $.length === 0 || !U.current || !N || F.width === 0 || (D(U.current).selectAll("*").remove(), !s?.xAxis || !s?.yAxis || !s?.series))
65
+ return;
66
+ const l = Array.isArray(s.xAxis) ? s.xAxis[0] : s.xAxis, o = Array.isArray(s.yAxis) ? s.yAxis[0] : s.yAxis, d = Array.isArray(s.series) ? s.series[0] : s.series, u = Array.isArray(s.sizeField) ? s.sizeField[0] : s.sizeField || o, i = Array.isArray(s.colorField) ? s.colorField[0] : s.colorField;
67
+ if (!l || !o || !d || !u)
68
+ return;
69
+ const A = Se(H, l), h = H?.timeDimensions?.some(
70
+ (e) => e.dimension === l
71
+ ) || !1, a = $.map((e) => {
72
+ const t = e[l];
73
+ let r, m;
74
+ if (h && t) {
75
+ const c = String(t);
76
+ let x;
77
+ if (c.match(/^\d{4}-\d{2}-\d{2}[T ]/)) {
78
+ let f = c;
79
+ c.includes(" ") && (f = c.replace(" ", "T").replace("+00", "Z").replace(/\+\d{2}:\d{2}$/, "Z")), !f.endsWith("Z") && !f.includes("+") && (f = f + "Z"), x = new Date(f);
80
+ } else
81
+ x = new Date(c);
82
+ r = isNaN(x.getTime()) ? parseFloat(c) : x.getTime(), m = oe(t, A);
83
+ } else {
84
+ const c = oe(t, A) || t;
85
+ r = typeof c == "string" ? parseFloat(c) : c, m = String(c);
86
+ }
87
+ const y = ce(e[o]), T = ce(e[u]), V = e[d];
88
+ return {
89
+ x: r,
90
+ xLabel: m,
91
+ // Store formatted label for tooltip display
92
+ y,
93
+ // Type assertion: filter below ensures this is never null
94
+ size: T !== null ? Math.abs(T) : 0,
95
+ // Ensure positive size
96
+ color: i ? e[i] : V,
97
+ series: V,
98
+ label: `${V || "Unknown"}`,
99
+ isValid: Ae(r) && y !== null && T !== null && T > 0
100
+ };
101
+ }).filter((e) => e.isValid && e.size > 0);
102
+ if (a.length === 0) return;
103
+ const k = {
104
+ ...de,
105
+ left: de.left + 30,
106
+ // Add extra 30px left margin for Y-axis label
107
+ bottom: n.showLegend && i ? 100 : 40
108
+ // Add extra space for legend
109
+ }, B = F.width - k.left - k.right, v = F.height - k.top - k.bottom, le = D(U.current).attr("width", F.width).attr("height", F.height), z = le.append("g").attr("transform", `translate(${k.left},${k.top})`), Y = ue().domain(me(a, (e) => e.x)).range([0, B]).nice(), _ = ue().domain(me(a, (e) => e.y)).range([v, 0]).nice(), I = ve().domain([0, ze(a, (e) => e.size)]).range([n.minBubbleSize, n.maxBubbleSize]);
110
+ let R, C = !1, j = [];
111
+ if (i && a.length > 0) {
112
+ const e = a.map((t) => {
113
+ const r = t.color;
114
+ return typeof r == "string" ? parseFloat(r) : r;
115
+ }).filter((t) => !isNaN(t));
116
+ if (C = e.length === a.length && e.every((t) => typeof t == "number"), C) {
117
+ const t = Math.min(...e), r = Math.max(...e);
118
+ R = Te().domain([t, r]).range(L?.gradient || ye);
119
+ } else
120
+ j = [...new Set(a.map((t) => String(t.color)))], R = pe().domain(j).range(L?.colors || ee);
121
+ } else
122
+ R = pe().domain(["default"]).range([ee[0]]);
123
+ const Z = (e, t) => getComputedStyle(document.documentElement).getPropertyValue(e).trim() || t, ne = se !== "light", g = ne ? Z("--dc-text-muted", "#cbd5e1") : Z("--dc-text-secondary", "#374151"), M = ne ? Z("--dc-border", "#475569") : "#9ca3af";
124
+ if (n.showGrid) {
125
+ const e = z.append("g").attr("class", "grid").attr("transform", `translate(0,${v})`).call(
126
+ xe(Y).tickSize(-v).tickFormat(() => "")
127
+ );
128
+ e.selectAll("line").style("stroke", M).style("stroke-dasharray", "3,3").style("opacity", 0.3), e.select(".domain").style("stroke", "none");
129
+ const t = z.append("g").attr("class", "grid").call(
130
+ he(_).tickSize(-B).tickFormat(() => "")
131
+ );
132
+ t.selectAll("line").style("stroke", M).style("stroke-dasharray", "3,3").style("opacity", 0.3), t.select(".domain").style("stroke", "none");
133
+ }
134
+ const ie = xe(Y);
135
+ h && ie.tickFormat((e) => {
136
+ const t = new Date(e);
137
+ if (isNaN(t.getTime())) return String(e);
138
+ switch (A?.toLowerCase()) {
139
+ case "year":
140
+ return String(t.getUTCFullYear());
141
+ case "quarter": {
142
+ const r = Math.floor(t.getUTCMonth() / 3) + 1;
143
+ return `${t.getUTCFullYear()}-Q${r}`;
144
+ }
145
+ case "month":
146
+ return `${t.getUTCFullYear()}-${String(t.getUTCMonth() + 1).padStart(2, "0")}`;
147
+ case "week":
148
+ case "day":
149
+ return `${t.getUTCFullYear()}-${String(t.getUTCMonth() + 1).padStart(2, "0")}-${String(t.getUTCDate()).padStart(2, "0")}`;
150
+ case "hour":
151
+ return `${String(t.getUTCMonth() + 1).padStart(2, "0")}-${String(t.getUTCDate()).padStart(2, "0")} ${String(t.getUTCHours()).padStart(2, "0")}:00`;
152
+ default:
153
+ return `${t.getUTCFullYear()}-${String(t.getUTCMonth() + 1).padStart(2, "0")}`;
154
+ }
155
+ });
156
+ const X = z.append("g").attr("transform", `translate(0,${v})`).call(ie);
157
+ X.selectAll("text").style("fill", g), X.selectAll("line, path").style("stroke", M), X.append("text").attr("x", B / 2).attr("y", 35).attr("fill", g).style("text-anchor", "middle").style("font-size", "12px").text(S(l));
158
+ const Q = z.append("g").call(he(_));
159
+ Q.selectAll("text").style("fill", g), Q.selectAll("line, path").style("stroke", M), Q.append("text").attr("transform", "rotate(-90)").attr("y", -35).attr("x", -v / 2).attr("fill", g).style("text-anchor", "middle").style("font-size", "12px").text(S(o));
160
+ const G = D("body").append("div").attr("class", "bubble-chart-tooltip").style("position", "absolute").style("padding", "8px").style("background", "rgba(0, 0, 0, 0.8)").style("color", "white").style("border-radius", "4px").style("font-size", "12px").style("pointer-events", "none").style("opacity", 0).style("z-index", 1e3), J = z.selectAll(".bubble").data(a).enter().append("circle").attr("class", "bubble").attr("cx", (e) => Y(e.x)).attr("cy", (e) => _(e.y)).attr("r", (e) => I(e.size)).style("fill", (e) => i && e.color !== void 0 ? R(C ? e.color : String(e.color)) : ee[0]).style("opacity", n.bubbleOpacity).style("stroke", "#fff").style("stroke-width", 1).style("cursor", "pointer");
161
+ if (n.showTooltip && J.on("mouseover", function(e, t) {
162
+ D(this).transition().duration(200).style("opacity", 1).attr("r", I(t.size) * 1.1);
163
+ const r = [
164
+ `<strong>${t.series || "Unknown"}</strong>`,
165
+ `${S(l)}: ${t.xLabel || t.x}`,
166
+ `${S(o)}: ${t.y}`,
167
+ `${S(u)}: ${t.size}`,
168
+ i && t.color ? `${S(i)}: ${t.color}` : ""
169
+ ].filter(Boolean).join("<br>");
170
+ G.html(r).style("left", e.pageX + 10 + "px").style("top", e.pageY - 10 + "px").transition().duration(200).style("opacity", 1), te(t.label);
171
+ }).on("mousemove", function(e) {
172
+ G.style("left", e.pageX + 10 + "px").style("top", e.pageY - 10 + "px");
173
+ }).on("mouseout", function(e, t) {
174
+ D(this).transition().duration(200).style("opacity", n.bubbleOpacity).attr("r", I(t.size)), G.transition().duration(200).style("opacity", 0), te(null);
175
+ }), n.showLegend && i)
176
+ if (C) {
177
+ const r = Math.min(...a.map((x) => x.color)), m = Math.max(...a.map((x) => x.color)), y = z.append("g").attr("class", "color-legend").attr("transform", `translate(${B / 2 - 200 / 2}, ${v + 60})`), V = le.append("defs").append("linearGradient").attr("id", "color-scale-gradient").attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%"), c = L?.gradient || ye;
178
+ c.forEach((x, f) => {
179
+ V.append("stop").attr("offset", `${f / (c.length - 1) * 100}%`).attr("stop-color", x);
180
+ }), y.append("rect").attr("width", 200).attr("height", 20).style("fill", "url(#color-scale-gradient)").style("stroke", "#ccc").style("stroke-width", 1), y.append("text").attr("x", 0).attr("y", 35).attr("text-anchor", "start").style("font-size", "11px").style("fill", g).text(r.toFixed(2)), y.append("text").attr("x", 200).attr("y", 35).attr("text-anchor", "end").style("font-size", "11px").style("fill", g).text(m.toFixed(2)), y.append("text").attr("x", 200 / 2).attr("y", -5).attr("text-anchor", "middle").style("font-size", "12px").style("font-weight", "bold").style("fill", g).text(S(i));
181
+ } else {
182
+ const e = j;
183
+ if (e.length > 0) {
184
+ const r = z.append("g").attr("class", "legend").attr("transform", `translate(${B / 2 - e.length * 80 / 2}, ${v + 60})`).selectAll(".legend-item").data(e).enter().append("g").attr("class", "legend-item").attr("transform", (m, y) => `translate(${y * 80}, 0)`).style("cursor", "pointer");
185
+ r.append("circle").attr("cx", 5).attr("cy", 5).attr("r", 5).style("fill", (m) => R(m)).style("opacity", n.bubbleOpacity), r.append("text").attr("x", 15).attr("y", 5).attr("dy", ".35em").style("font-size", "11px").style("fill", g).text((m) => String(m)), r.on("mouseover", function(m, y) {
186
+ J.transition().duration(200).style("opacity", (T) => i && String(T.color) === y ? 1 : 0.2);
187
+ }).on("mouseout", function() {
188
+ J.transition().duration(200).style("opacity", n.bubbleOpacity);
189
+ });
190
+ }
191
+ }
192
+ return () => {
193
+ G.remove();
194
+ };
195
+ }, [$, s, b, H, F, N, n.showLegend, n.showGrid, n.showTooltip, n.minBubbleSize, n.maxBubbleSize, n.bubbleOpacity, L, se]), !$ || $.length === 0 ? /* @__PURE__ */ p("div", { className: "flex items-center justify-center w-full text-dc-text-muted", style: { height: q }, children: /* @__PURE__ */ K("div", { className: "text-center", children: [
196
+ /* @__PURE__ */ p("div", { className: "text-sm font-semibold mb-1", children: "No data available" }),
197
+ /* @__PURE__ */ p("div", { className: "text-xs text-dc-text-secondary", children: "No data points to display in bubble chart" })
198
+ ] }) }) : s?.xAxis && s?.yAxis && s?.series ? /* @__PURE__ */ p("div", { className: "w-full flex-1 flex flex-col relative", style: { height: q, minHeight: "250px", overflow: "hidden" }, children: /* @__PURE__ */ K("div", { ref: w, className: "w-full h-full relative", children: [
199
+ /* @__PURE__ */ p("svg", { ref: U, className: "w-full h-full" }),
200
+ !N && /* @__PURE__ */ p("div", { className: "absolute inset-0 flex items-center justify-center", children: /* @__PURE__ */ p("div", { className: "text-dc-text-muted text-sm", children: "Measuring chart dimensions..." }) })
201
+ ] }) }) : /* @__PURE__ */ p("div", { className: "flex items-center justify-center w-full text-yellow-600", style: { height: q }, children: /* @__PURE__ */ K("div", { className: "text-center", children: [
202
+ /* @__PURE__ */ p("div", { className: "text-sm font-semibold mb-1", children: "Configuration Required" }),
203
+ /* @__PURE__ */ p("div", { className: "text-xs", children: "Bubble chart requires xAxis, yAxis, series, and sizeField dimensions" }),
204
+ /* @__PURE__ */ p("div", { className: "text-xs mt-1", children: "Optional: colorField for bubble coloring" })
205
+ ] }) });
206
+ }
207
+ export {
208
+ Re as default
209
+ };
210
+ //# sourceMappingURL=chart-bubblechart-Dg7sT_Mm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chart-bubblechart-Dg7sT_Mm.js","sources":["../../../src/client/components/charts/BubbleChart.tsx"],"sourcesContent":["import { useEffect, useLayoutEffect, useRef, useState } from 'react'\nimport { select, scaleLinear, scaleSqrt, scaleOrdinal, scaleQuantize, extent, max, axisBottom, axisLeft, type ScaleOrdinal, type ScaleQuantize } from 'd3'\nimport { CHART_COLORS, CHART_COLORS_GRADIENT, CHART_MARGINS } from '../../utils/chartConstants'\nimport { formatTimeValue, getFieldGranularity, parseNumericValue, isValidNumericValue } from '../../utils/chartUtils'\nimport { useCubeContext } from '../../providers/CubeProvider'\nimport { getTheme, watchThemeChanges, type Theme } from '../../theme'\nimport type { ChartProps } from '../../types'\n\ninterface BubbleData {\n x: number\n xLabel?: string // Formatted label for time dimensions\n y: number\n size: number\n color?: string | number\n label: string\n series?: string\n}\n\nexport default function BubbleChart({\n data,\n chartConfig,\n displayConfig = {},\n queryObject,\n height = \"100%\",\n colorPalette\n}: ChartProps) {\n const svgRef = useRef<SVGSVGElement | null>(null)\n const containerRef = useRef<HTMLDivElement | null>(null)\n const [, setHoveredBubble] = useState<string | null>(null)\n const [dimensions, setDimensions] = useState({ width: 0, height: 0 })\n const [dimensionsReady, setDimensionsReady] = useState(false)\n const [currentTheme, setCurrentTheme] = useState<Theme>('light')\n const { getFieldLabel } = useCubeContext()\n\n // Watch for theme changes\n useEffect(() => {\n setCurrentTheme(getTheme())\n const unwatch = watchThemeChanges((theme) => {\n setCurrentTheme(theme)\n })\n return unwatch\n }, [])\n\n const safeDisplayConfig = {\n showLegend: displayConfig?.showLegend ?? true,\n showGrid: displayConfig?.showGrid ?? true,\n showTooltip: displayConfig?.showTooltip ?? true,\n minBubbleSize: displayConfig?.minBubbleSize ?? 5,\n maxBubbleSize: displayConfig?.maxBubbleSize ?? 50,\n bubbleOpacity: displayConfig?.bubbleOpacity ?? 0.7\n }\n\n // Enhanced dimension measurement with retry mechanism\n useLayoutEffect(() => {\n let retryCount = 0\n const maxRetries = 10\n let rafId: number\n let timeoutId: NodeJS.Timeout\n \n const updateDimensions = () => {\n if (containerRef.current) {\n const { width, height } = containerRef.current.getBoundingClientRect()\n \n if (width > 0 && height > 0) {\n setDimensions({ width, height })\n setDimensionsReady(true)\n return true\n }\n }\n return false\n }\n \n // Immediate measurement\n const success = updateDimensions()\n \n if (!success && retryCount < maxRetries) {\n // Retry with requestAnimationFrame\n const retryWithRaf = () => {\n const rafSuccess = updateDimensions()\n \n if (!rafSuccess && retryCount < maxRetries) {\n retryCount++\n // Use setTimeout for additional retries with increasing delays\n timeoutId = setTimeout(() => {\n rafId = requestAnimationFrame(retryWithRaf)\n }, 50 * retryCount) // Increasing delay: 50ms, 100ms, 150ms, etc.\n }\n }\n \n rafId = requestAnimationFrame(retryWithRaf)\n }\n \n return () => {\n if (rafId) cancelAnimationFrame(rafId)\n if (timeoutId) clearTimeout(timeoutId)\n }\n }, [])\n\n // Enhanced ResizeObserver for dynamic resizing with immediate initialization\n useEffect(() => {\n let resizeObserver: ResizeObserver | null = null\n \n const updateDimensions = () => {\n if (containerRef.current) {\n const { width, height } = containerRef.current.getBoundingClientRect()\n if (width > 0 && height > 0) {\n setDimensions({ width, height })\n if (!dimensionsReady) {\n setDimensionsReady(true)\n }\n }\n }\n }\n \n // Initialize ResizeObserver immediately\n if (containerRef.current) {\n resizeObserver = new ResizeObserver((entries) => {\n for (const entry of entries) {\n const { width, height } = entry.contentRect\n if (width > 0 && height > 0) {\n setDimensions({ width, height })\n if (!dimensionsReady) {\n setDimensionsReady(true)\n }\n }\n }\n })\n \n resizeObserver.observe(containerRef.current)\n \n // Also try immediate measurement as fallback\n updateDimensions()\n }\n\n // Window resize as additional fallback\n window.addEventListener('resize', updateDimensions)\n \n return () => {\n if (resizeObserver) {\n resizeObserver.disconnect()\n }\n window.removeEventListener('resize', updateDimensions)\n }\n }, [dimensionsReady])\n\n useEffect(() => {\n if (!data || data.length === 0 || !svgRef.current || !dimensionsReady || dimensions.width === 0) {\n return\n }\n\n // Clear previous chart\n select(svgRef.current).selectAll('*').remove()\n\n\n // Validate chartConfig - only new format supported\n if (!chartConfig?.xAxis || !chartConfig?.yAxis || !chartConfig?.series) {\n return\n }\n\n const xAxisField = Array.isArray(chartConfig.xAxis) ? chartConfig.xAxis[0] : chartConfig.xAxis\n const yAxisField = Array.isArray(chartConfig.yAxis) ? chartConfig.yAxis[0] : chartConfig.yAxis\n const seriesField = Array.isArray(chartConfig.series) ? chartConfig.series[0] : chartConfig.series\n const sizeFieldName = Array.isArray(chartConfig.sizeField) ? chartConfig.sizeField[0] : chartConfig.sizeField || yAxisField\n const colorFieldName = Array.isArray(chartConfig.colorField) ? chartConfig.colorField[0] : chartConfig.colorField\n\n\n if (!xAxisField || !yAxisField || !seriesField || !sizeFieldName) {\n return\n }\n\n // Transform data for bubble chart\n // Null handling: Filter out bubbles where x, y, or size are null\n const xGranularity = getFieldGranularity(queryObject, xAxisField)\n\n // Check if x-axis field is a time dimension\n const isTimeDimension = queryObject?.timeDimensions?.some(\n (td: { dimension: string }) => td.dimension === xAxisField\n ) || false\n\n const bubbleData: BubbleData[] = data\n .map(item => {\n const rawXValue = item[xAxisField]\n let xNum: number\n let xLabel: string\n\n if (isTimeDimension && rawXValue) {\n // For time dimensions, convert to timestamp for proper numeric positioning\n const dateStr = String(rawXValue)\n // Try to parse as date - handle ISO format and PostgreSQL format\n let date: Date\n if (dateStr.match(/^\\d{4}-\\d{2}-\\d{2}[T ]/)) {\n // Full timestamp format\n let isoStr = dateStr\n if (dateStr.includes(' ')) {\n isoStr = dateStr.replace(' ', 'T').replace('+00', 'Z').replace(/\\+\\d{2}:\\d{2}$/, 'Z')\n }\n if (!isoStr.endsWith('Z') && !isoStr.includes('+')) {\n isoStr = isoStr + 'Z'\n }\n date = new Date(isoStr)\n } else {\n date = new Date(dateStr)\n }\n\n xNum = isNaN(date.getTime()) ? parseFloat(dateStr) : date.getTime()\n xLabel = formatTimeValue(rawXValue, xGranularity)\n } else {\n // Non-time value - use as-is\n const formattedValue = formatTimeValue(rawXValue, xGranularity) || rawXValue\n xNum = typeof formattedValue === 'string' ? parseFloat(formattedValue) : formattedValue\n xLabel = String(formattedValue)\n }\n\n const yValue = parseNumericValue(item[yAxisField])\n const sizeValue = parseNumericValue(item[sizeFieldName])\n const seriesValue = item[seriesField]\n\n return {\n x: xNum,\n xLabel, // Store formatted label for tooltip display\n y: yValue as number, // Type assertion: filter below ensures this is never null\n size: sizeValue !== null ? Math.abs(sizeValue) : 0, // Ensure positive size\n color: colorFieldName ? item[colorFieldName] : seriesValue,\n series: seriesValue,\n label: `${seriesValue || 'Unknown'}`,\n isValid: isValidNumericValue(xNum) && yValue !== null && sizeValue !== null && sizeValue > 0\n }\n })\n .filter(d => d.isValid && d.size > 0) // Filter out bubbles with invalid coordinates or no size\n\n if (bubbleData.length === 0) return\n\n const margin = { \n ...CHART_MARGINS, \n left: CHART_MARGINS.left + 30, // Add extra 30px left margin for Y-axis label\n bottom: (safeDisplayConfig.showLegend && colorFieldName) ? 100 : 40 // Add extra space for legend\n }\n const width = dimensions.width - margin.left - margin.right\n const chartHeight = dimensions.height - margin.top - margin.bottom\n\n const svg = select(svgRef.current)\n .attr('width', dimensions.width)\n .attr('height', dimensions.height)\n\n const g = svg.append('g')\n .attr('transform', `translate(${margin.left},${margin.top})`)\n\n // Set up scales\n const xScale = scaleLinear()\n .domain(extent(bubbleData, d => d.x) as [number, number])\n .range([0, width])\n .nice()\n\n const yScale = scaleLinear()\n .domain(extent(bubbleData, d => d.y) as [number, number])\n .range([chartHeight, 0])\n .nice()\n\n const sizeScale = scaleSqrt()\n .domain([0, max(bubbleData, d => d.size) as number])\n .range([safeDisplayConfig.minBubbleSize, safeDisplayConfig.maxBubbleSize])\n\n // Set up color scale\n let colorScale: ScaleOrdinal<string, string> | ScaleQuantize<string>\n let isNumericColorField = false\n let uniqueColors: string[] = []\n \n if (colorFieldName && bubbleData.length > 0) {\n // Check if color field is numeric for color scaling (same logic as TreeMapChart)\n const colorValues = bubbleData.map(item => {\n const value = item.color\n return typeof value === 'string' ? parseFloat(value) : value\n }).filter((val): val is number => !isNaN(val as number))\n \n isNumericColorField = colorValues.length === bubbleData.length && colorValues.every(val => typeof val === 'number')\n \n if (isNumericColorField) {\n // Use D3 quantize scale for better color distribution with small ranges\n const minValue = Math.min(...colorValues)\n const maxValue = Math.max(...colorValues)\n \n // Create D3 quantize color scale - maps continuous data to discrete color bands\n colorScale = scaleQuantize<string>()\n .domain([minValue, maxValue])\n .range(colorPalette?.gradient || CHART_COLORS_GRADIENT)\n } else {\n // Categorical color field - use series colors\n uniqueColors = [...new Set(bubbleData.map(d => String(d.color)))]\n colorScale = scaleOrdinal<string>()\n .domain(uniqueColors)\n .range(colorPalette?.colors || CHART_COLORS)\n }\n } else {\n // Single color for all bubbles\n colorScale = scaleOrdinal<string>()\n .domain(['default'])\n .range([CHART_COLORS[0]])\n }\n\n // Get theme colors from CSS variables\n const getThemeColor = (varName: string, fallback: string) => {\n const value = getComputedStyle(document.documentElement).getPropertyValue(varName).trim()\n return value || fallback\n }\n\n const isDark = currentTheme !== 'light'\n const textColor = isDark\n ? getThemeColor('--dc-text-muted', '#cbd5e1') // Lighter text for dark mode\n : getThemeColor('--dc-text-secondary', '#374151') // Darker text for light mode\n const gridColor = isDark\n ? getThemeColor('--dc-border', '#475569') // Lighter grid for dark mode\n : '#9ca3af' // Much darker gray for light mode visibility\n\n // Add grid\n if (safeDisplayConfig.showGrid) {\n // X-axis grid\n const xGrid = g.append('g')\n .attr('class', 'grid')\n .attr('transform', `translate(0,${chartHeight})`)\n .call(axisBottom(xScale)\n .tickSize(-chartHeight)\n .tickFormat(() => '')\n )\n\n xGrid.selectAll('line')\n .style('stroke', gridColor)\n .style('stroke-dasharray', '3,3')\n .style('opacity', 0.3)\n\n xGrid.select('.domain')\n .style('stroke', 'none')\n\n // Y-axis grid\n const yGrid = g.append('g')\n .attr('class', 'grid')\n .call(axisLeft(yScale)\n .tickSize(-width)\n .tickFormat(() => '')\n )\n\n yGrid.selectAll('line')\n .style('stroke', gridColor)\n .style('stroke-dasharray', '3,3')\n .style('opacity', 0.3)\n\n yGrid.select('.domain')\n .style('stroke', 'none')\n }\n\n // Add X axis with proper time formatting if needed\n const xAxisGenerator = axisBottom(xScale)\n\n // If it's a time dimension, format the tick labels\n if (isTimeDimension) {\n xAxisGenerator.tickFormat((d) => {\n const date = new Date(d as number)\n if (isNaN(date.getTime())) return String(d)\n\n // Format based on granularity\n switch (xGranularity?.toLowerCase()) {\n case 'year':\n return String(date.getUTCFullYear())\n case 'quarter': {\n const q = Math.floor(date.getUTCMonth() / 3) + 1\n return `${date.getUTCFullYear()}-Q${q}`\n }\n case 'month':\n return `${date.getUTCFullYear()}-${String(date.getUTCMonth() + 1).padStart(2, '0')}`\n case 'week':\n case 'day':\n return `${date.getUTCFullYear()}-${String(date.getUTCMonth() + 1).padStart(2, '0')}-${String(date.getUTCDate()).padStart(2, '0')}`\n case 'hour':\n return `${String(date.getUTCMonth() + 1).padStart(2, '0')}-${String(date.getUTCDate()).padStart(2, '0')} ${String(date.getUTCHours()).padStart(2, '0')}:00`\n default:\n return `${date.getUTCFullYear()}-${String(date.getUTCMonth() + 1).padStart(2, '0')}`\n }\n })\n }\n\n const xAxis = g.append('g')\n .attr('transform', `translate(0,${chartHeight})`)\n .call(xAxisGenerator)\n\n xAxis.selectAll('text')\n .style('fill', textColor)\n\n xAxis.selectAll('line, path')\n .style('stroke', gridColor)\n\n xAxis.append('text')\n .attr('x', width / 2)\n .attr('y', 35)\n .attr('fill', textColor)\n .style('text-anchor', 'middle')\n .style('font-size', '12px')\n .text(getFieldLabel(xAxisField))\n\n // Add Y axis\n const yAxis = g.append('g')\n .call(axisLeft(yScale))\n\n yAxis.selectAll('text')\n .style('fill', textColor)\n\n yAxis.selectAll('line, path')\n .style('stroke', gridColor)\n\n yAxis.append('text')\n .attr('transform', 'rotate(-90)')\n .attr('y', -35)\n .attr('x', -chartHeight / 2)\n .attr('fill', textColor)\n .style('text-anchor', 'middle')\n .style('font-size', '12px')\n .text(getFieldLabel(yAxisField))\n\n // Create tooltip\n const tooltip = select('body').append('div')\n .attr('class', 'bubble-chart-tooltip')\n .style('position', 'absolute')\n .style('padding', '8px')\n .style('background', 'rgba(0, 0, 0, 0.8)')\n .style('color', 'white')\n .style('border-radius', '4px')\n .style('font-size', '12px')\n .style('pointer-events', 'none')\n .style('opacity', 0)\n .style('z-index', 1000)\n\n // Add bubbles\n const bubbles = g.selectAll('.bubble')\n .data(bubbleData)\n .enter().append('circle')\n .attr('class', 'bubble')\n .attr('cx', d => xScale(d.x))\n .attr('cy', d => yScale(d.y))\n .attr('r', d => sizeScale(d.size))\n .style('fill', d => {\n if (colorFieldName && d.color !== undefined) {\n return isNumericColorField\n ? (colorScale as ScaleQuantize<string>)(d.color as number)\n : (colorScale as ScaleOrdinal<string, string>)(String(d.color))\n }\n return CHART_COLORS[0]\n })\n .style('opacity', safeDisplayConfig.bubbleOpacity)\n .style('stroke', '#fff')\n .style('stroke-width', 1)\n .style('cursor', 'pointer')\n\n // Add hover effects\n if (safeDisplayConfig.showTooltip) {\n bubbles\n .on('mouseover', function(event, d) {\n select(this)\n .transition()\n .duration(200)\n .style('opacity', 1)\n .attr('r', sizeScale(d.size) * 1.1)\n\n const tooltipContent = [\n `<strong>${d.series || 'Unknown'}</strong>`,\n `${getFieldLabel(xAxisField)}: ${d.xLabel || d.x}`,\n `${getFieldLabel(yAxisField)}: ${d.y}`,\n `${getFieldLabel(sizeFieldName)}: ${d.size}`,\n colorFieldName && d.color ? `${getFieldLabel(colorFieldName)}: ${d.color}` : ''\n ].filter(Boolean).join('<br>')\n\n tooltip\n .html(tooltipContent)\n .style('left', (event.pageX + 10) + 'px')\n .style('top', (event.pageY - 10) + 'px')\n .transition()\n .duration(200)\n .style('opacity', 1)\n\n setHoveredBubble(d.label)\n })\n .on('mousemove', function(event) {\n tooltip\n .style('left', (event.pageX + 10) + 'px')\n .style('top', (event.pageY - 10) + 'px')\n })\n .on('mouseout', function(_event, d) {\n select(this)\n .transition()\n .duration(200)\n .style('opacity', safeDisplayConfig.bubbleOpacity)\n .attr('r', sizeScale(d.size))\n\n tooltip\n .transition()\n .duration(200)\n .style('opacity', 0)\n\n setHoveredBubble(null)\n })\n }\n\n // Add legend if needed\n if (safeDisplayConfig.showLegend && colorFieldName) {\n if (isNumericColorField) {\n // Create gradient legend for numeric color field\n const legendWidth = 200\n const legendHeight = 20\n const minValue = Math.min(...bubbleData.map(d => d.color as number))\n const maxValue = Math.max(...bubbleData.map(d => d.color as number))\n \n const legend = g.append('g')\n .attr('class', 'color-legend')\n .attr('transform', `translate(${width / 2 - legendWidth / 2}, ${chartHeight + 60})`)\n\n // Create gradient definition\n const defs = svg.append('defs')\n const gradient = defs.append('linearGradient')\n .attr('id', 'color-scale-gradient')\n .attr('x1', '0%')\n .attr('y1', '0%')\n .attr('x2', '100%')\n .attr('y2', '0%')\n\n // Add color stops for the gradient\n const gradientColors = colorPalette?.gradient || CHART_COLORS_GRADIENT\n gradientColors.forEach((color, i) => {\n gradient.append('stop')\n .attr('offset', `${(i / (gradientColors.length - 1)) * 100}%`)\n .attr('stop-color', color)\n })\n\n // Add the gradient rectangle\n legend.append('rect')\n .attr('width', legendWidth)\n .attr('height', legendHeight)\n .style('fill', 'url(#color-scale-gradient)')\n .style('stroke', '#ccc')\n .style('stroke-width', 1)\n\n // Add min value label\n legend.append('text')\n .attr('x', 0)\n .attr('y', legendHeight + 15)\n .attr('text-anchor', 'start')\n .style('font-size', '11px')\n .style('fill', textColor)\n .text(minValue.toFixed(2))\n\n // Add max value label\n legend.append('text')\n .attr('x', legendWidth)\n .attr('y', legendHeight + 15)\n .attr('text-anchor', 'end')\n .style('font-size', '11px')\n .style('fill', textColor)\n .text(maxValue.toFixed(2))\n\n // Add field name label\n legend.append('text')\n .attr('x', legendWidth / 2)\n .attr('y', -5)\n .attr('text-anchor', 'middle')\n .style('font-size', '12px')\n .style('font-weight', 'bold')\n .style('fill', textColor)\n .text(getFieldLabel(colorFieldName))\n\n } else {\n // Original categorical legend\n const legendItems = uniqueColors\n\n if (legendItems.length > 0) {\n const legend = g.append('g')\n .attr('class', 'legend')\n .attr('transform', `translate(${width / 2 - (legendItems.length * 80) / 2}, ${chartHeight + 60})`)\n\n const legendItem = legend.selectAll('.legend-item')\n .data(legendItems)\n .enter().append('g')\n .attr('class', 'legend-item')\n .attr('transform', (_d, i) => `translate(${i * 80}, 0)`)\n .style('cursor', 'pointer')\n\n legendItem.append('circle')\n .attr('cx', 5)\n .attr('cy', 5)\n .attr('r', 5)\n .style('fill', d => (colorScale as ScaleOrdinal<string, string>)(d as string))\n .style('opacity', safeDisplayConfig.bubbleOpacity)\n\n legendItem.append('text')\n .attr('x', 15)\n .attr('y', 5)\n .attr('dy', '.35em')\n .style('font-size', '11px')\n .style('fill', textColor)\n .text(d => String(d))\n\n // Legend hover effects\n legendItem\n .on('mouseover', function(_event, legendKey) {\n // Highlight matching bubbles\n bubbles\n .transition()\n .duration(200)\n .style('opacity', d => {\n const matches = colorFieldName && String(d.color) === legendKey\n return matches ? 1 : 0.2\n })\n })\n .on('mouseout', function() {\n // Reset all bubbles\n bubbles\n .transition()\n .duration(200)\n .style('opacity', safeDisplayConfig.bubbleOpacity)\n })\n }\n }\n }\n\n // Cleanup function\n return () => {\n tooltip.remove()\n }\n }, [data, chartConfig, displayConfig, queryObject, dimensions, dimensionsReady, safeDisplayConfig.showLegend, safeDisplayConfig.showGrid, safeDisplayConfig.showTooltip, safeDisplayConfig.minBubbleSize, safeDisplayConfig.maxBubbleSize, safeDisplayConfig.bubbleOpacity, colorPalette, currentTheme])\n\n if (!data || data.length === 0) {\n return (\n <div className=\"flex items-center justify-center w-full text-dc-text-muted\" style={{ height }}>\n <div className=\"text-center\">\n <div className=\"text-sm font-semibold mb-1\">No data available</div>\n <div className=\"text-xs text-dc-text-secondary\">No data points to display in bubble chart</div>\n </div>\n </div>\n )\n }\n\n // Validate that we have required fields\n const hasValidConfig = chartConfig?.xAxis && chartConfig?.yAxis && chartConfig?.series\n if (!hasValidConfig) {\n return (\n <div className=\"flex items-center justify-center w-full text-yellow-600\" style={{ height }}>\n <div className=\"text-center\">\n <div className=\"text-sm font-semibold mb-1\">Configuration Required</div>\n <div className=\"text-xs\">Bubble chart requires xAxis, yAxis, series, and sizeField dimensions</div>\n <div className=\"text-xs mt-1\">Optional: colorField for bubble coloring</div>\n </div>\n </div>\n )\n }\n\n return (\n <div className=\"w-full flex-1 flex flex-col relative\" style={{ height, minHeight: '250px', overflow: 'hidden' }}>\n <div ref={containerRef} className=\"w-full h-full relative\">\n <svg ref={svgRef} className=\"w-full h-full\" />\n {!dimensionsReady && (\n <div className=\"absolute inset-0 flex items-center justify-center\">\n <div className=\"text-dc-text-muted text-sm\">Measuring chart dimensions...</div>\n </div>\n )}\n </div>\n </div>\n )\n}"],"names":["BubbleChart","data","chartConfig","displayConfig","queryObject","height","colorPalette","svgRef","useRef","containerRef","setHoveredBubble","useState","dimensions","setDimensions","dimensionsReady","setDimensionsReady","currentTheme","setCurrentTheme","getFieldLabel","useCubeContext","useEffect","getTheme","watchThemeChanges","theme","safeDisplayConfig","useLayoutEffect","retryCount","maxRetries","rafId","timeoutId","updateDimensions","width","retryWithRaf","resizeObserver","entries","entry","select","xAxisField","yAxisField","seriesField","sizeFieldName","colorFieldName","xGranularity","getFieldGranularity","isTimeDimension","td","bubbleData","item","rawXValue","xNum","xLabel","dateStr","date","isoStr","formatTimeValue","formattedValue","yValue","parseNumericValue","sizeValue","seriesValue","isValidNumericValue","d","margin","CHART_MARGINS","chartHeight","svg","g","xScale","scaleLinear","extent","yScale","sizeScale","scaleSqrt","max","colorScale","isNumericColorField","uniqueColors","colorValues","value","val","minValue","maxValue","scaleQuantize","CHART_COLORS_GRADIENT","scaleOrdinal","CHART_COLORS","getThemeColor","varName","fallback","isDark","textColor","gridColor","xGrid","axisBottom","yGrid","axisLeft","xAxisGenerator","q","xAxis","yAxis","tooltip","bubbles","event","tooltipContent","_event","legend","gradient","gradientColors","color","i","legendItems","legendItem","_d","legendKey","jsx","jsxs"],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ import { jsx as i } from "react/jsx-runtime";
2
+ import { I as o, c as s } from "./icons-D-n_woAP.js";
3
+ const r = {
4
+ icon: ({ className: e }) => /* @__PURE__ */ i(o, { icon: s, className: e }),
5
+ description: "Compare three dimensions of data",
6
+ useCase: "Best for showing relationships between three variables (X, Y, and size), market analysis",
7
+ dropZones: [
8
+ {
9
+ key: "xAxis",
10
+ label: "X-Axis",
11
+ description: "Horizontal axis position",
12
+ mandatory: !0,
13
+ maxItems: 1,
14
+ acceptTypes: ["dimension", "timeDimension", "measure"],
15
+ emptyText: "Drop a field for X-axis position"
16
+ },
17
+ {
18
+ key: "yAxis",
19
+ label: "Y-Axis",
20
+ description: "Vertical axis position",
21
+ mandatory: !0,
22
+ maxItems: 1,
23
+ acceptTypes: ["measure"],
24
+ emptyText: "Drop a measure for Y-axis position"
25
+ },
26
+ {
27
+ key: "sizeField",
28
+ label: "Bubble Radius",
29
+ description: "Size of bubbles based on this measure",
30
+ mandatory: !0,
31
+ maxItems: 1,
32
+ acceptTypes: ["measure"],
33
+ emptyText: "Drop a measure for bubble size"
34
+ },
35
+ {
36
+ key: "series",
37
+ label: "Bubble Labels",
38
+ description: "Field to use for bubble labels and identification",
39
+ mandatory: !0,
40
+ maxItems: 1,
41
+ acceptTypes: ["dimension"],
42
+ emptyText: "Drop a dimension for bubble labels"
43
+ },
44
+ {
45
+ key: "colorField",
46
+ label: "Bubble Colour",
47
+ description: "Color bubbles by this field (optional)",
48
+ mandatory: !1,
49
+ maxItems: 1,
50
+ acceptTypes: ["dimension", "measure"],
51
+ emptyText: "Drop a field for bubble color (optional)"
52
+ }
53
+ ],
54
+ displayOptions: ["showLegend", "showGrid", "showTooltip", "minBubbleSize", "maxBubbleSize", "bubbleOpacity", "hideHeader"]
55
+ };
56
+ export {
57
+ r as bubbleChartConfig
58
+ };
59
+ //# sourceMappingURL=chart-bubblechart-config-CcZTMTCx.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chart-bubblechart-config-CcZTMTCx.js","sources":["../../../src/client/components/charts/BubbleChart.config.tsx"],"sourcesContent":["import type { ChartTypeConfig } from '../../charts/chartConfigs'\nimport { Icon } from '@iconify/react'\nimport chartBubbleIcon from '@iconify-icons/tabler/chart-bubble'\n\n/**\n * Configuration for the bubble chart type\n */\nexport const bubbleChartConfig: ChartTypeConfig = {\n icon: ({ className }) => <Icon icon={chartBubbleIcon} className={className} />,\n description: 'Compare three dimensions of data',\n useCase: 'Best for showing relationships between three variables (X, Y, and size), market analysis',\n dropZones: [\n {\n key: 'xAxis',\n label: 'X-Axis',\n description: 'Horizontal axis position',\n mandatory: true,\n maxItems: 1,\n acceptTypes: ['dimension', 'timeDimension', 'measure'],\n emptyText: 'Drop a field for X-axis position'\n },\n {\n key: 'yAxis',\n label: 'Y-Axis', \n description: 'Vertical axis position',\n mandatory: true,\n maxItems: 1,\n acceptTypes: ['measure'],\n emptyText: 'Drop a measure for Y-axis position'\n },\n {\n key: 'sizeField',\n label: 'Bubble Radius',\n description: 'Size of bubbles based on this measure',\n mandatory: true,\n maxItems: 1,\n acceptTypes: ['measure'],\n emptyText: 'Drop a measure for bubble size'\n },\n {\n key: 'series',\n label: 'Bubble Labels',\n description: 'Field to use for bubble labels and identification',\n mandatory: true,\n maxItems: 1,\n acceptTypes: ['dimension'],\n emptyText: 'Drop a dimension for bubble labels'\n },\n {\n key: 'colorField',\n label: 'Bubble Colour',\n description: 'Color bubbles by this field (optional)',\n mandatory: false,\n maxItems: 1,\n acceptTypes: ['dimension', 'measure'],\n emptyText: 'Drop a field for bubble color (optional)'\n }\n ],\n displayOptions: ['showLegend', 'showGrid', 'showTooltip', 'minBubbleSize', 'maxBubbleSize', 'bubbleOpacity', 'hideHeader']\n}"],"names":["bubbleChartConfig","className","jsx","Icon","chartBubbleIcon"],"mappings":";;AAOO,MAAMA,IAAqC;AAAA,EAChD,MAAM,CAAC,EAAE,WAAAC,EAAA,MAAgB,gBAAAC,EAACC,GAAA,EAAK,MAAMC,GAAiB,WAAAH,GAAsB;AAAA,EAC5E,aAAa;AAAA,EACb,SAAS;AAAA,EACT,WAAW;AAAA,IACT;AAAA,MACE,KAAK;AAAA,MACL,OAAO;AAAA,MACP,aAAa;AAAA,MACb,WAAW;AAAA,MACX,UAAU;AAAA,MACV,aAAa,CAAC,aAAa,iBAAiB,SAAS;AAAA,MACrD,WAAW;AAAA,IAAA;AAAA,IAEb;AAAA,MACE,KAAK;AAAA,MACL,OAAO;AAAA,MACP,aAAa;AAAA,MACb,WAAW;AAAA,MACX,UAAU;AAAA,MACV,aAAa,CAAC,SAAS;AAAA,MACvB,WAAW;AAAA,IAAA;AAAA,IAEb;AAAA,MACE,KAAK;AAAA,MACL,OAAO;AAAA,MACP,aAAa;AAAA,MACb,WAAW;AAAA,MACX,UAAU;AAAA,MACV,aAAa,CAAC,SAAS;AAAA,MACvB,WAAW;AAAA,IAAA;AAAA,IAEb;AAAA,MACE,KAAK;AAAA,MACL,OAAO;AAAA,MACP,aAAa;AAAA,MACb,WAAW;AAAA,MACX,UAAU;AAAA,MACV,aAAa,CAAC,WAAW;AAAA,MACzB,WAAW;AAAA,IAAA;AAAA,IAEb;AAAA,MACE,KAAK;AAAA,MACL,OAAO;AAAA,MACP,aAAa;AAAA,MACb,WAAW;AAAA,MACX,UAAU;AAAA,MACV,aAAa,CAAC,aAAa,SAAS;AAAA,MACpC,WAAW;AAAA,IAAA;AAAA,EACb;AAAA,EAEF,gBAAgB,CAAC,cAAc,YAAY,eAAe,iBAAiB,iBAAiB,iBAAiB,YAAY;AAC3H;"}
@@ -0,0 +1,103 @@
1
+ import { jsx as e, jsxs as p } from "react/jsx-runtime";
2
+ import { useRef as v, useState as m, useLayoutEffect as y } from "react";
3
+ import { ResponsiveContainer as x } from "recharts";
4
+ const b = {
5
+ sm: "h-6 w-6",
6
+ md: "h-8 w-8",
7
+ lg: "h-12 w-12"
8
+ };
9
+ function g({
10
+ size: l = "md",
11
+ className: i = ""
12
+ }) {
13
+ return /* @__PURE__ */ e(
14
+ "div",
15
+ {
16
+ className: `animate-spin rounded-full border-b-2 ${b[l]} ${i}`,
17
+ style: { borderBottomColor: "var(--dc-primary)" },
18
+ role: "status",
19
+ "aria-label": "Loading"
20
+ }
21
+ );
22
+ }
23
+ function z({ children: l, height: i = "100%" }) {
24
+ const t = v(null), [o, h] = m(!1), [r, f] = m({ width: 0, height: 0 });
25
+ y(() => {
26
+ let n = !0, a = null;
27
+ const w = () => {
28
+ if (!n || !t.current) return;
29
+ const c = t.current.getBoundingClientRect(), d = Math.max(t.current.clientWidth, c.width), s = Math.max(t.current.clientHeight, c.height);
30
+ d > 0 && s > 0 && (f({ width: d, height: s }), h(!0));
31
+ };
32
+ return a = new ResizeObserver((c) => {
33
+ for (const d of c) {
34
+ const { width: s, height: u } = d.contentRect;
35
+ s > 0 && u > 0 && (f({ width: s, height: u }), o || h(!0));
36
+ }
37
+ }), t.current && (a.observe(t.current), w()), () => {
38
+ n = !1, a?.disconnect();
39
+ };
40
+ }, [o]);
41
+ try {
42
+ if (i === "100%")
43
+ return /* @__PURE__ */ e(
44
+ "div",
45
+ {
46
+ ref: t,
47
+ className: "w-full h-full flex-1 flex flex-col relative",
48
+ style: { minHeight: "250px", minWidth: "100px", overflow: "hidden" },
49
+ children: o && r.width > 0 && r.height > 0 ? /* @__PURE__ */ e(
50
+ x,
51
+ {
52
+ width: r.width,
53
+ height: r.height - 16,
54
+ debounce: 100,
55
+ style: { marginTop: "16px" },
56
+ children: l
57
+ }
58
+ ) : /* @__PURE__ */ e("div", { className: "flex items-center justify-center w-full h-full", children: /* @__PURE__ */ e(g, { size: "sm" }) })
59
+ }
60
+ );
61
+ const n = {
62
+ height: typeof i == "number" ? `${i}px` : i,
63
+ width: "100%",
64
+ minHeight: "200px",
65
+ minWidth: "100px"
66
+ };
67
+ return /* @__PURE__ */ e(
68
+ "div",
69
+ {
70
+ ref: t,
71
+ className: "w-full flex flex-col relative",
72
+ style: { ...n, overflow: "hidden" },
73
+ children: o && r.width > 0 && r.height > 0 ? /* @__PURE__ */ e(
74
+ x,
75
+ {
76
+ width: r.width,
77
+ height: r.height - 16,
78
+ debounce: 100,
79
+ style: { marginTop: "16px" },
80
+ children: l
81
+ }
82
+ ) : /* @__PURE__ */ e("div", { className: "flex items-center justify-center w-full h-full", children: /* @__PURE__ */ e(g, { size: "sm" }) })
83
+ }
84
+ );
85
+ } catch (n) {
86
+ return /* @__PURE__ */ p(
87
+ "div",
88
+ {
89
+ className: "flex flex-col items-center justify-center w-full h-full p-4 text-center border border-dashed rounded-lg",
90
+ style: { height: i, borderColor: "var(--dc-border)", backgroundColor: "var(--dc-surface)" },
91
+ children: [
92
+ /* @__PURE__ */ e("div", { className: "text-sm font-semibold mb-1 text-dc-text-muted", children: "Unable to display chart" }),
93
+ /* @__PURE__ */ e("div", { className: "text-xs text-dc-text-secondary", children: n instanceof Error ? n.message : "Failed to create responsive container" })
94
+ ]
95
+ }
96
+ );
97
+ }
98
+ }
99
+ export {
100
+ z as C,
101
+ g as L
102
+ };
103
+ //# sourceMappingURL=chart-chartcontainer-CdwzIKP1.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chart-chartcontainer-CdwzIKP1.js","sources":["../../../src/client/components/LoadingIndicator.tsx","../../../src/client/components/charts/ChartContainer.tsx"],"sourcesContent":["/**\n * LoadingIndicator Component\n *\n * A centralized, theme-aware loading spinner that uses CSS variables\n * for consistent styling across all drizzle-cube components.\n *\n * Can be overridden at the Dashboard or Portlet level by passing a\n * custom loadingComponent prop.\n */\n\nexport interface LoadingIndicatorProps {\n /** Size variant: 'sm' (24px), 'md' (32px), 'lg' (48px) */\n size?: 'sm' | 'md' | 'lg'\n /** Additional CSS classes */\n className?: string\n}\n\nconst sizeClasses = {\n sm: 'h-6 w-6',\n md: 'h-8 w-8',\n lg: 'h-12 w-12'\n}\n\nexport default function LoadingIndicator({\n size = 'md',\n className = ''\n}: LoadingIndicatorProps) {\n return (\n <div\n className={`animate-spin rounded-full border-b-2 ${sizeClasses[size]} ${className}`}\n style={{ borderBottomColor: 'var(--dc-primary)' }}\n role=\"status\"\n aria-label=\"Loading\"\n />\n )\n}\n","import { ReactElement, useState, useRef, useLayoutEffect } from 'react'\nimport { ResponsiveContainer } from 'recharts'\nimport LoadingIndicator from '../LoadingIndicator'\n\ninterface ChartContainerProps {\n children: ReactElement\n height?: string | number\n}\n\nexport default function ChartContainer({ children, height = \"100%\" }: ChartContainerProps) {\n // Track if container is ready to render ResponsiveContainer\n // We need to wait for the container to be in the DOM with valid dimensions\n const containerRef = useRef<HTMLDivElement>(null)\n const [isReady, setIsReady] = useState(false)\n const [containerSize, setContainerSize] = useState({ width: 0, height: 0 })\n\n // Use useLayoutEffect to measure before paint\n useLayoutEffect(() => {\n let mounted = true\n let resizeObserver: ResizeObserver | null = null\n\n const measureAndSetReady = () => {\n if (!mounted || !containerRef.current) return\n\n const rect = containerRef.current.getBoundingClientRect()\n // Check both clientWidth/Height AND getBoundingClientRect for robustness\n const width = Math.max(containerRef.current.clientWidth, rect.width)\n const height = Math.max(containerRef.current.clientHeight, rect.height)\n\n if (width > 0 && height > 0) {\n setContainerSize({ width, height })\n setIsReady(true)\n }\n }\n\n // Set up ResizeObserver to detect when container gets valid dimensions\n resizeObserver = new ResizeObserver((entries) => {\n for (const entry of entries) {\n const { width, height } = entry.contentRect\n if (width > 0 && height > 0) {\n setContainerSize({ width, height })\n if (!isReady) {\n setIsReady(true)\n }\n }\n }\n })\n\n if (containerRef.current) {\n resizeObserver.observe(containerRef.current)\n // Also try immediate measurement\n measureAndSetReady()\n }\n\n return () => {\n mounted = false\n resizeObserver?.disconnect()\n }\n }, [isReady])\n\n try {\n if (height === \"100%\") {\n // For 100% height, make the container fill the available flex space with proper sizing\n return (\n <div\n ref={containerRef}\n className=\"w-full h-full flex-1 flex flex-col relative\"\n style={{ minHeight: '250px', minWidth: '100px', overflow: 'hidden' }}\n >\n {isReady && containerSize.width > 0 && containerSize.height > 0 ? (\n <ResponsiveContainer\n width={containerSize.width}\n height={containerSize.height - 16}\n debounce={100}\n style={{ marginTop: '16px' }}\n >\n {children}\n </ResponsiveContainer>\n ) : (\n <div className=\"flex items-center justify-center w-full h-full\">\n <LoadingIndicator size=\"sm\" />\n </div>\n )}\n </div>\n )\n }\n\n // For specific heights, use them directly\n const containerStyle = {\n height: typeof height === 'number' ? `${height}px` : height,\n width: '100%',\n minHeight: '200px',\n minWidth: '100px'\n }\n\n return (\n <div\n ref={containerRef}\n className=\"w-full flex flex-col relative\"\n style={{ ...containerStyle, overflow: 'hidden' }}\n >\n {isReady && containerSize.width > 0 && containerSize.height > 0 ? (\n <ResponsiveContainer\n width={containerSize.width}\n height={containerSize.height - 16}\n debounce={100}\n style={{ marginTop: '16px' }}\n >\n {children}\n </ResponsiveContainer>\n ) : (\n <div className=\"flex items-center justify-center w-full h-full\">\n <LoadingIndicator size=\"sm\" />\n </div>\n )}\n </div>\n )\n } catch (error) {\n // ChartContainer ResponsiveContainer error\n\n return (\n <div\n className=\"flex flex-col items-center justify-center w-full h-full p-4 text-center border border-dashed rounded-lg\"\n style={{ height, borderColor: 'var(--dc-border)', backgroundColor: 'var(--dc-surface)' }}\n >\n <div className=\"text-sm font-semibold mb-1 text-dc-text-muted\">Unable to display chart</div>\n <div className=\"text-xs text-dc-text-secondary\">\n {error instanceof Error ? error.message : 'Failed to create responsive container'}\n </div>\n </div>\n )\n }\n}"],"names":["sizeClasses","LoadingIndicator","size","className","jsx","ChartContainer","children","height","containerRef","useRef","isReady","setIsReady","useState","containerSize","setContainerSize","useLayoutEffect","mounted","resizeObserver","measureAndSetReady","rect","width","entries","entry","ResponsiveContainer","containerStyle","error","jsxs"],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import { jsx as t } from "react/jsx-runtime";
2
+ import { Tooltip as e } from "recharts";
3
+ import { f as p } from "./chart-activitygridchart-BRk9BNnp.js";
4
+ const i = (r, o) => r == null ? ["No data", o] : [p(r), o];
5
+ function f({ formatter: r, labelFormatter: o }) {
6
+ return /* @__PURE__ */ t(
7
+ e,
8
+ {
9
+ formatter: r || i,
10
+ labelFormatter: o,
11
+ contentStyle: {
12
+ backgroundColor: "white",
13
+ border: "1px solid #e5e7eb",
14
+ borderRadius: "0.5rem",
15
+ fontSize: "0.875rem",
16
+ color: "#1f2937",
17
+ boxShadow: "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)",
18
+ padding: "8px 12px"
19
+ }
20
+ }
21
+ );
22
+ }
23
+ export {
24
+ f as C
25
+ };
26
+ //# sourceMappingURL=chart-charttooltip-NrFVM1cJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chart-charttooltip-NrFVM1cJ.js","sources":["../../../src/client/components/charts/ChartTooltip.tsx"],"sourcesContent":["import React from 'react'\nimport { Tooltip } from 'recharts'\nimport { formatNumericValue } from '../../utils/chartUtils'\n\ninterface ChartTooltipProps {\n formatter?: (value: any, name: any, props: any) => [React.ReactText, React.ReactText]\n labelFormatter?: (label: any) => React.ReactText\n}\n\n// Default formatter that rounds numeric values to at most 2 decimal places\nconst defaultFormatter = (value: any, name: any): [React.ReactText, React.ReactText] => {\n if (value === null || value === undefined) {\n return ['No data', name]\n }\n return [formatNumericValue(value), name]\n}\n\nexport default function ChartTooltip({ formatter, labelFormatter }: ChartTooltipProps) {\n return (\n <Tooltip\n formatter={formatter || defaultFormatter}\n labelFormatter={labelFormatter}\n contentStyle={{\n backgroundColor: 'white',\n border: '1px solid #e5e7eb',\n borderRadius: '0.5rem',\n fontSize: '0.875rem',\n color: '#1f2937',\n boxShadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',\n padding: '8px 12px'\n }}\n />\n )\n}"],"names":["defaultFormatter","value","name","formatNumericValue","ChartTooltip","formatter","labelFormatter","jsx","Tooltip"],"mappings":";;;AAUA,MAAMA,IAAmB,CAACC,GAAYC,MAChCD,KAAU,OACL,CAAC,WAAWC,CAAI,IAElB,CAACC,EAAmBF,CAAK,GAAGC,CAAI;AAGzC,SAAwBE,EAAa,EAAE,WAAAC,GAAW,gBAAAC,KAAqC;AACrF,SACE,gBAAAC;AAAA,IAACC;AAAA,IAAA;AAAA,MACC,WAAWH,KAAaL;AAAA,MACxB,gBAAAM;AAAA,MACA,cAAc;AAAA,QACZ,iBAAiB;AAAA,QACjB,QAAQ;AAAA,QACR,cAAc;AAAA,QACd,UAAU;AAAA,QACV,OAAO;AAAA,QACP,WAAW;AAAA,QACX,SAAS;AAAA,MAAA;AAAA,IACX;AAAA,EAAA;AAGN;"}