@tetrascience-npm/tetrascience-react-ui 0.6.0 → 0.7.0-beta.101.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. package/README.md +55 -0
  2. package/dist/components/ai/chain-of-thought.cjs +1 -1
  3. package/dist/components/ai/chain-of-thought.cjs.map +1 -1
  4. package/dist/components/ai/chain-of-thought.js +5 -5
  5. package/dist/components/ai/chain-of-thought.js.map +1 -1
  6. package/dist/components/ai/conversation.cjs +2 -2
  7. package/dist/components/ai/conversation.cjs.map +1 -1
  8. package/dist/components/ai/conversation.js +2 -2
  9. package/dist/components/ai/conversation.js.map +1 -1
  10. package/dist/components/ai/queue.cjs +1 -1
  11. package/dist/components/ai/queue.cjs.map +1 -1
  12. package/dist/components/ai/queue.js +9 -9
  13. package/dist/components/ai/queue.js.map +1 -1
  14. package/dist/components/charts/AreaGraph/AreaGraph.cjs +1 -1
  15. package/dist/components/charts/AreaGraph/AreaGraph.cjs.map +1 -1
  16. package/dist/components/charts/AreaGraph/AreaGraph.js +165 -103
  17. package/dist/components/charts/AreaGraph/AreaGraph.js.map +1 -1
  18. package/dist/components/charts/BarGraph/BarGraph.cjs +1 -1
  19. package/dist/components/charts/BarGraph/BarGraph.cjs.map +1 -1
  20. package/dist/components/charts/BarGraph/BarGraph.js +135 -90
  21. package/dist/components/charts/BarGraph/BarGraph.js.map +1 -1
  22. package/dist/components/charts/Boxplot/Boxplot.cjs +1 -1
  23. package/dist/components/charts/Boxplot/Boxplot.cjs.map +1 -1
  24. package/dist/components/charts/Boxplot/Boxplot.js +130 -92
  25. package/dist/components/charts/Boxplot/Boxplot.js.map +1 -1
  26. package/dist/components/charts/ChartTooltip/ChartTooltip.cjs +2 -0
  27. package/dist/components/charts/ChartTooltip/ChartTooltip.cjs.map +1 -0
  28. package/dist/components/charts/ChartTooltip/ChartTooltip.js +163 -0
  29. package/dist/components/charts/ChartTooltip/ChartTooltip.js.map +1 -0
  30. package/dist/components/charts/ChartTooltip/lines.cjs +2 -0
  31. package/dist/components/charts/ChartTooltip/lines.cjs.map +1 -0
  32. package/dist/components/charts/ChartTooltip/lines.js +29 -0
  33. package/dist/components/charts/ChartTooltip/lines.js.map +1 -0
  34. package/dist/components/charts/Chromatogram/Chromatogram.cjs +1 -1
  35. package/dist/components/charts/Chromatogram/Chromatogram.cjs.map +1 -1
  36. package/dist/components/charts/Chromatogram/Chromatogram.js +75 -61
  37. package/dist/components/charts/Chromatogram/Chromatogram.js.map +1 -1
  38. package/dist/components/charts/ChromatogramChart/ChromatogramChart.cjs +1 -1
  39. package/dist/components/charts/ChromatogramChart/ChromatogramChart.cjs.map +1 -1
  40. package/dist/components/charts/ChromatogramChart/ChromatogramChart.js +116 -108
  41. package/dist/components/charts/ChromatogramChart/ChromatogramChart.js.map +1 -1
  42. package/dist/components/charts/ChromatogramChart/annotations.cjs +1 -1
  43. package/dist/components/charts/ChromatogramChart/annotations.cjs.map +1 -1
  44. package/dist/components/charts/ChromatogramChart/annotations.js +32 -32
  45. package/dist/components/charts/ChromatogramChart/annotations.js.map +1 -1
  46. package/dist/components/charts/ChromatogramChart/boundaryMarkers.cjs +1 -1
  47. package/dist/components/charts/ChromatogramChart/boundaryMarkers.cjs.map +1 -1
  48. package/dist/components/charts/ChromatogramChart/boundaryMarkers.js +6 -6
  49. package/dist/components/charts/ChromatogramChart/boundaryMarkers.js.map +1 -1
  50. package/dist/components/charts/ChromatogramChart/constants.cjs +1 -1
  51. package/dist/components/charts/ChromatogramChart/constants.cjs.map +1 -1
  52. package/dist/components/charts/ChromatogramChart/constants.js +11 -5
  53. package/dist/components/charts/ChromatogramChart/constants.js.map +1 -1
  54. package/dist/components/charts/ChromatogramChart/dataProcessing.cjs +1 -1
  55. package/dist/components/charts/ChromatogramChart/dataProcessing.cjs.map +1 -1
  56. package/dist/components/charts/ChromatogramChart/dataProcessing.js +38 -49
  57. package/dist/components/charts/ChromatogramChart/dataProcessing.js.map +1 -1
  58. package/dist/components/charts/DotPlot/DotPlot.cjs +1 -1
  59. package/dist/components/charts/DotPlot/DotPlot.cjs.map +1 -1
  60. package/dist/components/charts/DotPlot/DotPlot.js +112 -88
  61. package/dist/components/charts/DotPlot/DotPlot.js.map +1 -1
  62. package/dist/components/charts/Histogram/Histogram.cjs +1 -1
  63. package/dist/components/charts/Histogram/Histogram.cjs.map +1 -1
  64. package/dist/components/charts/Histogram/Histogram.js +132 -115
  65. package/dist/components/charts/Histogram/Histogram.js.map +1 -1
  66. package/dist/components/charts/LineGraph/LineGraph.cjs +1 -1
  67. package/dist/components/charts/LineGraph/LineGraph.cjs.map +1 -1
  68. package/dist/components/charts/LineGraph/LineGraph.js +151 -111
  69. package/dist/components/charts/LineGraph/LineGraph.js.map +1 -1
  70. package/dist/components/charts/PieChart/PieChart.cjs +1 -1
  71. package/dist/components/charts/PieChart/PieChart.cjs.map +1 -1
  72. package/dist/components/charts/PieChart/PieChart.js +81 -70
  73. package/dist/components/charts/PieChart/PieChart.js.map +1 -1
  74. package/dist/components/charts/PlateMap/PlateMap.cjs +1 -1
  75. package/dist/components/charts/PlateMap/PlateMap.cjs.map +1 -1
  76. package/dist/components/charts/PlateMap/PlateMap.js +271 -256
  77. package/dist/components/charts/PlateMap/PlateMap.js.map +1 -1
  78. package/dist/components/charts/PlateMap/constants.cjs +1 -1
  79. package/dist/components/charts/PlateMap/constants.cjs.map +1 -1
  80. package/dist/components/charts/PlateMap/constants.js +20 -29
  81. package/dist/components/charts/PlateMap/constants.js.map +1 -1
  82. package/dist/components/charts/ScatterGraph/ScatterGraph.cjs +1 -1
  83. package/dist/components/charts/ScatterGraph/ScatterGraph.cjs.map +1 -1
  84. package/dist/components/charts/ScatterGraph/ScatterGraph.js +154 -106
  85. package/dist/components/charts/ScatterGraph/ScatterGraph.js.map +1 -1
  86. package/dist/components/composed/DataAppShell/DataAppShell.cjs +1 -1
  87. package/dist/components/composed/DataAppShell/DataAppShell.cjs.map +1 -1
  88. package/dist/components/composed/DataAppShell/DataAppShell.js +118 -111
  89. package/dist/components/composed/DataAppShell/DataAppShell.js.map +1 -1
  90. package/dist/components/composed/PlateMapEditor/PlateMapGrid.cjs +1 -1
  91. package/dist/components/composed/PlateMapEditor/PlateMapGrid.cjs.map +1 -1
  92. package/dist/components/composed/PlateMapEditor/PlateMapGrid.js +1 -1
  93. package/dist/components/composed/PlateMapEditor/PlateMapGrid.js.map +1 -1
  94. package/dist/components/composed/PlateMapEditor/WellLegend.cjs +1 -1
  95. package/dist/components/composed/PlateMapEditor/WellLegend.cjs.map +1 -1
  96. package/dist/components/composed/PlateMapEditor/WellLegend.js +8 -8
  97. package/dist/components/composed/PlateMapEditor/WellLegend.js.map +1 -1
  98. package/dist/components/composed/RichListItem/RichListItem.cjs +1 -1
  99. package/dist/components/composed/RichListItem/RichListItem.cjs.map +1 -1
  100. package/dist/components/composed/RichListItem/RichListItem.js +16 -16
  101. package/dist/components/composed/RichListItem/RichListItem.js.map +1 -1
  102. package/dist/components/ui/accordion.cjs +1 -1
  103. package/dist/components/ui/accordion.cjs.map +1 -1
  104. package/dist/components/ui/accordion.js +1 -1
  105. package/dist/components/ui/accordion.js.map +1 -1
  106. package/dist/components/ui/badge.cjs +1 -1
  107. package/dist/components/ui/badge.cjs.map +1 -1
  108. package/dist/components/ui/badge.js +8 -8
  109. package/dist/components/ui/badge.js.map +1 -1
  110. package/dist/components/ui/button.cjs +1 -1
  111. package/dist/components/ui/button.cjs.map +1 -1
  112. package/dist/components/ui/button.js +11 -11
  113. package/dist/components/ui/button.js.map +1 -1
  114. package/dist/components/ui/combobox.cjs +1 -1
  115. package/dist/components/ui/combobox.cjs.map +1 -1
  116. package/dist/components/ui/combobox.js +12 -12
  117. package/dist/components/ui/combobox.js.map +1 -1
  118. package/dist/components/ui/input-group.cjs +1 -1
  119. package/dist/components/ui/input-group.cjs.map +1 -1
  120. package/dist/components/ui/input-group.js +19 -19
  121. package/dist/components/ui/input-group.js.map +1 -1
  122. package/dist/components/ui/item.cjs +1 -1
  123. package/dist/components/ui/item.cjs.map +1 -1
  124. package/dist/components/ui/item.js +1 -1
  125. package/dist/components/ui/item.js.map +1 -1
  126. package/dist/components/ui/menubar.cjs +1 -1
  127. package/dist/components/ui/menubar.cjs.map +1 -1
  128. package/dist/components/ui/menubar.js +1 -1
  129. package/dist/components/ui/menubar.js.map +1 -1
  130. package/dist/components/ui/navigation-menu.cjs +1 -1
  131. package/dist/components/ui/navigation-menu.cjs.map +1 -1
  132. package/dist/components/ui/navigation-menu.js +54 -54
  133. package/dist/components/ui/navigation-menu.js.map +1 -1
  134. package/dist/components/ui/resizable.cjs +1 -1
  135. package/dist/components/ui/resizable.cjs.map +1 -1
  136. package/dist/components/ui/resizable.js +27 -15
  137. package/dist/components/ui/resizable.js.map +1 -1
  138. package/dist/components/ui/select.cjs +1 -1
  139. package/dist/components/ui/select.cjs.map +1 -1
  140. package/dist/components/ui/select.js +1 -1
  141. package/dist/components/ui/select.js.map +1 -1
  142. package/dist/components/ui/slider.cjs +1 -1
  143. package/dist/components/ui/slider.cjs.map +1 -1
  144. package/dist/components/ui/slider.js +9 -9
  145. package/dist/components/ui/slider.js.map +1 -1
  146. package/dist/components/ui/table.cjs +1 -1
  147. package/dist/components/ui/table.cjs.map +1 -1
  148. package/dist/components/ui/table.js +13 -13
  149. package/dist/components/ui/table.js.map +1 -1
  150. package/dist/components/ui/tabs.cjs +1 -1
  151. package/dist/components/ui/tabs.cjs.map +1 -1
  152. package/dist/components/ui/tabs.js +7 -7
  153. package/dist/components/ui/tabs.js.map +1 -1
  154. package/dist/components/ui/toggle.cjs +1 -1
  155. package/dist/components/ui/toggle.cjs.map +1 -1
  156. package/dist/components/ui/toggle.js +12 -12
  157. package/dist/components/ui/toggle.js.map +1 -1
  158. package/dist/hooks/use-element-size.cjs +2 -0
  159. package/dist/hooks/use-element-size.cjs.map +1 -0
  160. package/dist/hooks/use-element-size.js +21 -0
  161. package/dist/hooks/use-element-size.js.map +1 -0
  162. package/dist/hooks/use-plotly-theme.cjs +1 -1
  163. package/dist/hooks/use-plotly-theme.cjs.map +1 -1
  164. package/dist/hooks/use-plotly-theme.js +4 -2
  165. package/dist/hooks/use-plotly-theme.js.map +1 -1
  166. package/dist/index.cjs +1 -1
  167. package/dist/index.css +1 -1
  168. package/dist/index.d.ts +254 -77
  169. package/dist/index.js +587 -581
  170. package/dist/index.js.map +1 -1
  171. package/dist/index.tailwind.css +1 -1
  172. package/dist/utils/colors.cjs +1 -1
  173. package/dist/utils/colors.cjs.map +1 -1
  174. package/dist/utils/colors.js +38 -93
  175. package/dist/utils/colors.js.map +1 -1
  176. package/package.json +18 -12
@@ -1,64 +1,59 @@
1
- import { jsx as d, jsxs as z } from "react/jsx-runtime";
2
- import P from "plotly.js-dist";
3
- import O, { useRef as q, useMemo as f, useEffect as A } from "react";
4
- import { usePlotlyTheme as F } from "../../../hooks/use-plotly-theme.js";
5
- import { COLORS as x } from "../../../utils/colors.js";
1
+ import { jsxs as I, jsx as u } from "react/jsx-runtime";
2
+ import A from "plotly.js-dist";
3
+ import G, { useRef as k, useMemo as x, useEffect as V } from "react";
4
+ import { useChartTooltip as J } from "../ChartTooltip/ChartTooltip.js";
5
+ import { useElementSize as K } from "../../../hooks/use-element-size.js";
6
+ import { usePlotlyTheme as Q } from "../../../hooks/use-plotly-theme.js";
7
+ import { cn as _ } from "../../../lib/utils.js";
8
+ import { CHART_COLORS as Z } from "../../../utils/colors.js";
6
9
  /* empty css */
7
- const _ = -0.5, W = (e) => e.reduce((n, l) => n + l, 0) / e.length, $ = (e, i) => {
8
- const l = e.map((r) => Math.pow(r - i, 2)).reduce((r, s) => r + s, 0) / e.length;
9
- return Math.sqrt(l);
10
- }, S = (e, i, n, l, r = 100) => {
11
- const s = [], u = [], p = (l - n) / (r - 1);
12
- for (let c = 0; c < r; c++) {
13
- const o = n + c * p;
14
- s.push(o);
15
- const g = _ * Math.pow((o - e) / i, 2), M = 1 / (i * Math.sqrt(2 * Math.PI)) * Math.exp(g);
16
- u.push(M);
10
+ const tt = -0.5, ot = (r) => r.reduce((e, s) => e + s, 0) / r.length, et = (r, c) => {
11
+ const s = r.map((i) => Math.pow(i - c, 2)).reduce((i, a) => i + a, 0) / r.length;
12
+ return Math.sqrt(s);
13
+ }, nt = (r, c, e, s, i = 100) => {
14
+ const a = [], p = [], g = (s - e) / (i - 1);
15
+ for (let n = 0; n < i; n++) {
16
+ const o = e + n * g;
17
+ a.push(o);
18
+ const b = tt * Math.pow((o - r) / c, 2), z = 1 / (c * Math.sqrt(2 * Math.PI)) * Math.exp(b);
19
+ p.push(z);
17
20
  }
18
- return { x: s, y: u };
19
- }, U = (e, i, n) => {
20
- const l = Math.ceil((n.end - n.start) / n.size), r = Array(l).fill(0);
21
- i.forEach((c) => {
22
- if (c >= n.start && c <= n.end) {
23
- const o = Math.floor((c - n.start) / n.size);
24
- r[o]++;
21
+ return { x: a, y: p };
22
+ }, rt = (r, c, e) => {
23
+ const s = Math.ceil((e.end - e.start) / e.size), i = Array(s).fill(0);
24
+ c.forEach((n) => {
25
+ if (n >= e.start && n <= e.end) {
26
+ const o = Math.floor((n - e.start) / e.size);
27
+ i[o]++;
25
28
  }
26
29
  });
27
- const s = Math.max(...r), u = Math.max(...e), p = s / u;
28
- return e.map((c) => c * p);
29
- }, K = ({
30
- dataSeries: e,
31
- width: i = 480,
32
- height: n = 480,
33
- title: l = "Histogram",
34
- xTitle: r = "X Axis",
35
- yTitle: s = "Frequency",
36
- bargap: u = 0.2,
37
- showDistributionLine: p = !1
30
+ const a = Math.max(...i), p = Math.max(...r), g = a / p;
31
+ return r.map((n) => n * g);
32
+ }, ft = ({
33
+ dataSeries: r,
34
+ width: c,
35
+ height: e,
36
+ title: s = "Histogram",
37
+ xTitle: i = "X Axis",
38
+ yTitle: a = "Frequency",
39
+ bargap: p = 0.2,
40
+ showDistributionLine: g = !1
38
41
  }) => {
39
- const c = q(null), o = F(), g = f(
40
- () => Array.isArray(e) ? e : [e],
41
- [e]
42
- ), M = f(() => g.length > 1 ? "stack" : void 0, [g.length]), v = f(
43
- () => [
44
- x.ORANGE,
45
- x.RED,
46
- x.BLUE,
47
- x.GREEN,
48
- x.PURPLE,
49
- x.YELLOW
50
- ],
51
- []
52
- ), y = f(() => g.map((t, h) => {
53
- const m = typeof t.showDistributionLine > "u" ? p : t.showDistributionLine;
42
+ const n = k(null), o = Q(), { bindTooltip: b, tooltipElement: z } = J({ xLabel: i, yLabel: a }), [j, q] = K(), m = c ?? q.width, f = e ?? q.height, B = m > 0 && f > 0, X = c === void 0, D = e === void 0, M = k({ width: m, height: f });
43
+ M.current = { width: m, height: f };
44
+ const R = k(!1), C = k({ width: 0, height: 0 }), N = x(
45
+ () => Array.isArray(r) ? r : [r],
46
+ [r]
47
+ ), F = x(() => N.length > 1 ? "stack" : void 0, [N.length]), L = Z, y = x(() => N.map((t, d) => {
48
+ const h = typeof t.showDistributionLine > "u" ? g : t.showDistributionLine;
54
49
  return {
55
50
  ...t,
56
- color: t.color || v[h % v.length],
57
- opacity: m ? 0.5 : t.opacity || 1,
58
- showDistributionLine: m,
51
+ color: t.color || L[d % L.length],
52
+ opacity: h ? 0.5 : t.opacity || 1,
53
+ showDistributionLine: h,
59
54
  lineWidth: t.lineWidth || 3
60
55
  };
61
- }), [g, p, v]), N = o.gridColor, C = f(
56
+ }), [N, g, L]), E = o.gridColor, P = x(
62
57
  () => y.map((t) => ({
63
58
  type: "histogram",
64
59
  x: t.x,
@@ -73,30 +68,30 @@ const _ = -0.5, W = (e) => e.reduce((n, l) => n + l, 0) / e.length, $ = (e, i) =
73
68
  },
74
69
  autobinx: t.autobinx,
75
70
  xbins: t.xbins,
76
- hovertemplate: `${r}: %{x}<br>${s}: %{y}<extra>${t.name}</extra>`
71
+ hoverinfo: "none"
77
72
  })),
78
- [y, r, s, o]
79
- ), D = f(
73
+ [y, o]
74
+ ), O = x(
80
75
  () => y.filter((t) => t.showDistributionLine).map((t) => {
81
- const h = W(t.x), m = $(t.x, h), b = Math.min(...t.x), a = Math.max(...t.x), w = a - b, E = b - w * 0.1, L = a + w * 0.1, B = t.xbins || {
82
- start: E,
83
- end: L,
84
- size: w / 10
85
- }, R = S(
76
+ const d = ot(t.x), h = et(t.x, d), w = Math.min(...t.x), l = Math.max(...t.x), v = l - w, W = w - v * 0.1, H = l + v * 0.1, Y = t.xbins || {
77
+ start: W,
78
+ end: H,
79
+ size: v / 10
80
+ }, T = nt(
81
+ d,
86
82
  h,
87
- m,
88
- E,
89
- L,
83
+ W,
84
+ H,
90
85
  100
91
- ), I = U(
92
- R.y,
86
+ ), $ = rt(
87
+ T.y,
93
88
  t.x,
94
- B
89
+ Y
95
90
  );
96
91
  return {
97
92
  type: "scatter",
98
- x: R.x,
99
- y: I,
93
+ x: T.x,
94
+ y: $,
100
95
  mode: "lines",
101
96
  name: `${t.name} Distribution`,
102
97
  line: {
@@ -107,15 +102,15 @@ const _ = -0.5, W = (e) => e.reduce((n, l) => n + l, 0) / e.length, $ = (e, i) =
107
102
  };
108
103
  }),
109
104
  [y]
110
- ), k = f(
111
- () => [...C, ...D],
112
- [C, D]
105
+ ), S = x(
106
+ () => [...P, ...O],
107
+ [P, O]
113
108
  );
114
- return A(() => {
115
- if (!c.current) return;
109
+ V(() => {
110
+ if (!n.current || !B) return;
116
111
  const t = {
117
- width: i,
118
- height: n,
112
+ width: M.current.width,
113
+ height: M.current.height,
119
114
  font: {
120
115
  family: "Inter, sans-serif"
121
116
  },
@@ -123,7 +118,7 @@ const _ = -0.5, W = (e) => e.reduce((n, l) => n + l, 0) / e.length, $ = (e, i) =
123
118
  margin: { l: 90, r: 40, b: 80, t: 40 },
124
119
  xaxis: {
125
120
  title: {
126
- text: r,
121
+ text: i,
127
122
  font: {
128
123
  size: 16,
129
124
  color: o.textSecondary,
@@ -132,18 +127,19 @@ const _ = -0.5, W = (e) => e.reduce((n, l) => n + l, 0) / e.length, $ = (e, i) =
132
127
  },
133
128
  standoff: 20
134
129
  },
135
- gridcolor: N,
130
+ gridcolor: E,
136
131
  tickcolor: o.tickColor,
137
132
  ticklen: 8,
138
133
  tickwidth: 1,
139
134
  ticks: "outside",
140
135
  linecolor: o.lineColor,
141
136
  linewidth: 1,
142
- zeroline: !1
137
+ zeroline: !1,
138
+ automargin: !0
143
139
  },
144
140
  yaxis: {
145
141
  title: {
146
- text: s,
142
+ text: a,
147
143
  font: {
148
144
  size: 16,
149
145
  color: o.textSecondary,
@@ -152,7 +148,7 @@ const _ = -0.5, W = (e) => e.reduce((n, l) => n + l, 0) / e.length, $ = (e, i) =
152
148
  },
153
149
  standoff: 20
154
150
  },
155
- gridcolor: N,
151
+ gridcolor: E,
156
152
  tickcolor: o.tickColor,
157
153
  ticklen: 8,
158
154
  tickwidth: 1,
@@ -160,50 +156,71 @@ const _ = -0.5, W = (e) => e.reduce((n, l) => n + l, 0) / e.length, $ = (e, i) =
160
156
  linecolor: o.lineColor,
161
157
  linewidth: 1,
162
158
  zeroline: !1,
163
- rangemode: "tozero"
159
+ rangemode: "tozero",
160
+ automargin: !0
164
161
  },
165
- barmode: M,
166
- bargap: u,
162
+ barmode: F,
163
+ bargap: p,
167
164
  paper_bgcolor: o.paperBg,
168
165
  plot_bgcolor: o.plotBg
169
- }, h = {
170
- responsive: !0,
166
+ }, d = {
167
+ // Sizing is driven from the measured container; disable Plotly's own
168
+ // window-resize responsiveness (it can't see container resizes).
169
+ responsive: !1,
171
170
  displayModeBar: !1,
172
171
  displaylogo: !1
173
172
  };
174
- P.newPlot(c.current, k, t, h);
175
- const m = c.current;
176
- return () => {
177
- m && P.purge(m);
173
+ A.newPlot(n.current, S, t, d), b(n.current);
174
+ const h = n.current;
175
+ return R.current = !0, C.current = { ...M.current }, () => {
176
+ h && (A.purge(h), R.current = !1);
178
177
  };
179
- }, [i, n, r, s, u, k, M, N, o]), /* @__PURE__ */ d("div", { className: "histogram-container", style: { width: i }, children: /* @__PURE__ */ z("div", { className: "chart-container", children: [
180
- l && /* @__PURE__ */ d("div", { className: "title-container", children: /* @__PURE__ */ d("h2", { className: "title", children: l }) }),
181
- /* @__PURE__ */ d(
182
- "div",
183
- {
184
- ref: c,
185
- style: {
186
- width: "100%",
187
- height: "100%",
188
- margin: "0"
189
- }
178
+ }, [B, i, a, p, S, F, E, o, b]), V(() => {
179
+ const t = n.current;
180
+ !t || !R.current || m <= 0 || f <= 0 || C.current.width === m && C.current.height === f || (C.current = { width: m, height: f }, A.relayout(t, { width: m, height: f }).catch(
181
+ () => {
190
182
  }
191
- ),
192
- /* @__PURE__ */ d(({ series: t }) => {
193
- const h = t.map((a, w) => /* @__PURE__ */ d(O.Fragment, { children: /* @__PURE__ */ z("div", { className: "legend-item", children: [
194
- /* @__PURE__ */ d("span", { className: "color-box", style: { background: a.color } }),
195
- a.name,
196
- w < t.length - 1 && /* @__PURE__ */ d("span", { className: "divider" })
197
- ] }) }, a.name)), m = [], b = 6;
198
- for (let a = 0; a < h.length; a += b)
199
- m.push(
200
- /* @__PURE__ */ d("div", { className: "legend-row", children: h.slice(a, a + b) }, a)
201
- );
202
- return /* @__PURE__ */ d("div", { className: "legend-container", children: m });
203
- }, { series: y })
204
- ] }) });
183
+ ));
184
+ }, [m, f]);
185
+ const U = ({ series: t }) => {
186
+ const d = t.map((l, v) => /* @__PURE__ */ u(G.Fragment, { children: /* @__PURE__ */ I("div", { className: "legend-item", children: [
187
+ /* @__PURE__ */ u("span", { className: "color-box", style: { background: l.color } }),
188
+ l.name,
189
+ v < t.length - 1 && /* @__PURE__ */ u("span", { className: "divider" })
190
+ ] }) }, l.name)), h = [], w = 6;
191
+ for (let l = 0; l < d.length; l += w)
192
+ h.push(
193
+ /* @__PURE__ */ u("div", { className: "legend-row", children: d.slice(l, l + w) }, l)
194
+ );
195
+ return /* @__PURE__ */ u("div", { className: "legend-container", children: h });
196
+ };
197
+ return /* @__PURE__ */ I(
198
+ "div",
199
+ {
200
+ className: _("histogram-container relative", X && "w-full", D && "h-full"),
201
+ style: c === void 0 ? void 0 : { width: c },
202
+ children: [
203
+ /* @__PURE__ */ I("div", { className: _("chart-container", D && "flex h-full flex-col"), children: [
204
+ s && /* @__PURE__ */ u("div", { className: "title-container", children: /* @__PURE__ */ u("h2", { className: "title", children: s }) }),
205
+ /* @__PURE__ */ u("div", { ref: j, className: _(D && "min-h-0 flex-1"), children: /* @__PURE__ */ u(
206
+ "div",
207
+ {
208
+ ref: n,
209
+ style: {
210
+ width: "100%",
211
+ height: "100%",
212
+ margin: "0"
213
+ }
214
+ }
215
+ ) }),
216
+ /* @__PURE__ */ u(U, { series: y })
217
+ ] }),
218
+ z
219
+ ]
220
+ }
221
+ );
205
222
  };
206
223
  export {
207
- K as Histogram
224
+ ft as Histogram
208
225
  };
209
226
  //# sourceMappingURL=Histogram.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Histogram.js","sources":["../../../../src/components/charts/Histogram/Histogram.tsx"],"sourcesContent":["import Plotly from \"plotly.js-dist\";\nimport React, { useEffect, useRef, useMemo } from \"react\";\n\nimport { usePlotlyTheme } from \"@/hooks/use-plotly-theme\";\nimport { COLORS } from \"@/utils/colors\";\nimport \"./Histogram.scss\";\n\n/** Exponent coefficient for normal distribution calculation */\nconst NORMAL_DISTRIBUTION_EXPONENT_COEFF = -0.5;\n\ninterface HistogramDataSeries {\n x: number[];\n name: string;\n color?: string;\n autobinx?: boolean;\n xbins?: {\n start: number;\n end: number;\n size: number;\n };\n opacity?: number;\n showDistributionLine?: boolean;\n lineWidth?: number;\n}\n\ntype HistogramProps = {\n dataSeries: HistogramDataSeries | HistogramDataSeries[];\n width?: number;\n height?: number;\n title?: string;\n xTitle?: string;\n yTitle?: string;\n bargap?: number;\n showDistributionLine?: boolean;\n};\n\nconst calculateMean = (data: number[]): number => {\n const sum = data.reduce((acc, val) => acc + val, 0);\n return sum / data.length;\n};\n\nconst calculateStdDev = (data: number[], mean: number): number => {\n const squaredDiffs = data.map((value) => Math.pow(value - mean, 2));\n const variance =\n squaredDiffs.reduce((acc, val) => acc + val, 0) / data.length;\n return Math.sqrt(variance);\n};\n\nconst generateNormalDistributionPoints = (\n mean: number,\n stdDev: number,\n start: number,\n end: number,\n points = 100\n): { x: number[]; y: number[] } => {\n const xValues: number[] = [];\n const yValues: number[] = [];\n\n const step = (end - start) / (points - 1);\n\n for (let i = 0; i < points; i++) {\n const x = start + i * step;\n xValues.push(x);\n\n const exponent = NORMAL_DISTRIBUTION_EXPONENT_COEFF * Math.pow((x - mean) / stdDev, 2);\n const y = (1 / (stdDev * Math.sqrt(2 * Math.PI))) * Math.exp(exponent);\n yValues.push(y);\n }\n\n return { x: xValues, y: yValues };\n};\n\nconst scaleDistributionCurve = (\n yValues: number[],\n histogramData: number[],\n bins: { start: number; end: number; size: number }\n): number[] => {\n const binCount = Math.ceil((bins.end - bins.start) / bins.size);\n const binFrequencies = Array(binCount).fill(0);\n\n histogramData.forEach((value) => {\n if (value >= bins.start && value <= bins.end) {\n const binIndex = Math.floor((value - bins.start) / bins.size);\n binFrequencies[binIndex]++;\n }\n });\n\n const maxBinFrequency = Math.max(...binFrequencies);\n const maxCurveValue = Math.max(...yValues);\n\n const scaleFactor = maxBinFrequency / maxCurveValue;\n\n return yValues.map((y) => y * scaleFactor);\n};\n\nconst Histogram: React.FC<HistogramProps> = ({\n dataSeries,\n width = 480,\n height = 480,\n title = \"Histogram\",\n xTitle = \"X Axis\",\n yTitle = \"Frequency\",\n bargap = 0.2,\n showDistributionLine = false,\n}) => {\n const plotRef = useRef<HTMLDivElement>(null);\n const theme = usePlotlyTheme();\n const seriesArray = useMemo(\n () => (Array.isArray(dataSeries) ? dataSeries : [dataSeries]),\n [dataSeries],\n );\n const effectiveBarMode = useMemo<\n \"stack\" | \"group\" | \"overlay\" | \"relative\" | undefined\n >(() => (seriesArray.length > 1 ? \"stack\" : undefined), [seriesArray.length]);\n\n const defaultColors = useMemo(\n () => [\n COLORS.ORANGE,\n COLORS.RED,\n COLORS.BLUE,\n COLORS.GREEN,\n COLORS.PURPLE,\n COLORS.YELLOW,\n ],\n [],\n );\n\n const seriesWithColors = useMemo(() => {\n return seriesArray.map((series, index) => {\n const hasDistributionLine =\n typeof series.showDistributionLine === \"undefined\"\n ? showDistributionLine\n : series.showDistributionLine;\n\n return {\n ...series,\n color: series.color || defaultColors[index % defaultColors.length],\n opacity: hasDistributionLine ? 0.5 : series.opacity || 1,\n showDistributionLine: hasDistributionLine,\n lineWidth: series.lineWidth || 3,\n };\n });\n }, [seriesArray, showDistributionLine, defaultColors]);\n\n const gridColor = theme.gridColor;\n\n const histogramData = useMemo(\n () =>\n seriesWithColors.map((series) => ({\n type: \"histogram\" as const,\n x: series.x,\n name: series.name,\n marker: {\n color: series.color,\n line: {\n color: theme.paperBg,\n width: 1,\n },\n opacity: series.opacity,\n },\n autobinx: series.autobinx,\n xbins: series.xbins,\n hovertemplate: `${xTitle}: %{x}<br>${yTitle}: %{y}<extra>${series.name}</extra>`,\n })),\n [seriesWithColors, xTitle, yTitle, theme],\n );\n\n const distributionLines = useMemo(\n () =>\n seriesWithColors\n .filter((series) => series.showDistributionLine)\n .map((series) => {\n const mean = calculateMean(series.x);\n const stdDev = calculateStdDev(series.x, mean);\n\n const min = Math.min(...series.x);\n const max = Math.max(...series.x);\n const range = max - min;\n const start = min - range * 0.1;\n const end = max + range * 0.1;\n\n const bins = series.xbins || {\n start: start,\n end: end,\n size: range / 10,\n };\n\n const curvePoints = generateNormalDistributionPoints(\n mean,\n stdDev,\n start,\n end,\n 100,\n );\n\n const scaledYValues = scaleDistributionCurve(\n curvePoints.y,\n series.x,\n bins,\n );\n\n return {\n type: \"scatter\" as const,\n x: curvePoints.x,\n y: scaledYValues,\n mode: \"lines\" as const,\n name: `${series.name} Distribution`,\n line: {\n color: series.color,\n width: series.lineWidth,\n },\n hoverinfo: \"none\" as const,\n };\n }),\n [seriesWithColors],\n );\n\n const plotData = useMemo(\n () => [...histogramData, ...distributionLines],\n [histogramData, distributionLines],\n );\n\n useEffect(() => {\n if (!plotRef.current) return;\n\n const layout = {\n width,\n height,\n font: {\n family: \"Inter, sans-serif\",\n },\n showlegend: false,\n margin: { l: 90, r: 40, b: 80, t: 40 },\n xaxis: {\n title: {\n text: xTitle,\n font: {\n size: 16,\n color: theme.textSecondary,\n family: \"Inter, sans-serif\",\n weight: 400,\n },\n standoff: 20,\n },\n gridcolor: gridColor,\n tickcolor: theme.tickColor,\n ticklen: 8,\n tickwidth: 1,\n ticks: \"outside\" as const,\n linecolor: theme.lineColor,\n linewidth: 1,\n zeroline: false,\n },\n yaxis: {\n title: {\n text: yTitle,\n font: {\n size: 16,\n color: theme.textSecondary,\n family: \"Inter, sans-serif\",\n weight: 400,\n },\n standoff: 20,\n },\n gridcolor: gridColor,\n tickcolor: theme.tickColor,\n ticklen: 8,\n tickwidth: 1,\n ticks: \"outside\" as const,\n linecolor: theme.lineColor,\n linewidth: 1,\n zeroline: false,\n rangemode: \"tozero\" as const,\n },\n barmode: effectiveBarMode,\n bargap: bargap,\n paper_bgcolor: theme.paperBg,\n plot_bgcolor: theme.plotBg,\n };\n\n const config = {\n responsive: true,\n displayModeBar: false,\n displaylogo: false,\n };\n\n Plotly.newPlot(plotRef.current, plotData, layout, config);\n\n // Capture ref value for cleanup\n const plotElement = plotRef.current;\n\n return () => {\n if (plotElement) {\n Plotly.purge(plotElement);\n }\n };\n }, [width, height, xTitle, yTitle, bargap, plotData, effectiveBarMode, gridColor, theme]);\n\n const ChartLegend: React.FC<{\n series: Array<{ name: string; color: string }>;\n }> = ({ series }) => {\n const items = series.map((item, i) => (\n <React.Fragment key={item.name}>\n <div className=\"legend-item\">\n <span className=\"color-box\" style={{ background: item.color }} />\n {item.name}\n {i < series.length - 1 && <span className=\"divider\" />}\n </div>\n </React.Fragment>\n ));\n\n const rows = [];\n const rowSize = 6;\n for (let i = 0; i < items.length; i += rowSize) {\n rows.push(\n <div className=\"legend-row\" key={i}>\n {items.slice(i, i + rowSize)}\n </div>\n );\n }\n\n return <div className=\"legend-container\">{rows}</div>;\n };\n\n return (\n <div className=\"histogram-container\" style={{ width: width }}>\n <div className=\"chart-container\">\n {title && (\n <div className=\"title-container\">\n <h2 className=\"title\">{title}</h2>\n </div>\n )}\n <div\n ref={plotRef}\n style={{\n width: \"100%\",\n height: \"100%\",\n margin: \"0\",\n }}\n />\n <ChartLegend series={seriesWithColors} />\n </div>\n </div>\n );\n};\n\nexport { Histogram };\nexport type { HistogramDataSeries, HistogramProps };\n"],"names":["NORMAL_DISTRIBUTION_EXPONENT_COEFF","calculateMean","data","acc","val","calculateStdDev","mean","variance","value","generateNormalDistributionPoints","stdDev","start","end","points","xValues","yValues","step","i","x","exponent","y","scaleDistributionCurve","histogramData","bins","binCount","binFrequencies","binIndex","maxBinFrequency","maxCurveValue","scaleFactor","Histogram","dataSeries","width","height","title","xTitle","yTitle","bargap","showDistributionLine","plotRef","useRef","theme","usePlotlyTheme","seriesArray","useMemo","effectiveBarMode","defaultColors","COLORS","seriesWithColors","series","index","hasDistributionLine","gridColor","distributionLines","min","max","range","curvePoints","scaledYValues","plotData","useEffect","layout","config","Plotly","plotElement","jsx","jsxs","items","item","React","rows","rowSize"],"mappings":"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"}
1
+ {"version":3,"file":"Histogram.js","sources":["../../../../src/components/charts/Histogram/Histogram.tsx"],"sourcesContent":["import Plotly from \"plotly.js-dist\";\nimport React, { useEffect, useRef, useMemo } from \"react\";\n\nimport { useChartTooltip } from \"../ChartTooltip\";\n\nimport { useElementSize } from \"@/hooks/use-element-size\";\nimport { usePlotlyTheme } from \"@/hooks/use-plotly-theme\";\nimport { cn } from \"@/lib/utils\";\nimport { CHART_COLORS } from \"@/utils/colors\";\nimport \"./Histogram.scss\";\n\n/** Exponent coefficient for normal distribution calculation */\nconst NORMAL_DISTRIBUTION_EXPONENT_COEFF = -0.5;\n\ninterface HistogramDataSeries {\n x: number[];\n name: string;\n color?: string;\n autobinx?: boolean;\n xbins?: {\n start: number;\n end: number;\n size: number;\n };\n opacity?: number;\n showDistributionLine?: boolean;\n lineWidth?: number;\n}\n\ntype HistogramProps = {\n dataSeries: HistogramDataSeries | HistogramDataSeries[];\n /**\n * Fixed width in pixels. When omitted, the chart fills its container and\n * tracks the container's width via a `ResizeObserver`.\n */\n width?: number;\n /**\n * Fixed height in pixels. When omitted, the chart fills its container and\n * tracks the container's height via a `ResizeObserver`.\n */\n height?: number;\n title?: string;\n xTitle?: string;\n yTitle?: string;\n bargap?: number;\n showDistributionLine?: boolean;\n};\n\nconst calculateMean = (data: number[]): number => {\n const sum = data.reduce((acc, val) => acc + val, 0);\n return sum / data.length;\n};\n\nconst calculateStdDev = (data: number[], mean: number): number => {\n const squaredDiffs = data.map((value) => Math.pow(value - mean, 2));\n const variance =\n squaredDiffs.reduce((acc, val) => acc + val, 0) / data.length;\n return Math.sqrt(variance);\n};\n\nconst generateNormalDistributionPoints = (\n mean: number,\n stdDev: number,\n start: number,\n end: number,\n points = 100\n): { x: number[]; y: number[] } => {\n const xValues: number[] = [];\n const yValues: number[] = [];\n\n const step = (end - start) / (points - 1);\n\n for (let i = 0; i < points; i++) {\n const x = start + i * step;\n xValues.push(x);\n\n const exponent = NORMAL_DISTRIBUTION_EXPONENT_COEFF * Math.pow((x - mean) / stdDev, 2);\n const y = (1 / (stdDev * Math.sqrt(2 * Math.PI))) * Math.exp(exponent);\n yValues.push(y);\n }\n\n return { x: xValues, y: yValues };\n};\n\nconst scaleDistributionCurve = (\n yValues: number[],\n histogramData: number[],\n bins: { start: number; end: number; size: number }\n): number[] => {\n const binCount = Math.ceil((bins.end - bins.start) / bins.size);\n const binFrequencies = Array(binCount).fill(0);\n\n histogramData.forEach((value) => {\n if (value >= bins.start && value <= bins.end) {\n const binIndex = Math.floor((value - bins.start) / bins.size);\n binFrequencies[binIndex]++;\n }\n });\n\n const maxBinFrequency = Math.max(...binFrequencies);\n const maxCurveValue = Math.max(...yValues);\n\n const scaleFactor = maxBinFrequency / maxCurveValue;\n\n return yValues.map((y) => y * scaleFactor);\n};\n\nconst Histogram: React.FC<HistogramProps> = ({\n dataSeries,\n width,\n height,\n title = \"Histogram\",\n xTitle = \"X Axis\",\n yTitle = \"Frequency\",\n bargap = 0.2,\n showDistributionLine = false,\n}) => {\n const plotRef = useRef<HTMLDivElement>(null);\n const theme = usePlotlyTheme();\n const { bindTooltip, tooltipElement } = useChartTooltip({ xLabel: xTitle, yLabel: yTitle });\n\n // Omitted width/height → fill the container and track its measured size;\n // explicit pixel values override. Histogram has its own HTML title + legend,\n // so we measure a wrapper around just the Plotly canvas. See AreaGraph for\n // the reference pattern.\n const [plotAreaRef, measured] = useElementSize<HTMLDivElement>();\n const resolvedWidth = width ?? measured.width;\n const resolvedHeight = height ?? measured.height;\n const hasSize = resolvedWidth > 0 && resolvedHeight > 0;\n // Fill is per-dimension: omit width to fill the container width, omit height\n // to fill its height (so e.g. a fixed width with a container-driven height works).\n const fillWidth = width === undefined;\n const fillHeight = height === undefined;\n const sizeRef = useRef({ width: resolvedWidth, height: resolvedHeight });\n sizeRef.current = { width: resolvedWidth, height: resolvedHeight };\n const plotInitedRef = useRef(false);\n // Size last applied to the plot, so the resize effect can skip a redundant\n // relayout right after newPlot already drew at that size.\n const appliedSizeRef = useRef({ width: 0, height: 0 });\n const seriesArray = useMemo(\n () => (Array.isArray(dataSeries) ? dataSeries : [dataSeries]),\n [dataSeries],\n );\n const effectiveBarMode = useMemo<\n \"stack\" | \"group\" | \"overlay\" | \"relative\" | undefined\n >(() => (seriesArray.length > 1 ? \"stack\" : undefined), [seriesArray.length]);\n\n const defaultColors = CHART_COLORS;\n\n const seriesWithColors = useMemo(() => {\n return seriesArray.map((series, index) => {\n const hasDistributionLine =\n typeof series.showDistributionLine === \"undefined\"\n ? showDistributionLine\n : series.showDistributionLine;\n\n return {\n ...series,\n color: series.color || defaultColors[index % defaultColors.length],\n opacity: hasDistributionLine ? 0.5 : series.opacity || 1,\n showDistributionLine: hasDistributionLine,\n lineWidth: series.lineWidth || 3,\n };\n });\n }, [seriesArray, showDistributionLine, defaultColors]);\n\n const gridColor = theme.gridColor;\n\n const histogramData = useMemo(\n () =>\n seriesWithColors.map((series) => ({\n type: \"histogram\" as const,\n x: series.x,\n name: series.name,\n marker: {\n color: series.color,\n line: {\n color: theme.paperBg,\n width: 1,\n },\n opacity: series.opacity,\n },\n autobinx: series.autobinx,\n xbins: series.xbins,\n hoverinfo: \"none\" as const,\n })),\n [seriesWithColors, theme],\n );\n\n const distributionLines = useMemo(\n () =>\n seriesWithColors\n .filter((series) => series.showDistributionLine)\n .map((series) => {\n const mean = calculateMean(series.x);\n const stdDev = calculateStdDev(series.x, mean);\n\n const min = Math.min(...series.x);\n const max = Math.max(...series.x);\n const range = max - min;\n const start = min - range * 0.1;\n const end = max + range * 0.1;\n\n const bins = series.xbins || {\n start: start,\n end: end,\n size: range / 10,\n };\n\n const curvePoints = generateNormalDistributionPoints(\n mean,\n stdDev,\n start,\n end,\n 100,\n );\n\n const scaledYValues = scaleDistributionCurve(\n curvePoints.y,\n series.x,\n bins,\n );\n\n return {\n type: \"scatter\" as const,\n x: curvePoints.x,\n y: scaledYValues,\n mode: \"lines\" as const,\n name: `${series.name} Distribution`,\n line: {\n color: series.color,\n width: series.lineWidth,\n },\n hoverinfo: \"none\" as const,\n };\n }),\n [seriesWithColors],\n );\n\n const plotData = useMemo(\n () => [...histogramData, ...distributionLines],\n [histogramData, distributionLines],\n );\n\n useEffect(() => {\n if (!plotRef.current || !hasSize) return;\n\n const layout = {\n width: sizeRef.current.width,\n height: sizeRef.current.height,\n font: {\n family: \"Inter, sans-serif\",\n },\n showlegend: false,\n margin: { l: 90, r: 40, b: 80, t: 40 },\n xaxis: {\n title: {\n text: xTitle,\n font: {\n size: 16,\n color: theme.textSecondary,\n family: \"Inter, sans-serif\",\n weight: 400,\n },\n standoff: 20,\n },\n gridcolor: gridColor,\n tickcolor: theme.tickColor,\n ticklen: 8,\n tickwidth: 1,\n ticks: \"outside\" as const,\n linecolor: theme.lineColor,\n linewidth: 1,\n zeroline: false,\n automargin: true,\n },\n yaxis: {\n title: {\n text: yTitle,\n font: {\n size: 16,\n color: theme.textSecondary,\n family: \"Inter, sans-serif\",\n weight: 400,\n },\n standoff: 20,\n },\n gridcolor: gridColor,\n tickcolor: theme.tickColor,\n ticklen: 8,\n tickwidth: 1,\n ticks: \"outside\" as const,\n linecolor: theme.lineColor,\n linewidth: 1,\n zeroline: false,\n rangemode: \"tozero\" as const,\n automargin: true,\n },\n barmode: effectiveBarMode,\n bargap: bargap,\n paper_bgcolor: theme.paperBg,\n plot_bgcolor: theme.plotBg,\n };\n\n const config = {\n // Sizing is driven from the measured container; disable Plotly's own\n // window-resize responsiveness (it can't see container resizes).\n responsive: false,\n displayModeBar: false,\n displaylogo: false,\n };\n\n Plotly.newPlot(plotRef.current, plotData, layout, config);\n bindTooltip(plotRef.current);\n\n // Capture ref value for cleanup\n const plotElement = plotRef.current;\n plotInitedRef.current = true;\n appliedSizeRef.current = { ...sizeRef.current };\n\n return () => {\n if (plotElement) {\n Plotly.purge(plotElement);\n plotInitedRef.current = false;\n }\n };\n }, [hasSize, xTitle, yTitle, bargap, plotData, effectiveBarMode, gridColor, theme, bindTooltip]);\n\n // Resize in place when the measured/overridden size changes — cheaper than\n // recreating the plot, and it preserves tooltip/event bindings.\n useEffect(() => {\n const plotElement = plotRef.current;\n if (!plotElement || !plotInitedRef.current || resolvedWidth <= 0 || resolvedHeight <= 0) {\n return;\n }\n // newPlot already drew at the current size; skip the redundant relayout\n // (it would queue an automargin redraw that can reject if we unmount first).\n if (\n appliedSizeRef.current.width === resolvedWidth &&\n appliedSizeRef.current.height === resolvedHeight\n ) {\n return;\n }\n appliedSizeRef.current = { width: resolvedWidth, height: resolvedHeight };\n // Swallow rejections from a relayout that races an unmount/purge.\n void Plotly.relayout(plotElement, { width: resolvedWidth, height: resolvedHeight }).catch(\n () => {},\n );\n }, [resolvedWidth, resolvedHeight]);\n\n const ChartLegend: React.FC<{\n series: Array<{ name: string; color: string }>;\n }> = ({ series }) => {\n const items = series.map((item, i) => (\n <React.Fragment key={item.name}>\n <div className=\"legend-item\">\n <span className=\"color-box\" style={{ background: item.color }} />\n {item.name}\n {i < series.length - 1 && <span className=\"divider\" />}\n </div>\n </React.Fragment>\n ));\n\n const rows = [];\n const rowSize = 6;\n for (let i = 0; i < items.length; i += rowSize) {\n rows.push(\n <div className=\"legend-row\" key={i}>\n {items.slice(i, i + rowSize)}\n </div>\n );\n }\n\n return <div className=\"legend-container\">{rows}</div>;\n };\n\n return (\n <div\n className={cn(\"histogram-container relative\", fillWidth && \"w-full\", fillHeight && \"h-full\")}\n style={width === undefined ? undefined : { width }}\n >\n <div className={cn(\"chart-container\", fillHeight && \"flex h-full flex-col\")}>\n {title && (\n <div className=\"title-container\">\n <h2 className=\"title\">{title}</h2>\n </div>\n )}\n {/* Measured plot area — flexes to fill the space left by the title and\n legend in fill mode, so the Plotly canvas tracks it. */}\n <div ref={plotAreaRef} className={cn(fillHeight && \"min-h-0 flex-1\")}>\n <div\n ref={plotRef}\n style={{\n width: \"100%\",\n height: \"100%\",\n margin: \"0\",\n }}\n />\n </div>\n <ChartLegend series={seriesWithColors} />\n </div>\n {tooltipElement}\n </div>\n );\n};\n\nexport { Histogram };\nexport type { HistogramDataSeries, HistogramProps };\n"],"names":["NORMAL_DISTRIBUTION_EXPONENT_COEFF","calculateMean","data","acc","val","calculateStdDev","mean","variance","value","generateNormalDistributionPoints","stdDev","start","end","points","xValues","yValues","step","i","x","exponent","y","scaleDistributionCurve","histogramData","bins","binCount","binFrequencies","binIndex","maxBinFrequency","maxCurveValue","scaleFactor","Histogram","dataSeries","width","height","title","xTitle","yTitle","bargap","showDistributionLine","plotRef","useRef","theme","usePlotlyTheme","bindTooltip","tooltipElement","useChartTooltip","plotAreaRef","measured","useElementSize","resolvedWidth","resolvedHeight","hasSize","fillWidth","fillHeight","sizeRef","plotInitedRef","appliedSizeRef","seriesArray","useMemo","effectiveBarMode","defaultColors","CHART_COLORS","seriesWithColors","series","index","hasDistributionLine","gridColor","distributionLines","min","max","range","curvePoints","scaledYValues","plotData","useEffect","layout","config","Plotly","plotElement","ChartLegend","items","item","jsx","React","jsxs","rows","rowSize","cn"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const z=require("react/jsx-runtime"),L=require("plotly.js-dist"),i=require("react"),N=require("../../../hooks/use-plotly-theme.cjs"),P=({dataSeries:s,width:p=1e3,height:g=600,xRange:h,yRange:a,variant:m="lines",xTitle:x="Columns",yTitle:M="Rows",title:k="Line Graph"})=>{const f=i.useRef(null),t=N.usePlotlyTheme(),{yMin:w,yMax:b}=i.useMemo(()=>{let o=Number.MAX_VALUE,e=Number.MIN_VALUE,l=Number.MAX_VALUE,n=Number.MIN_VALUE;s.forEach(I=>{I.x.forEach(u=>{o=Math.min(o,u),e=Math.max(e,u)}),I.y.forEach(u=>{l=Math.min(l,u),n=Math.max(n,u)})});const r=(e-o)*.1,C=(n-l)*.1;return{xMin:o-r,xMax:e+r,yMin:l-C,yMax:n+C}},[s]),c=i.useMemo(()=>a||[w,b],[a,w,b]),_=i.useMemo(()=>{const o=c[1]-c[0];let e=Math.pow(10,Math.floor(Math.log10(o)));o/e>10&&(e=e*2),o/e<4&&(e=e/2);const l=[];let n=Math.ceil(c[0]/e)*e;for(;n<=c[1];)l.push(n),n+=e;return l},[c]),d=i.useMemo(()=>[...new Set(s.flatMap(o=>o.x))],[s]),E=i.useMemo(()=>{switch(m){case"lines+markers":case"lines+markers+error_bars":return"lines+markers";default:return"lines"}},[m]),y=i.useMemo(()=>({tickcolor:t.tickColor,ticklen:12,tickwidth:1,ticks:"outside",tickfont:{size:16,color:t.textColor,family:"Inter, sans-serif",weight:400},linecolor:t.lineColor,linewidth:1,position:0,zeroline:!1}),[t]);return i.useEffect(()=>{if(!f.current)return;const o=s.map(r=>({x:r.x,y:r.y,type:"scatter",mode:E,name:r.name,line:{color:r.color,width:1.5},marker:m==="lines"?{opacity:0}:{color:r.color,size:8,symbol:r.symbol||"triangle-up"},error_y:m==="lines+markers+error_bars"?r.error_y||{type:"data",array:r.y.map(()=>10),visible:!0,color:r.color,thickness:1,width:5}:void 0})),e={title:{text:k,font:{size:32,family:"Inter, sans-serif",color:t.textColor}},width:p,height:g,margin:{l:80,r:30,b:80,t:60,pad:10},paper_bgcolor:t.paperBg,plot_bgcolor:t.plotBg,font:{family:"Inter, sans-serif"},dragmode:!1,xaxis:{title:{text:x,font:{size:16,color:t.textSecondary,family:"Inter, sans-serif",weight:400},standoff:32},gridcolor:t.gridColor,range:h,autorange:!h,tickmode:"array",tickvals:d,ticktext:d.map(String),showgrid:!0,...y},yaxis:{title:{text:M,font:{size:16,color:t.textSecondary,family:"Inter, sans-serif",weight:400},standoff:30},gridcolor:t.gridColor,range:a,autorange:!a,tickmode:"array",tickvals:_,showgrid:!0,...y},legend:{x:.5,y:-.2,xanchor:"center",yanchor:"top",orientation:"h",font:{size:16,color:t.legendColor,family:"Inter, sans-serif",weight:500}},showlegend:!0},l={responsive:!0,displayModeBar:!1,displaylogo:!1};L.newPlot(f.current,o,e,l);const n=f.current;return()=>{n&&L.purge(n)}},[s,p,g,h,a,x,M,k,E,y,d,_,c,m,t]),z.jsx("div",{className:"chart-container",children:z.jsx("div",{ref:f,style:{width:"100%",height:"100%"}})})};exports.LineGraph=P;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const j=require("react/jsx-runtime"),z=require("plotly.js-dist"),o=require("react"),B=require("../ChartTooltip/ChartTooltip.cjs"),Y=require("../../../hooks/use-element-size.cjs"),H=require("../../../hooks/use-plotly-theme.cjs"),W=require("../../../lib/utils.cjs"),D=require("../../../utils/colors.cjs"),F=60,J=30,K=({dataSeries:a,width:C,height:L,xRange:k,yRange:m,variant:d="lines",xTitle:E,yTitle:_,title:p,xTickText:y})=>{const u=o.useRef(null),r=H.usePlotlyTheme(),{bindTooltip:N,tooltipElement:G}=B.useChartTooltip({xLabel:E,yLabel:_}),[T,P]=Y.useElementSize(),l=C??P.width,c=L??P.height,q=l>0&&c>0,U=C===void 0,V=L===void 0,M=o.useRef({width:l,height:c});M.current={width:l,height:c};const I=o.useRef(!1),w=o.useRef({width:0,height:0}),{yMin:A,yMax:R}=o.useMemo(()=>{let t=Number.MAX_VALUE,e=Number.MIN_VALUE,s=Number.MAX_VALUE,n=Number.MIN_VALUE;a.forEach(f=>{f.x.forEach(g=>{t=Math.min(t,g),e=Math.max(e,g)}),f.y.forEach(g=>{s=Math.min(s,g),n=Math.max(n,g)})});const i=(e-t)*.1,b=(n-s)*.1;return{xMin:t-i,xMax:e+i,yMin:s-b,yMax:n+b}},[a]),h=o.useMemo(()=>m||[A,R],[m,A,R]),O=o.useMemo(()=>{const t=h[1]-h[0];let e=Math.pow(10,Math.floor(Math.log10(t)));t/e>10&&(e=e*2),t/e<4&&(e=e/2);const s=[];let n=Math.ceil(h[0]/e)*e;for(;n<=h[1];)s.push(n),n+=e;return s},[h]),x=o.useMemo(()=>[...new Set(a.flatMap(t=>t.x))].sort((t,e)=>t-e),[a]),S=!!y&&y.length===x.length,X=o.useMemo(()=>{switch(d){case"lines+markers":case"lines+markers+error_bars":return"lines+markers";default:return"lines"}},[d]),v=o.useMemo(()=>({tickcolor:r.tickColor,ticklen:12,tickwidth:1,ticks:"outside",tickfont:{size:16,color:r.textColor,family:"Inter, sans-serif",weight:400},linecolor:r.lineColor,linewidth:1,position:0,zeroline:!1}),[r]);return o.useEffect(()=>{if(!u.current||!q)return;const t=a.map((i,b)=>{const f=D.seriesColor(b,i.color);return{x:i.x,y:i.y,type:"scatter",mode:X,name:i.name,hoverinfo:"none",line:{color:f,width:1.5},marker:d==="lines"?{opacity:0}:{color:f,size:8,symbol:i.symbol||"triangle-up"},error_y:d==="lines+markers+error_bars"?i.error_y||{type:"data",array:i.y.map(()=>10),visible:!0,color:f,thickness:1,width:5}:void 0}}),e={...p?{title:{text:p,font:{size:32,family:"Inter, sans-serif",color:r.textColor}}}:{},width:M.current.width,height:M.current.height,margin:{l:80,r:30,b:96,t:p?F:J,pad:10},paper_bgcolor:r.paperBg,plot_bgcolor:r.plotBg,font:{family:"Inter, sans-serif"},dragmode:!1,xaxis:{title:{text:E,font:{size:16,color:r.textSecondary,family:"Inter, sans-serif",weight:400},standoff:32},gridcolor:r.gridColor,range:k,autorange:!k,tickmode:"array",tickvals:x,ticktext:S?y:x.map(String),showgrid:!0,automargin:!0,...v},yaxis:{title:{text:_,font:{size:16,color:r.textSecondary,family:"Inter, sans-serif",weight:400},standoff:30},gridcolor:r.gridColor,range:m,autorange:!m,tickmode:"array",tickvals:O,showgrid:!0,automargin:!0,...v},legend:{x:.5,y:0,xanchor:"center",yanchor:"bottom",yref:"container",orientation:"h",font:{size:16,color:r.legendColor,family:"Inter, sans-serif",weight:500}},showlegend:!0},s={responsive:!1,displayModeBar:!1,displaylogo:!1};z.newPlot(u.current,t,e,s),N(u.current);const n=u.current;return I.current=!0,w.current={...M.current},()=>{n&&(z.purge(n),I.current=!1)}},[a,q,k,m,E,_,p,X,v,x,O,S,y,h,d,r,N]),o.useEffect(()=>{const t=u.current;!t||!I.current||l<=0||c<=0||w.current.width===l&&w.current.height===c||(w.current={width:l,height:c},z.relayout(t,{width:l,height:c}).catch(()=>{}))},[l,c]),j.jsxs("div",{ref:T,className:W.cn("relative",U&&"w-full",V&&"h-full"),children:[j.jsx("div",{ref:u,style:{width:"100%",height:"100%"}}),G]})};exports.LineGraph=K;
2
2
  //# sourceMappingURL=LineGraph.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"LineGraph.cjs","sources":["../../../../src/components/charts/LineGraph/LineGraph.tsx"],"sourcesContent":["import Plotly from \"plotly.js-dist\";\nimport React, { useEffect, useRef, useMemo } from \"react\";\n\nimport { usePlotlyTheme } from \"@/hooks/use-plotly-theme\";\n\ntype MarkerSymbol =\n | \"circle\"\n | \"circle-open\"\n | \"circle-dot\"\n | \"circle-open-dot\"\n | \"square\"\n | \"square-open\"\n | \"square-dot\"\n | \"square-open-dot\"\n | \"diamond\"\n | \"diamond-open\"\n | \"diamond-dot\"\n | \"diamond-open-dot\"\n | \"cross\"\n | \"cross-open\"\n | \"cross-dot\"\n | \"cross-open-dot\"\n | \"x\"\n | \"x-open\"\n | \"x-dot\"\n | \"x-open-dot\"\n | \"triangle-up\"\n | \"triangle-up-open\"\n | \"triangle-up-dot\"\n | \"triangle-up-open-dot\"\n | \"triangle-down\"\n | \"triangle-down-open\"\n | \"triangle-down-dot\"\n | \"triangle-down-open-dot\"\n | \"triangle-left\"\n | \"triangle-left-open\"\n | \"triangle-left-dot\"\n | \"triangle-left-open-dot\"\n | \"triangle-right\"\n | \"triangle-right-open\"\n | \"triangle-right-dot\"\n | \"triangle-right-open-dot\"\n | \"triangle-ne\"\n | \"triangle-ne-open\"\n | \"triangle-ne-dot\"\n | \"triangle-ne-open-dot\"\n | \"triangle-se\"\n | \"triangle-se-open\"\n | \"triangle-se-dot\"\n | \"triangle-se-open-dot\"\n | \"triangle-sw\"\n | \"triangle-sw-open\"\n | \"triangle-sw-dot\"\n | \"triangle-sw-open-dot\"\n | \"triangle-nw\"\n | \"triangle-nw-open\"\n | \"triangle-nw-dot\"\n | \"triangle-nw-open-dot\"\n | \"pentagon\"\n | \"pentagon-open\"\n | \"pentagon-dot\"\n | \"pentagon-open-dot\"\n | \"hexagon\"\n | \"hexagon-open\"\n | \"hexagon-dot\"\n | \"hexagon-open-dot\"\n | \"hexagon2\"\n | \"hexagon2-open\"\n | \"hexagon2-dot\"\n | \"hexagon2-open-dot\"\n | \"octagon\"\n | \"octagon-open\"\n | \"octagon-dot\"\n | \"octagon-open-dot\"\n | \"star\"\n | \"star-open\"\n | \"star-dot\"\n | \"star-open-dot\"\n | \"hexagram\"\n | \"hexagram-open\"\n | \"hexagram-dot\"\n | \"hexagram-open-dot\"\n | \"star-triangle-up\"\n | \"star-triangle-up-open\"\n | \"star-triangle-up-dot\"\n | \"star-triangle-up-open-dot\"\n | \"star-triangle-down\"\n | \"star-triangle-down-open\"\n | \"star-triangle-down-dot\"\n | \"star-triangle-down-open-dot\"\n | \"star-square\"\n | \"star-square-open\"\n | \"star-square-dot\"\n | \"star-square-open-dot\"\n | \"star-diamond\"\n | \"star-diamond-open\"\n | \"star-diamond-dot\"\n | \"star-diamond-open-dot\"\n | \"diamond-tall\"\n | \"diamond-tall-open\"\n | \"diamond-tall-dot\"\n | \"diamond-tall-open-dot\"\n | \"diamond-wide\"\n | \"diamond-wide-open\"\n | \"diamond-wide-dot\"\n | \"diamond-wide-open-dot\"\n | \"hourglass\"\n | \"hourglass-open\"\n | \"bowtie\"\n | \"bowtie-open\"\n | \"circle-cross\"\n | \"circle-cross-open\"\n | \"circle-x\"\n | \"circle-x-open\"\n | \"square-cross\"\n | \"square-cross-open\"\n | \"square-x\"\n | \"square-x-open\"\n | \"diamond-cross\"\n | \"diamond-cross-open\"\n | \"diamond-x\"\n | \"diamond-x-open\"\n | \"cross-thin\"\n | \"cross-thin-open\"\n | \"x-thin\"\n | \"x-thin-open\"\n | \"asterisk\"\n | \"asterisk-open\"\n | \"hash\"\n | \"hash-open\"\n | \"hash-dot\"\n | \"hash-open-dot\"\n | \"y-up\"\n | \"y-up-open\"\n | \"y-down\"\n | \"y-down-open\"\n | \"y-left\"\n | \"y-left-open\"\n | \"y-right\"\n | \"y-right-open\"\n | \"line-ew\"\n | \"line-ew-open\"\n | \"line-ns\"\n | \"line-ns-open\"\n | \"line-ne\"\n | \"line-ne-open\"\n | \"line-nw\"\n | \"line-nw-open\"\n | \"arrow\"\n | \"arrow-open\"\n | \"arrow-wide\"\n | \"arrow-wide-open\";\n\ninterface LineDataSeries {\n x: number[];\n y: number[];\n name: string;\n color: string;\n symbol?: MarkerSymbol;\n error_y?: {\n type: \"data\";\n array: number[];\n visible: boolean;\n };\n}\n\ntype LineGraphVariant = \"lines\" | \"lines+markers\" | \"lines+markers+error_bars\";\n\ntype LineGraphProps = {\n dataSeries: LineDataSeries[];\n width?: number;\n height?: number;\n xRange?: [number, number];\n yRange?: [number, number];\n variant?: LineGraphVariant;\n xTitle?: string;\n yTitle?: string;\n title?: string;\n};\n\nconst LineGraph: React.FC<LineGraphProps> = ({\n dataSeries,\n width = 1000,\n height = 600,\n xRange,\n yRange,\n variant = \"lines\",\n xTitle = \"Columns\",\n yTitle = \"Rows\",\n title = \"Line Graph\",\n}) => {\n const plotRef = useRef<HTMLDivElement>(null);\n const theme = usePlotlyTheme();\n\n const { yMin, yMax } = useMemo(() => {\n let minX = Number.MAX_VALUE;\n let maxX = Number.MIN_VALUE;\n let minY = Number.MAX_VALUE;\n let maxY = Number.MIN_VALUE;\n\n dataSeries.forEach((series) => {\n series.x.forEach((x) => {\n minX = Math.min(minX, x);\n maxX = Math.max(maxX, x);\n });\n series.y.forEach((y) => {\n minY = Math.min(minY, y);\n maxY = Math.max(maxY, y);\n });\n });\n\n const xPadding = (maxX - minX) * 0.1;\n const yPadding = (maxY - minY) * 0.1;\n\n return {\n xMin: minX - xPadding,\n xMax: maxX + xPadding,\n yMin: minY - yPadding,\n yMax: maxY + yPadding,\n };\n }, [dataSeries]);\n\n const effectiveYRange = useMemo(\n () => yRange || [yMin, yMax],\n [yRange, yMin, yMax],\n );\n\n const yTicks = useMemo(() => {\n const range = effectiveYRange[1] - effectiveYRange[0];\n let step = Math.pow(10, Math.floor(Math.log10(range)));\n\n if (range / step > 10) step = step * 2;\n if (range / step < 4) step = step / 2;\n\n const ticks = [];\n let current = Math.ceil(effectiveYRange[0] / step) * step;\n while (current <= effectiveYRange[1]) {\n ticks.push(current);\n current += step;\n }\n return ticks;\n }, [effectiveYRange]);\n\n const xTicks = useMemo(\n () => [...new Set(dataSeries.flatMap((s) => s.x))],\n [dataSeries],\n );\n\n const mode = useMemo((): \"lines\" | \"lines+markers\" => {\n switch (variant) {\n case \"lines+markers\":\n case \"lines+markers+error_bars\":\n return \"lines+markers\";\n default:\n return \"lines\";\n }\n }, [variant]);\n\n const tickOptions = useMemo(\n () => ({\n tickcolor: theme.tickColor,\n ticklen: 12,\n tickwidth: 1,\n ticks: \"outside\" as const,\n tickfont: {\n size: 16,\n color: theme.textColor,\n family: \"Inter, sans-serif\",\n weight: 400,\n },\n linecolor: theme.lineColor,\n linewidth: 1,\n position: 0,\n zeroline: false,\n }),\n [theme],\n );\n\n useEffect(() => {\n if (!plotRef.current) return;\n\n const plotData = dataSeries.map((series) => ({\n x: series.x,\n y: series.y,\n type: \"scatter\" as const,\n mode: mode,\n name: series.name,\n line: {\n color: series.color,\n width: 1.5,\n },\n marker:\n variant === \"lines\"\n ? { opacity: 0 }\n : {\n color: series.color,\n size: 8,\n symbol: series.symbol || \"triangle-up\",\n },\n error_y:\n variant === \"lines+markers+error_bars\"\n ? series.error_y || {\n type: \"data\" as const,\n array: series.y.map(() => 10),\n visible: true,\n color: series.color,\n thickness: 1,\n width: 5,\n }\n : undefined,\n }));\n\n const layout = {\n title: {\n text: title,\n font: {\n size: 32,\n family: \"Inter, sans-serif\",\n color: theme.textColor,\n },\n },\n width,\n height,\n margin: { l: 80, r: 30, b: 80, t: 60, pad: 10 },\n paper_bgcolor: theme.paperBg,\n plot_bgcolor: theme.plotBg,\n font: {\n family: \"Inter, sans-serif\",\n },\n dragmode: false as const,\n xaxis: {\n title: {\n text: xTitle,\n font: {\n size: 16,\n color: theme.textSecondary,\n family: \"Inter, sans-serif\",\n weight: 400,\n },\n standoff: 32,\n },\n gridcolor: theme.gridColor,\n range: xRange,\n autorange: !xRange,\n tickmode: \"array\" as const,\n tickvals: xTicks,\n ticktext: xTicks.map(String),\n showgrid: true,\n ...tickOptions,\n },\n yaxis: {\n title: {\n text: yTitle,\n font: {\n size: 16,\n color: theme.textSecondary,\n family: \"Inter, sans-serif\",\n weight: 400,\n },\n standoff: 30,\n },\n gridcolor: theme.gridColor,\n range: yRange,\n autorange: !yRange,\n tickmode: \"array\" as const,\n tickvals: yTicks,\n showgrid: true,\n ...tickOptions,\n },\n legend: {\n x: 0.5,\n y: -0.2,\n xanchor: \"center\" as const,\n yanchor: \"top\" as const,\n orientation: \"h\" as const,\n font: {\n size: 16,\n color: theme.legendColor,\n family: \"Inter, sans-serif\",\n weight: 500,\n },\n },\n showlegend: true,\n };\n\n const config = {\n responsive: true,\n displayModeBar: false,\n displaylogo: false,\n };\n\n Plotly.newPlot(plotRef.current, plotData, layout, config);\n\n // Capture ref value for cleanup\n const plotElement = plotRef.current;\n\n return () => {\n if (plotElement) {\n Plotly.purge(plotElement);\n }\n };\n }, [dataSeries, width, height, xRange, yRange, xTitle, yTitle, title, mode, tickOptions, xTicks, yTicks, effectiveYRange, variant, theme]);\n\n return (\n <div className=\"chart-container\">\n <div ref={plotRef} style={{ width: \"100%\", height: \"100%\" }} />\n </div>\n );\n};\n\nexport { LineGraph };\nexport type { LineDataSeries, LineGraphVariant, LineGraphProps, MarkerSymbol };\n"],"names":["LineGraph","dataSeries","width","height","xRange","yRange","variant","xTitle","yTitle","title","plotRef","useRef","theme","usePlotlyTheme","yMin","yMax","useMemo","minX","maxX","minY","maxY","series","x","y","xPadding","yPadding","effectiveYRange","yTicks","range","step","ticks","current","xTicks","s","mode","tickOptions","useEffect","plotData","layout","config","Plotly","plotElement","jsx"],"mappings":"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"}
1
+ {"version":3,"file":"LineGraph.cjs","sources":["../../../../src/components/charts/LineGraph/LineGraph.tsx"],"sourcesContent":["import Plotly from \"plotly.js-dist\";\nimport React, { useEffect, useRef, useMemo } from \"react\";\n\nimport { useChartTooltip } from \"../ChartTooltip\";\n\nimport { useElementSize } from \"@/hooks/use-element-size\";\nimport { usePlotlyTheme } from \"@/hooks/use-plotly-theme\";\nimport { cn } from \"@/lib/utils\";\nimport { seriesColor } from \"@/utils/colors\";\n\ntype MarkerSymbol =\n | \"circle\"\n | \"circle-open\"\n | \"circle-dot\"\n | \"circle-open-dot\"\n | \"square\"\n | \"square-open\"\n | \"square-dot\"\n | \"square-open-dot\"\n | \"diamond\"\n | \"diamond-open\"\n | \"diamond-dot\"\n | \"diamond-open-dot\"\n | \"cross\"\n | \"cross-open\"\n | \"cross-dot\"\n | \"cross-open-dot\"\n | \"x\"\n | \"x-open\"\n | \"x-dot\"\n | \"x-open-dot\"\n | \"triangle-up\"\n | \"triangle-up-open\"\n | \"triangle-up-dot\"\n | \"triangle-up-open-dot\"\n | \"triangle-down\"\n | \"triangle-down-open\"\n | \"triangle-down-dot\"\n | \"triangle-down-open-dot\"\n | \"triangle-left\"\n | \"triangle-left-open\"\n | \"triangle-left-dot\"\n | \"triangle-left-open-dot\"\n | \"triangle-right\"\n | \"triangle-right-open\"\n | \"triangle-right-dot\"\n | \"triangle-right-open-dot\"\n | \"triangle-ne\"\n | \"triangle-ne-open\"\n | \"triangle-ne-dot\"\n | \"triangle-ne-open-dot\"\n | \"triangle-se\"\n | \"triangle-se-open\"\n | \"triangle-se-dot\"\n | \"triangle-se-open-dot\"\n | \"triangle-sw\"\n | \"triangle-sw-open\"\n | \"triangle-sw-dot\"\n | \"triangle-sw-open-dot\"\n | \"triangle-nw\"\n | \"triangle-nw-open\"\n | \"triangle-nw-dot\"\n | \"triangle-nw-open-dot\"\n | \"pentagon\"\n | \"pentagon-open\"\n | \"pentagon-dot\"\n | \"pentagon-open-dot\"\n | \"hexagon\"\n | \"hexagon-open\"\n | \"hexagon-dot\"\n | \"hexagon-open-dot\"\n | \"hexagon2\"\n | \"hexagon2-open\"\n | \"hexagon2-dot\"\n | \"hexagon2-open-dot\"\n | \"octagon\"\n | \"octagon-open\"\n | \"octagon-dot\"\n | \"octagon-open-dot\"\n | \"star\"\n | \"star-open\"\n | \"star-dot\"\n | \"star-open-dot\"\n | \"hexagram\"\n | \"hexagram-open\"\n | \"hexagram-dot\"\n | \"hexagram-open-dot\"\n | \"star-triangle-up\"\n | \"star-triangle-up-open\"\n | \"star-triangle-up-dot\"\n | \"star-triangle-up-open-dot\"\n | \"star-triangle-down\"\n | \"star-triangle-down-open\"\n | \"star-triangle-down-dot\"\n | \"star-triangle-down-open-dot\"\n | \"star-square\"\n | \"star-square-open\"\n | \"star-square-dot\"\n | \"star-square-open-dot\"\n | \"star-diamond\"\n | \"star-diamond-open\"\n | \"star-diamond-dot\"\n | \"star-diamond-open-dot\"\n | \"diamond-tall\"\n | \"diamond-tall-open\"\n | \"diamond-tall-dot\"\n | \"diamond-tall-open-dot\"\n | \"diamond-wide\"\n | \"diamond-wide-open\"\n | \"diamond-wide-dot\"\n | \"diamond-wide-open-dot\"\n | \"hourglass\"\n | \"hourglass-open\"\n | \"bowtie\"\n | \"bowtie-open\"\n | \"circle-cross\"\n | \"circle-cross-open\"\n | \"circle-x\"\n | \"circle-x-open\"\n | \"square-cross\"\n | \"square-cross-open\"\n | \"square-x\"\n | \"square-x-open\"\n | \"diamond-cross\"\n | \"diamond-cross-open\"\n | \"diamond-x\"\n | \"diamond-x-open\"\n | \"cross-thin\"\n | \"cross-thin-open\"\n | \"x-thin\"\n | \"x-thin-open\"\n | \"asterisk\"\n | \"asterisk-open\"\n | \"hash\"\n | \"hash-open\"\n | \"hash-dot\"\n | \"hash-open-dot\"\n | \"y-up\"\n | \"y-up-open\"\n | \"y-down\"\n | \"y-down-open\"\n | \"y-left\"\n | \"y-left-open\"\n | \"y-right\"\n | \"y-right-open\"\n | \"line-ew\"\n | \"line-ew-open\"\n | \"line-ns\"\n | \"line-ns-open\"\n | \"line-ne\"\n | \"line-ne-open\"\n | \"line-nw\"\n | \"line-nw-open\"\n | \"arrow\"\n | \"arrow-open\"\n | \"arrow-wide\"\n | \"arrow-wide-open\";\n\ninterface LineDataSeries {\n x: number[];\n y: number[];\n name: string;\n /** Optional color override (auto-assigned from CHART_COLORS if not provided) */\n color?: string;\n symbol?: MarkerSymbol;\n error_y?: {\n type: \"data\";\n array: number[];\n visible: boolean;\n };\n}\n\ntype LineGraphVariant = \"lines\" | \"lines+markers\" | \"lines+markers+error_bars\";\n\n/** Top margin reserving room for the 32px title; reduced when no title is set */\nconst TITLE_MARGIN_TOP = 60;\nconst NO_TITLE_MARGIN_TOP = 30;\n\ntype LineGraphProps = {\n dataSeries: LineDataSeries[];\n /**\n * Fixed width in pixels. When omitted, the chart fills its container and\n * tracks the container's width via a `ResizeObserver`.\n */\n width?: number;\n /**\n * Fixed height in pixels. When omitted, the chart fills its container and\n * tracks the container's height via a `ResizeObserver`.\n */\n height?: number;\n xRange?: [number, number];\n yRange?: [number, number];\n variant?: LineGraphVariant;\n xTitle?: string;\n yTitle?: string;\n title?: string;\n /**\n * Categorical labels for the x-axis ticks. When provided, the x data values\n * still drive line positioning but the displayed tick labels match these\n * strings in order (e.g. [\"Mon\", \"Tue\", …]). Should align 1:1 with the\n * unique, ordered x values across all series.\n */\n xTickText?: string[];\n};\n\nconst LineGraph: React.FC<LineGraphProps> = ({\n dataSeries,\n width,\n height,\n xRange,\n yRange,\n variant = \"lines\",\n xTitle,\n yTitle,\n title,\n xTickText,\n}) => {\n const plotRef = useRef<HTMLDivElement>(null);\n const theme = usePlotlyTheme();\n const { bindTooltip, tooltipElement } = useChartTooltip({ xLabel: xTitle, yLabel: yTitle });\n\n // Omitted width/height → fill the container and track its measured size;\n // explicit pixel values override. See AreaGraph for the reference pattern.\n const [containerRef, measured] = useElementSize<HTMLDivElement>();\n const resolvedWidth = width ?? measured.width;\n const resolvedHeight = height ?? measured.height;\n const hasSize = resolvedWidth > 0 && resolvedHeight > 0;\n // Fill is per-dimension: omit width to fill the container width, omit height\n // to fill its height (so e.g. a fixed width with a container-driven height works).\n const fillWidth = width === undefined;\n const fillHeight = height === undefined;\n const sizeRef = useRef({ width: resolvedWidth, height: resolvedHeight });\n sizeRef.current = { width: resolvedWidth, height: resolvedHeight };\n const plotInitedRef = useRef(false);\n // Size last applied to the plot, so the resize effect can skip a redundant\n // relayout right after newPlot already drew at that size.\n const appliedSizeRef = useRef({ width: 0, height: 0 });\n\n const { yMin, yMax } = useMemo(() => {\n let minX = Number.MAX_VALUE;\n let maxX = Number.MIN_VALUE;\n let minY = Number.MAX_VALUE;\n let maxY = Number.MIN_VALUE;\n\n dataSeries.forEach((series) => {\n series.x.forEach((x) => {\n minX = Math.min(minX, x);\n maxX = Math.max(maxX, x);\n });\n series.y.forEach((y) => {\n minY = Math.min(minY, y);\n maxY = Math.max(maxY, y);\n });\n });\n\n const xPadding = (maxX - minX) * 0.1;\n const yPadding = (maxY - minY) * 0.1;\n\n return {\n xMin: minX - xPadding,\n xMax: maxX + xPadding,\n yMin: minY - yPadding,\n yMax: maxY + yPadding,\n };\n }, [dataSeries]);\n\n const effectiveYRange = useMemo(\n () => yRange || [yMin, yMax],\n [yRange, yMin, yMax],\n );\n\n const yTicks = useMemo(() => {\n const range = effectiveYRange[1] - effectiveYRange[0];\n let step = Math.pow(10, Math.floor(Math.log10(range)));\n\n if (range / step > 10) step = step * 2;\n if (range / step < 4) step = step / 2;\n\n const ticks = [];\n let current = Math.ceil(effectiveYRange[0] / step) * step;\n while (current <= effectiveYRange[1]) {\n ticks.push(current);\n current += step;\n }\n return ticks;\n }, [effectiveYRange]);\n\n const xTicks = useMemo(\n () => [...new Set(dataSeries.flatMap((s) => s.x))].sort((a, b) => a - b),\n [dataSeries],\n );\n\n // Only apply categorical labels when they align 1:1 with the tick positions;\n // a mismatch would silently mis-label ticks, so fall back to numeric ticks.\n const useCategoricalX = !!xTickText && xTickText.length === xTicks.length;\n\n const mode = useMemo((): \"lines\" | \"lines+markers\" => {\n switch (variant) {\n case \"lines+markers\":\n case \"lines+markers+error_bars\":\n return \"lines+markers\";\n default:\n return \"lines\";\n }\n }, [variant]);\n\n const tickOptions = useMemo(\n () => ({\n tickcolor: theme.tickColor,\n ticklen: 12,\n tickwidth: 1,\n ticks: \"outside\" as const,\n tickfont: {\n size: 16,\n color: theme.textColor,\n family: \"Inter, sans-serif\",\n weight: 400,\n },\n linecolor: theme.lineColor,\n linewidth: 1,\n position: 0,\n zeroline: false,\n }),\n [theme],\n );\n\n useEffect(() => {\n if (!plotRef.current || !hasSize) return;\n\n const plotData = dataSeries.map((series, index) => {\n const color = seriesColor(index, series.color);\n return {\n x: series.x,\n y: series.y,\n type: \"scatter\" as const,\n mode: mode,\n name: series.name,\n hoverinfo: \"none\" as const,\n line: {\n color,\n width: 1.5,\n },\n marker:\n variant === \"lines\"\n ? { opacity: 0 }\n : {\n color,\n size: 8,\n symbol: series.symbol || \"triangle-up\",\n },\n error_y:\n variant === \"lines+markers+error_bars\"\n ? series.error_y || {\n type: \"data\" as const,\n array: series.y.map(() => 10),\n visible: true,\n color,\n thickness: 1,\n width: 5,\n }\n : undefined,\n };\n });\n\n const layout = {\n ...(title\n ? {\n title: {\n text: title,\n font: {\n size: 32,\n family: \"Inter, sans-serif\",\n color: theme.textColor,\n },\n },\n }\n : {}),\n width: sizeRef.current.width,\n height: sizeRef.current.height,\n margin: {\n l: 80,\n r: 30,\n // Reserve room for tick labels, the x-axis title, and the\n // container-anchored bottom legend stacked beneath them.\n b: 96,\n t: title ? TITLE_MARGIN_TOP : NO_TITLE_MARGIN_TOP,\n pad: 10,\n },\n paper_bgcolor: theme.paperBg,\n plot_bgcolor: theme.plotBg,\n font: {\n family: \"Inter, sans-serif\",\n },\n dragmode: false as const,\n xaxis: {\n title: {\n text: xTitle,\n font: {\n size: 16,\n color: theme.textSecondary,\n family: \"Inter, sans-serif\",\n weight: 400,\n },\n standoff: 32,\n },\n gridcolor: theme.gridColor,\n range: xRange,\n autorange: !xRange,\n tickmode: \"array\" as const,\n tickvals: xTicks,\n ticktext: useCategoricalX ? xTickText : xTicks.map(String),\n showgrid: true,\n // Reserve space for tick labels + the axis title so the bottom legend\n // can't overlap them at small sizes (SW-2157).\n automargin: true,\n ...tickOptions,\n },\n yaxis: {\n title: {\n text: yTitle,\n font: {\n size: 16,\n color: theme.textSecondary,\n family: \"Inter, sans-serif\",\n weight: 400,\n },\n standoff: 30,\n },\n gridcolor: theme.gridColor,\n range: yRange,\n autorange: !yRange,\n tickmode: \"array\" as const,\n tickvals: yTicks,\n showgrid: true,\n automargin: true,\n ...tickOptions,\n },\n legend: {\n // Anchor to the bottom of the container (not the plot area) so the\n // legend always clears the x-axis tick labels + title — a paper-relative\n // fractional offset collapses into the ticks at small heights (SW-2157).\n x: 0.5,\n y: 0,\n xanchor: \"center\" as const,\n yanchor: \"bottom\" as const,\n yref: \"container\" as const,\n orientation: \"h\" as const,\n font: {\n size: 16,\n color: theme.legendColor,\n family: \"Inter, sans-serif\",\n weight: 500,\n },\n },\n showlegend: true,\n };\n\n const config = {\n // Sizing is driven from the measured container; disable Plotly's own\n // window-resize responsiveness (it can't see container resizes).\n responsive: false,\n displayModeBar: false,\n displaylogo: false,\n };\n\n Plotly.newPlot(plotRef.current, plotData, layout, config);\n bindTooltip(plotRef.current);\n\n // Capture ref value for cleanup\n const plotElement = plotRef.current;\n plotInitedRef.current = true;\n appliedSizeRef.current = { ...sizeRef.current };\n\n return () => {\n if (plotElement) {\n Plotly.purge(plotElement);\n plotInitedRef.current = false;\n }\n };\n }, [dataSeries, hasSize, xRange, yRange, xTitle, yTitle, title, mode, tickOptions, xTicks, yTicks, useCategoricalX, xTickText, effectiveYRange, variant, theme, bindTooltip]);\n\n // Resize in place when the measured/overridden size changes — cheaper than\n // recreating the plot, and it preserves tooltip/event bindings.\n useEffect(() => {\n const plotElement = plotRef.current;\n if (!plotElement || !plotInitedRef.current || resolvedWidth <= 0 || resolvedHeight <= 0) {\n return;\n }\n // newPlot already drew at the current size; skip the redundant relayout\n // (it would queue an automargin redraw that can reject if we unmount first).\n if (\n appliedSizeRef.current.width === resolvedWidth &&\n appliedSizeRef.current.height === resolvedHeight\n ) {\n return;\n }\n appliedSizeRef.current = { width: resolvedWidth, height: resolvedHeight };\n // Swallow rejections from a relayout that races an unmount/purge.\n void Plotly.relayout(plotElement, { width: resolvedWidth, height: resolvedHeight }).catch(\n () => {},\n );\n }, [resolvedWidth, resolvedHeight]);\n\n return (\n <div ref={containerRef} className={cn(\"relative\", fillWidth && \"w-full\", fillHeight && \"h-full\")}>\n <div ref={plotRef} style={{ width: \"100%\", height: \"100%\" }} />\n {tooltipElement}\n </div>\n );\n};\n\nexport { LineGraph };\nexport type { LineDataSeries, LineGraphVariant, LineGraphProps, MarkerSymbol };\n"],"names":["TITLE_MARGIN_TOP","NO_TITLE_MARGIN_TOP","LineGraph","dataSeries","width","height","xRange","yRange","variant","xTitle","yTitle","title","xTickText","plotRef","useRef","theme","usePlotlyTheme","bindTooltip","tooltipElement","useChartTooltip","containerRef","measured","useElementSize","resolvedWidth","resolvedHeight","hasSize","fillWidth","fillHeight","sizeRef","plotInitedRef","appliedSizeRef","yMin","yMax","useMemo","minX","maxX","minY","maxY","series","x","y","xPadding","yPadding","effectiveYRange","yTicks","range","step","ticks","current","xTicks","s","a","b","useCategoricalX","mode","tickOptions","useEffect","plotData","index","color","seriesColor","layout","config","Plotly","plotElement","jsxs","cn","jsx"],"mappings":"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"}