@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.
- package/README.md +55 -0
- package/dist/components/ai/chain-of-thought.cjs +1 -1
- package/dist/components/ai/chain-of-thought.cjs.map +1 -1
- package/dist/components/ai/chain-of-thought.js +5 -5
- package/dist/components/ai/chain-of-thought.js.map +1 -1
- package/dist/components/ai/conversation.cjs +2 -2
- package/dist/components/ai/conversation.cjs.map +1 -1
- package/dist/components/ai/conversation.js +2 -2
- package/dist/components/ai/conversation.js.map +1 -1
- package/dist/components/ai/queue.cjs +1 -1
- package/dist/components/ai/queue.cjs.map +1 -1
- package/dist/components/ai/queue.js +9 -9
- package/dist/components/ai/queue.js.map +1 -1
- package/dist/components/charts/AreaGraph/AreaGraph.cjs +1 -1
- package/dist/components/charts/AreaGraph/AreaGraph.cjs.map +1 -1
- package/dist/components/charts/AreaGraph/AreaGraph.js +165 -103
- package/dist/components/charts/AreaGraph/AreaGraph.js.map +1 -1
- package/dist/components/charts/BarGraph/BarGraph.cjs +1 -1
- package/dist/components/charts/BarGraph/BarGraph.cjs.map +1 -1
- package/dist/components/charts/BarGraph/BarGraph.js +135 -90
- package/dist/components/charts/BarGraph/BarGraph.js.map +1 -1
- package/dist/components/charts/Boxplot/Boxplot.cjs +1 -1
- package/dist/components/charts/Boxplot/Boxplot.cjs.map +1 -1
- package/dist/components/charts/Boxplot/Boxplot.js +130 -92
- package/dist/components/charts/Boxplot/Boxplot.js.map +1 -1
- package/dist/components/charts/ChartTooltip/ChartTooltip.cjs +2 -0
- package/dist/components/charts/ChartTooltip/ChartTooltip.cjs.map +1 -0
- package/dist/components/charts/ChartTooltip/ChartTooltip.js +163 -0
- package/dist/components/charts/ChartTooltip/ChartTooltip.js.map +1 -0
- package/dist/components/charts/ChartTooltip/lines.cjs +2 -0
- package/dist/components/charts/ChartTooltip/lines.cjs.map +1 -0
- package/dist/components/charts/ChartTooltip/lines.js +29 -0
- package/dist/components/charts/ChartTooltip/lines.js.map +1 -0
- package/dist/components/charts/Chromatogram/Chromatogram.cjs +1 -1
- package/dist/components/charts/Chromatogram/Chromatogram.cjs.map +1 -1
- package/dist/components/charts/Chromatogram/Chromatogram.js +75 -61
- package/dist/components/charts/Chromatogram/Chromatogram.js.map +1 -1
- package/dist/components/charts/ChromatogramChart/ChromatogramChart.cjs +1 -1
- package/dist/components/charts/ChromatogramChart/ChromatogramChart.cjs.map +1 -1
- package/dist/components/charts/ChromatogramChart/ChromatogramChart.js +116 -108
- package/dist/components/charts/ChromatogramChart/ChromatogramChart.js.map +1 -1
- package/dist/components/charts/ChromatogramChart/annotations.cjs +1 -1
- package/dist/components/charts/ChromatogramChart/annotations.cjs.map +1 -1
- package/dist/components/charts/ChromatogramChart/annotations.js +32 -32
- package/dist/components/charts/ChromatogramChart/annotations.js.map +1 -1
- package/dist/components/charts/ChromatogramChart/boundaryMarkers.cjs +1 -1
- package/dist/components/charts/ChromatogramChart/boundaryMarkers.cjs.map +1 -1
- package/dist/components/charts/ChromatogramChart/boundaryMarkers.js +6 -6
- package/dist/components/charts/ChromatogramChart/boundaryMarkers.js.map +1 -1
- package/dist/components/charts/ChromatogramChart/constants.cjs +1 -1
- package/dist/components/charts/ChromatogramChart/constants.cjs.map +1 -1
- package/dist/components/charts/ChromatogramChart/constants.js +11 -5
- package/dist/components/charts/ChromatogramChart/constants.js.map +1 -1
- package/dist/components/charts/ChromatogramChart/dataProcessing.cjs +1 -1
- package/dist/components/charts/ChromatogramChart/dataProcessing.cjs.map +1 -1
- package/dist/components/charts/ChromatogramChart/dataProcessing.js +38 -49
- package/dist/components/charts/ChromatogramChart/dataProcessing.js.map +1 -1
- package/dist/components/charts/DotPlot/DotPlot.cjs +1 -1
- package/dist/components/charts/DotPlot/DotPlot.cjs.map +1 -1
- package/dist/components/charts/DotPlot/DotPlot.js +112 -88
- package/dist/components/charts/DotPlot/DotPlot.js.map +1 -1
- package/dist/components/charts/Histogram/Histogram.cjs +1 -1
- package/dist/components/charts/Histogram/Histogram.cjs.map +1 -1
- package/dist/components/charts/Histogram/Histogram.js +132 -115
- package/dist/components/charts/Histogram/Histogram.js.map +1 -1
- package/dist/components/charts/LineGraph/LineGraph.cjs +1 -1
- package/dist/components/charts/LineGraph/LineGraph.cjs.map +1 -1
- package/dist/components/charts/LineGraph/LineGraph.js +151 -111
- package/dist/components/charts/LineGraph/LineGraph.js.map +1 -1
- package/dist/components/charts/PieChart/PieChart.cjs +1 -1
- package/dist/components/charts/PieChart/PieChart.cjs.map +1 -1
- package/dist/components/charts/PieChart/PieChart.js +81 -70
- package/dist/components/charts/PieChart/PieChart.js.map +1 -1
- package/dist/components/charts/PlateMap/PlateMap.cjs +1 -1
- package/dist/components/charts/PlateMap/PlateMap.cjs.map +1 -1
- package/dist/components/charts/PlateMap/PlateMap.js +271 -256
- package/dist/components/charts/PlateMap/PlateMap.js.map +1 -1
- package/dist/components/charts/PlateMap/constants.cjs +1 -1
- package/dist/components/charts/PlateMap/constants.cjs.map +1 -1
- package/dist/components/charts/PlateMap/constants.js +20 -29
- package/dist/components/charts/PlateMap/constants.js.map +1 -1
- package/dist/components/charts/ScatterGraph/ScatterGraph.cjs +1 -1
- package/dist/components/charts/ScatterGraph/ScatterGraph.cjs.map +1 -1
- package/dist/components/charts/ScatterGraph/ScatterGraph.js +154 -106
- package/dist/components/charts/ScatterGraph/ScatterGraph.js.map +1 -1
- package/dist/components/composed/DataAppShell/DataAppShell.cjs +1 -1
- package/dist/components/composed/DataAppShell/DataAppShell.cjs.map +1 -1
- package/dist/components/composed/DataAppShell/DataAppShell.js +118 -111
- package/dist/components/composed/DataAppShell/DataAppShell.js.map +1 -1
- package/dist/components/composed/PlateMapEditor/PlateMapGrid.cjs +1 -1
- package/dist/components/composed/PlateMapEditor/PlateMapGrid.cjs.map +1 -1
- package/dist/components/composed/PlateMapEditor/PlateMapGrid.js +1 -1
- package/dist/components/composed/PlateMapEditor/PlateMapGrid.js.map +1 -1
- package/dist/components/composed/PlateMapEditor/WellLegend.cjs +1 -1
- package/dist/components/composed/PlateMapEditor/WellLegend.cjs.map +1 -1
- package/dist/components/composed/PlateMapEditor/WellLegend.js +8 -8
- package/dist/components/composed/PlateMapEditor/WellLegend.js.map +1 -1
- package/dist/components/composed/RichListItem/RichListItem.cjs +1 -1
- package/dist/components/composed/RichListItem/RichListItem.cjs.map +1 -1
- package/dist/components/composed/RichListItem/RichListItem.js +16 -16
- package/dist/components/composed/RichListItem/RichListItem.js.map +1 -1
- package/dist/components/ui/accordion.cjs +1 -1
- package/dist/components/ui/accordion.cjs.map +1 -1
- package/dist/components/ui/accordion.js +1 -1
- package/dist/components/ui/accordion.js.map +1 -1
- package/dist/components/ui/badge.cjs +1 -1
- package/dist/components/ui/badge.cjs.map +1 -1
- package/dist/components/ui/badge.js +8 -8
- package/dist/components/ui/badge.js.map +1 -1
- package/dist/components/ui/button.cjs +1 -1
- package/dist/components/ui/button.cjs.map +1 -1
- package/dist/components/ui/button.js +11 -11
- package/dist/components/ui/button.js.map +1 -1
- package/dist/components/ui/combobox.cjs +1 -1
- package/dist/components/ui/combobox.cjs.map +1 -1
- package/dist/components/ui/combobox.js +12 -12
- package/dist/components/ui/combobox.js.map +1 -1
- package/dist/components/ui/input-group.cjs +1 -1
- package/dist/components/ui/input-group.cjs.map +1 -1
- package/dist/components/ui/input-group.js +19 -19
- package/dist/components/ui/input-group.js.map +1 -1
- package/dist/components/ui/item.cjs +1 -1
- package/dist/components/ui/item.cjs.map +1 -1
- package/dist/components/ui/item.js +1 -1
- package/dist/components/ui/item.js.map +1 -1
- package/dist/components/ui/menubar.cjs +1 -1
- package/dist/components/ui/menubar.cjs.map +1 -1
- package/dist/components/ui/menubar.js +1 -1
- package/dist/components/ui/menubar.js.map +1 -1
- package/dist/components/ui/navigation-menu.cjs +1 -1
- package/dist/components/ui/navigation-menu.cjs.map +1 -1
- package/dist/components/ui/navigation-menu.js +54 -54
- package/dist/components/ui/navigation-menu.js.map +1 -1
- package/dist/components/ui/resizable.cjs +1 -1
- package/dist/components/ui/resizable.cjs.map +1 -1
- package/dist/components/ui/resizable.js +27 -15
- package/dist/components/ui/resizable.js.map +1 -1
- package/dist/components/ui/select.cjs +1 -1
- package/dist/components/ui/select.cjs.map +1 -1
- package/dist/components/ui/select.js +1 -1
- package/dist/components/ui/select.js.map +1 -1
- package/dist/components/ui/slider.cjs +1 -1
- package/dist/components/ui/slider.cjs.map +1 -1
- package/dist/components/ui/slider.js +9 -9
- package/dist/components/ui/slider.js.map +1 -1
- package/dist/components/ui/table.cjs +1 -1
- package/dist/components/ui/table.cjs.map +1 -1
- package/dist/components/ui/table.js +13 -13
- package/dist/components/ui/table.js.map +1 -1
- package/dist/components/ui/tabs.cjs +1 -1
- package/dist/components/ui/tabs.cjs.map +1 -1
- package/dist/components/ui/tabs.js +7 -7
- package/dist/components/ui/tabs.js.map +1 -1
- package/dist/components/ui/toggle.cjs +1 -1
- package/dist/components/ui/toggle.cjs.map +1 -1
- package/dist/components/ui/toggle.js +12 -12
- package/dist/components/ui/toggle.js.map +1 -1
- package/dist/hooks/use-element-size.cjs +2 -0
- package/dist/hooks/use-element-size.cjs.map +1 -0
- package/dist/hooks/use-element-size.js +21 -0
- package/dist/hooks/use-element-size.js.map +1 -0
- package/dist/hooks/use-plotly-theme.cjs +1 -1
- package/dist/hooks/use-plotly-theme.cjs.map +1 -1
- package/dist/hooks/use-plotly-theme.js +4 -2
- package/dist/hooks/use-plotly-theme.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.css +1 -1
- package/dist/index.d.ts +254 -77
- package/dist/index.js +587 -581
- package/dist/index.js.map +1 -1
- package/dist/index.tailwind.css +1 -1
- package/dist/utils/colors.cjs +1 -1
- package/dist/utils/colors.cjs.map +1 -1
- package/dist/utils/colors.js +38 -93
- package/dist/utils/colors.js.map +1 -1
- package/package.json +18 -12
|
@@ -1,186 +1,234 @@
|
|
|
1
|
-
import { jsx as
|
|
2
|
-
import
|
|
3
|
-
import { useRef as
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
1
|
+
import { jsxs as G, jsx as O } from "react/jsx-runtime";
|
|
2
|
+
import g from "plotly.js-dist";
|
|
3
|
+
import { useRef as k, useMemo as m, useEffect as Y } from "react";
|
|
4
|
+
import { useChartTooltip as T } from "../ChartTooltip/ChartTooltip.js";
|
|
5
|
+
import { useElementSize as q } from "../../../hooks/use-element-size.js";
|
|
6
|
+
import { usePlotlyTheme as F } from "../../../hooks/use-plotly-theme.js";
|
|
7
|
+
import { cn as J } from "../../../lib/utils.js";
|
|
8
|
+
import { seriesColor as K } from "../../../utils/colors.js";
|
|
9
|
+
const it = ({
|
|
10
|
+
dataSeries: x,
|
|
11
|
+
width: I,
|
|
12
|
+
height: _,
|
|
13
|
+
xRange: u,
|
|
14
|
+
yRange: p,
|
|
15
|
+
xTitle: v,
|
|
16
|
+
yTitle: b,
|
|
17
|
+
title: L = "Scatter Plot"
|
|
14
18
|
}) => {
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
const a = k(null), r = F(), { bindTooltip: N, tooltipElement: j } = T({ xLabel: v, yLabel: b }), [H, A] = q(), s = I ?? A.width, c = _ ?? A.height, P = s > 0 && c > 0, W = I === void 0, D = _ === void 0, w = k({ width: s, height: c });
|
|
20
|
+
w.current = { width: s, height: c };
|
|
21
|
+
const E = k(!1), M = k({ width: 0, height: 0 }), { xMin: S, xMax: X, yMin: U, yMax: V } = m(() => {
|
|
22
|
+
let o = Number.MAX_VALUE, t = Number.MIN_VALUE, n = Number.MAX_VALUE, e = Number.MIN_VALUE;
|
|
23
|
+
x.forEach((l) => {
|
|
24
|
+
l.x.forEach((i) => {
|
|
25
|
+
o = Math.min(o, i), t = Math.max(t, i);
|
|
26
|
+
}), l.y.forEach((i) => {
|
|
27
|
+
n = Math.min(n, i), e = Math.max(e, i);
|
|
22
28
|
});
|
|
23
29
|
});
|
|
24
|
-
const
|
|
30
|
+
const d = (t - o) * 0.1, y = (e - n) * 0.1;
|
|
25
31
|
return {
|
|
26
|
-
xMin:
|
|
27
|
-
xMax: t +
|
|
28
|
-
yMin:
|
|
29
|
-
yMax: e +
|
|
32
|
+
xMin: o - d,
|
|
33
|
+
xMax: t + d,
|
|
34
|
+
yMin: n - y,
|
|
35
|
+
yMax: e + y
|
|
30
36
|
};
|
|
31
|
-
}, [
|
|
32
|
-
() =>
|
|
33
|
-
[
|
|
34
|
-
),
|
|
35
|
-
() =>
|
|
36
|
-
[
|
|
37
|
-
),
|
|
38
|
-
const
|
|
39
|
-
let t = Math.pow(10, Math.floor(Math.log10(
|
|
40
|
-
|
|
41
|
-
const
|
|
42
|
-
let e = Math.ceil(
|
|
43
|
-
for (; e <=
|
|
44
|
-
|
|
45
|
-
return
|
|
46
|
-
}, [
|
|
47
|
-
const
|
|
48
|
-
let t = Math.pow(10, Math.floor(Math.log10(
|
|
49
|
-
|
|
50
|
-
const
|
|
51
|
-
let e = Math.ceil(
|
|
52
|
-
for (; e <=
|
|
53
|
-
|
|
54
|
-
return
|
|
55
|
-
}, [
|
|
37
|
+
}, [x]), h = m(
|
|
38
|
+
() => u || [S, X],
|
|
39
|
+
[u, S, X]
|
|
40
|
+
), f = m(
|
|
41
|
+
() => p || [U, V],
|
|
42
|
+
[p, U, V]
|
|
43
|
+
), z = m(() => {
|
|
44
|
+
const o = h[1] - h[0];
|
|
45
|
+
let t = Math.pow(10, Math.floor(Math.log10(o)));
|
|
46
|
+
o / t > 10 && (t = t * 2), o / t < 4 && (t = t / 2);
|
|
47
|
+
const n = [];
|
|
48
|
+
let e = Math.ceil(h[0] / t) * t;
|
|
49
|
+
for (; e <= h[1]; )
|
|
50
|
+
n.push(e), e += t;
|
|
51
|
+
return n;
|
|
52
|
+
}, [h]), B = m(() => {
|
|
53
|
+
const o = f[1] - f[0];
|
|
54
|
+
let t = Math.pow(10, Math.floor(Math.log10(o)));
|
|
55
|
+
o / t > 10 && (t = t * 2), o / t < 4 && (t = t / 2);
|
|
56
|
+
const n = [];
|
|
57
|
+
let e = Math.ceil(f[0] / t) * t;
|
|
58
|
+
for (; e <= f[1]; )
|
|
59
|
+
n.push(e), e += t;
|
|
60
|
+
return n;
|
|
61
|
+
}, [f]), C = m(
|
|
56
62
|
() => ({
|
|
57
|
-
tickcolor:
|
|
63
|
+
tickcolor: r.tickColor,
|
|
58
64
|
ticklen: 12,
|
|
59
65
|
tickwidth: 1,
|
|
60
66
|
ticks: "outside",
|
|
61
67
|
tickfont: {
|
|
62
68
|
size: 16,
|
|
63
|
-
color:
|
|
69
|
+
color: r.textColor,
|
|
64
70
|
family: "Inter, sans-serif",
|
|
65
71
|
weight: 400
|
|
66
72
|
},
|
|
67
|
-
linecolor:
|
|
73
|
+
linecolor: r.lineColor,
|
|
68
74
|
linewidth: 1,
|
|
69
75
|
position: 0,
|
|
70
76
|
zeroline: !1
|
|
71
77
|
}),
|
|
72
|
-
[
|
|
73
|
-
), k = s(
|
|
74
|
-
() => ({
|
|
75
|
-
showspikes: !0,
|
|
76
|
-
spikemode: "across",
|
|
77
|
-
spikedash: "solid",
|
|
78
|
-
spikecolor: o.spikeColor,
|
|
79
|
-
spikethickness: 2
|
|
80
|
-
}),
|
|
81
|
-
[o]
|
|
78
|
+
[r]
|
|
82
79
|
);
|
|
83
|
-
return
|
|
84
|
-
if (!
|
|
85
|
-
const
|
|
86
|
-
x:
|
|
87
|
-
y:
|
|
80
|
+
return Y(() => {
|
|
81
|
+
if (!a.current || !P) return;
|
|
82
|
+
const o = x.map((l, i) => ({
|
|
83
|
+
x: l.x,
|
|
84
|
+
y: l.y,
|
|
88
85
|
type: "scatter",
|
|
89
86
|
mode: "markers",
|
|
90
|
-
name:
|
|
87
|
+
name: l.name,
|
|
91
88
|
marker: {
|
|
92
|
-
color:
|
|
89
|
+
color: K(i, l.color),
|
|
93
90
|
size: 10,
|
|
94
91
|
symbol: "circle"
|
|
95
92
|
},
|
|
96
|
-
|
|
93
|
+
hoverinfo: "none"
|
|
97
94
|
})), t = {
|
|
98
95
|
title: {
|
|
99
|
-
text:
|
|
96
|
+
text: L,
|
|
100
97
|
font: {
|
|
101
98
|
size: 32,
|
|
102
99
|
family: "Inter, sans-serif",
|
|
103
|
-
color:
|
|
100
|
+
color: r.textColor
|
|
104
101
|
}
|
|
105
102
|
},
|
|
106
|
-
width:
|
|
107
|
-
height:
|
|
108
|
-
margin
|
|
109
|
-
|
|
110
|
-
|
|
103
|
+
width: w.current.width,
|
|
104
|
+
height: w.current.height,
|
|
105
|
+
// Bottom margin reserves room for tick labels, the x-axis title, and the
|
|
106
|
+
// container-anchored bottom legend stacked beneath them.
|
|
107
|
+
margin: { l: 80, r: 30, b: 96, t: 60, pad: 10 },
|
|
108
|
+
paper_bgcolor: r.paperBg,
|
|
109
|
+
plot_bgcolor: r.plotBg,
|
|
111
110
|
font: {
|
|
112
111
|
family: "Inter, sans-serif"
|
|
113
112
|
},
|
|
114
113
|
dragmode: !1,
|
|
115
114
|
xaxis: {
|
|
116
115
|
title: {
|
|
117
|
-
text:
|
|
116
|
+
text: v,
|
|
118
117
|
font: {
|
|
119
118
|
size: 16,
|
|
120
|
-
color:
|
|
119
|
+
color: r.textSecondary,
|
|
121
120
|
family: "Inter, sans-serif",
|
|
122
121
|
weight: 400
|
|
123
122
|
},
|
|
124
123
|
standoff: 32
|
|
125
124
|
},
|
|
126
|
-
gridcolor:
|
|
127
|
-
range:
|
|
128
|
-
autorange: !
|
|
125
|
+
gridcolor: r.gridColor,
|
|
126
|
+
range: u,
|
|
127
|
+
autorange: !u,
|
|
129
128
|
tickmode: "array",
|
|
130
|
-
tickvals:
|
|
131
|
-
ticktext:
|
|
129
|
+
tickvals: z,
|
|
130
|
+
ticktext: z.map(String),
|
|
132
131
|
showgrid: !0,
|
|
133
|
-
|
|
134
|
-
|
|
132
|
+
// Reserve space for tick labels + the axis title so the bottom legend
|
|
133
|
+
// can't overlap them at small sizes (SW-2157).
|
|
134
|
+
automargin: !0,
|
|
135
|
+
...C
|
|
135
136
|
},
|
|
136
137
|
yaxis: {
|
|
137
138
|
title: {
|
|
138
|
-
text:
|
|
139
|
+
text: b,
|
|
139
140
|
font: {
|
|
140
141
|
size: 16,
|
|
141
|
-
color:
|
|
142
|
+
color: r.textSecondary,
|
|
142
143
|
family: "Inter, sans-serif",
|
|
143
144
|
weight: 400
|
|
144
145
|
},
|
|
145
146
|
standoff: 30
|
|
146
147
|
},
|
|
147
|
-
gridcolor:
|
|
148
|
-
range:
|
|
149
|
-
autorange: !
|
|
148
|
+
gridcolor: r.gridColor,
|
|
149
|
+
range: p,
|
|
150
|
+
autorange: !p,
|
|
150
151
|
tickmode: "array",
|
|
151
|
-
tickvals:
|
|
152
|
+
tickvals: B,
|
|
152
153
|
showgrid: !0,
|
|
153
|
-
|
|
154
|
-
...
|
|
154
|
+
automargin: !0,
|
|
155
|
+
...C
|
|
155
156
|
},
|
|
156
157
|
legend: {
|
|
158
|
+
// Anchor to the bottom of the container (not the plot area) so the
|
|
159
|
+
// legend always clears the x-axis tick labels + title — a paper-relative
|
|
160
|
+
// fractional offset collapses into the ticks at small heights (SW-2157).
|
|
157
161
|
x: 0.5,
|
|
158
|
-
y:
|
|
162
|
+
y: 0,
|
|
159
163
|
xanchor: "center",
|
|
160
|
-
yanchor: "
|
|
164
|
+
yanchor: "bottom",
|
|
165
|
+
yref: "container",
|
|
161
166
|
orientation: "h",
|
|
162
167
|
font: {
|
|
163
168
|
size: 16,
|
|
164
|
-
color:
|
|
169
|
+
color: r.legendColor,
|
|
165
170
|
family: "Inter, sans-serif",
|
|
166
171
|
weight: 500
|
|
167
172
|
}
|
|
168
173
|
},
|
|
169
174
|
showlegend: !0,
|
|
170
175
|
hovermode: "closest"
|
|
171
|
-
},
|
|
172
|
-
|
|
176
|
+
}, n = {
|
|
177
|
+
// Sizing is driven from the measured container; disable Plotly's own
|
|
178
|
+
// window-resize responsiveness (it can't see container resizes).
|
|
179
|
+
responsive: !1,
|
|
173
180
|
displayModeBar: !1,
|
|
174
181
|
displaylogo: !1
|
|
175
182
|
};
|
|
176
|
-
|
|
177
|
-
const e =
|
|
178
|
-
|
|
179
|
-
|
|
183
|
+
g.newPlot(a.current, o, t, n), N(a.current);
|
|
184
|
+
const e = a.current;
|
|
185
|
+
E.current = !0, M.current = { ...w.current };
|
|
186
|
+
const d = e, y = { color: r.spikeColor, width: 2 };
|
|
187
|
+
return d.on("plotly_hover", (l) => {
|
|
188
|
+
const i = l.points[0];
|
|
189
|
+
i && g.relayout(e, {
|
|
190
|
+
shapes: [
|
|
191
|
+
{
|
|
192
|
+
type: "line",
|
|
193
|
+
xref: "x",
|
|
194
|
+
yref: "paper",
|
|
195
|
+
x0: i.x,
|
|
196
|
+
x1: i.x,
|
|
197
|
+
y0: 0,
|
|
198
|
+
y1: 1,
|
|
199
|
+
line: y,
|
|
200
|
+
layer: "below"
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
type: "line",
|
|
204
|
+
xref: "paper",
|
|
205
|
+
yref: "y",
|
|
206
|
+
x0: 0,
|
|
207
|
+
x1: 1,
|
|
208
|
+
y0: i.y,
|
|
209
|
+
y1: i.y,
|
|
210
|
+
line: y,
|
|
211
|
+
layer: "below"
|
|
212
|
+
}
|
|
213
|
+
]
|
|
214
|
+
});
|
|
215
|
+
}), d.on("plotly_unhover", () => {
|
|
216
|
+
g.relayout(e, { shapes: [] });
|
|
217
|
+
}), () => {
|
|
218
|
+
e && (g.purge(e), E.current = !1);
|
|
180
219
|
};
|
|
181
|
-
}, [
|
|
220
|
+
}, [x, P, u, p, v, b, L, h, f, z, B, C, r, N]), Y(() => {
|
|
221
|
+
const o = a.current;
|
|
222
|
+
!o || !E.current || s <= 0 || c <= 0 || M.current.width === s && M.current.height === c || (M.current = { width: s, height: c }, g.relayout(o, { width: s, height: c }).catch(
|
|
223
|
+
() => {
|
|
224
|
+
}
|
|
225
|
+
));
|
|
226
|
+
}, [s, c]), /* @__PURE__ */ G("div", { ref: H, className: J("relative", W && "w-full", D && "h-full"), children: [
|
|
227
|
+
/* @__PURE__ */ O("div", { ref: a, style: { width: "100%", height: "100%" } }),
|
|
228
|
+
j
|
|
229
|
+
] });
|
|
182
230
|
};
|
|
183
231
|
export {
|
|
184
|
-
|
|
232
|
+
it as ScatterGraph
|
|
185
233
|
};
|
|
186
234
|
//# sourceMappingURL=ScatterGraph.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScatterGraph.js","sources":["../../../../src/components/charts/ScatterGraph/ScatterGraph.tsx"],"sourcesContent":["import Plotly from \"plotly.js-dist\";\nimport React, { useEffect, useRef, useMemo } from \"react\";\n\nimport { usePlotlyTheme } from \"@/hooks/use-plotly-theme\";\n\ninterface ScatterDataPoint {\n x: number;\n y: number;\n additionalInfo?: Record<string, string | number>;\n}\n\ninterface ScatterDataSeries {\n x: number[];\n y: number[];\n name: string;\n color: string;\n}\n\ninterface ScatterGraphProps {\n dataSeries: ScatterDataSeries[];\n width?: number;\n height?: number;\n xRange?: [number, number];\n yRange?: [number, number];\n xTitle?: string;\n yTitle?: string;\n title?: string;\n}\n\nconst ScatterGraph: React.FC<ScatterGraphProps> = ({\n dataSeries,\n width = 1000,\n height = 600,\n xRange,\n yRange,\n xTitle = \"Columns\",\n yTitle = \"Rows\",\n title = \"Scatter Plot\",\n}) => {\n const plotRef = useRef<HTMLDivElement>(null);\n const theme = usePlotlyTheme();\n\n const { xMin, xMax, 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 effectiveXRange = useMemo(\n () => xRange || [xMin, xMax],\n [xRange, xMin, xMax],\n );\n\n const effectiveYRange = useMemo(\n () => yRange || [yMin, yMax],\n [yRange, yMin, yMax],\n );\n\n const xTicks = useMemo(() => {\n const range = effectiveXRange[1] - effectiveXRange[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(effectiveXRange[0] / step) * step;\n while (current <= effectiveXRange[1]) {\n ticks.push(current);\n current += step;\n }\n return ticks;\n }, [effectiveXRange]);\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 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 const spikeOptions = useMemo(\n () => ({\n showspikes: true,\n spikemode: \"across\" as const,\n spikedash: \"solid\" as const,\n spikecolor: theme.spikeColor,\n spikethickness: 2,\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: \"markers\" as const,\n name: series.name,\n marker: {\n color: series.color,\n size: 10,\n symbol: \"circle\" as const,\n },\n hovertemplate: `${xTitle}: %{x}<br>${yTitle}: %{y}<extra>${series.name}</extra>`,\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 ...spikeOptions,\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 ...spikeOptions,\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 hovermode: \"closest\" as const,\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, effectiveXRange, effectiveYRange, xTicks, yTicks, tickOptions, spikeOptions, theme]);\n\n return (\n <div className=\"chart-container\">\n <div ref={plotRef} style={{ width: \"100%\", height: \"100%\" }} />\n </div>\n );\n};\n\nexport { ScatterGraph };\nexport type { ScatterDataPoint, ScatterDataSeries, ScatterGraphProps };\n"],"names":["ScatterGraph","dataSeries","width","height","xRange","yRange","xTitle","yTitle","title","plotRef","useRef","theme","usePlotlyTheme","xMin","xMax","yMin","yMax","useMemo","minX","maxX","minY","maxY","series","x","y","xPadding","yPadding","effectiveXRange","effectiveYRange","xTicks","range","step","ticks","current","yTicks","tickOptions","spikeOptions","useEffect","plotData","layout","config","Plotly","plotElement","jsx"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ScatterGraph.js","sources":["../../../../src/components/charts/ScatterGraph/ScatterGraph.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\ninterface ScatterDataPoint {\n x: number;\n y: number;\n additionalInfo?: Record<string, string | number>;\n}\n\ninterface ScatterDataSeries {\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}\n\ninterface ScatterGraphProps {\n dataSeries: ScatterDataSeries[];\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 xTitle?: string;\n yTitle?: string;\n title?: string;\n}\n\nconst ScatterGraph: React.FC<ScatterGraphProps> = ({\n dataSeries,\n width,\n height,\n xRange,\n yRange,\n xTitle,\n yTitle,\n title = \"Scatter Plot\",\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 { xMin, xMax, 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 effectiveXRange = useMemo(\n () => xRange || [xMin, xMax],\n [xRange, xMin, xMax],\n );\n\n const effectiveYRange = useMemo(\n () => yRange || [yMin, yMax],\n [yRange, yMin, yMax],\n );\n\n const xTicks = useMemo(() => {\n const range = effectiveXRange[1] - effectiveXRange[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(effectiveXRange[0] / step) * step;\n while (current <= effectiveXRange[1]) {\n ticks.push(current);\n current += step;\n }\n return ticks;\n }, [effectiveXRange]);\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 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 x: series.x,\n y: series.y,\n type: \"scatter\" as const,\n mode: \"markers\" as const,\n name: series.name,\n marker: {\n color: seriesColor(index, series.color),\n size: 10,\n symbol: \"circle\" as const,\n },\n hoverinfo: \"none\" as const,\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: sizeRef.current.width,\n height: sizeRef.current.height,\n // Bottom margin reserves room for tick labels, the x-axis title, and the\n // container-anchored bottom legend stacked beneath them.\n margin: { l: 80, r: 30, b: 96, 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 // 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 hovermode: \"closest\" as const,\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 // Crosshair guide lines through the hovered point. Drawn as layout shapes\n // with `layer: \"below\"` so they sit behind the markers — native Plotly\n // spikelines always render on top and can't be moved behind.\n const emitter = plotElement as unknown as Plotly.PlotlyHTMLElement;\n const crosshairLine = { color: theme.spikeColor, width: 2 };\n emitter.on(\"plotly_hover\", (eventData) => {\n const point = eventData.points[0];\n if (!point) return;\n void Plotly.relayout(plotElement, {\n shapes: [\n {\n type: \"line\",\n xref: \"x\",\n yref: \"paper\",\n x0: point.x,\n x1: point.x,\n y0: 0,\n y1: 1,\n line: crosshairLine,\n layer: \"below\",\n },\n {\n type: \"line\",\n xref: \"paper\",\n yref: \"y\",\n x0: 0,\n x1: 1,\n y0: point.y,\n y1: point.y,\n line: crosshairLine,\n layer: \"below\",\n },\n ],\n });\n });\n emitter.on(\"plotly_unhover\", () => {\n void Plotly.relayout(plotElement, { shapes: [] });\n });\n\n return () => {\n if (plotElement) {\n Plotly.purge(plotElement);\n plotInitedRef.current = false;\n }\n };\n }, [dataSeries, hasSize, xRange, yRange, xTitle, yTitle, title, effectiveXRange, effectiveYRange, xTicks, yTicks, tickOptions, theme, bindTooltip]);\n\n // Resize in place when the measured/overridden size changes — cheaper than\n // recreating the plot, and it preserves the hover/crosshair 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 { ScatterGraph };\nexport type { ScatterDataPoint, ScatterDataSeries, ScatterGraphProps };\n"],"names":["ScatterGraph","dataSeries","width","height","xRange","yRange","xTitle","yTitle","title","plotRef","useRef","theme","usePlotlyTheme","bindTooltip","tooltipElement","useChartTooltip","containerRef","measured","useElementSize","resolvedWidth","resolvedHeight","hasSize","fillWidth","fillHeight","sizeRef","plotInitedRef","appliedSizeRef","xMin","xMax","yMin","yMax","useMemo","minX","maxX","minY","maxY","series","x","y","xPadding","yPadding","effectiveXRange","effectiveYRange","xTicks","range","step","ticks","current","yTicks","tickOptions","useEffect","plotData","index","seriesColor","layout","config","Plotly","plotElement","emitter","crosshairLine","eventData","point","jsxs","cn","jsx"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),B=require("class-variance-authority"),N=require("lucide-react"),q=require("react"),O=require("../tdp-link.cjs"),f=require("../../ui/breadcrumb.cjs"),A=require("../../ui/button.cjs"),h=require("../../ui/dropdown-menu.cjs"),m=require("../../ui/sheet.cjs"),x=require("../../ui/tooltip.cjs"),l=require("../../../lib/utils.cjs");function P(r){const a=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(r){for(const i in r)if(i!=="default"){const o=Object.getOwnPropertyDescriptor(r,i);Object.defineProperty(a,i,o.get?o:{enumerable:!0,get:()=>r[i]})}}return a.default=r,Object.freeze(a)}const k=P(q),S=B.cva("flex items-center justify-center rounded-lg transition-colors duration-150",{variants:{active:{true:"bg-primary/10",false:"bg-transparent"},compact:{true:"w-9 h-9 hover:bg-accent",false:"w-8 h-8"}},defaultVariants:{active:!1,compact:!0}});function D({appName:r,appFullName:a,appIcon:i,version:o,navGroups:t,onAppNameClick:d,backToPlatformPath:u,onBackToPlatform:b,userMenu:p,compact:s,onAfterNavClick:y}){return e.jsxs(x.TooltipProvider,{children:[e.jsx("div",{className:l.cn("shrink-0 flex",s?"justify-center py-2":"px-3 py-2.5 border-b border-sidebar-border"),children:e.jsxs(h.DropdownMenu,{children:[e.jsx(h.DropdownMenuTrigger,{asChild:!0,children:e.jsxs("button",{type:"button",className:l.cn("cursor-pointer bg-transparent border-none p-0",!s&&"flex items-center gap-3 w-full text-left"),children:[e.jsx("span",{className:l.cn("flex items-center justify-center rounded-lg bg-sidebar-accent border border-sidebar-border font-bold text-foreground shrink-0",s?"w-9 h-9 text-[11px]":"w-8 h-8 text-[10px]"),children:i??r}),!s&&e.jsx("span",{className:"text-sm font-semibold text-foreground truncate leading-snug",children:a??r})]})}),e.jsxs(h.DropdownMenuContent,{side:"right",align:"start",className:"min-w-[220px]",children:[e.jsxs("div",{className:"flex items-center gap-3 px-3 py-2.5 cursor-pointer",onClick:d,role:"button",tabIndex:0,onKeyDown:c=>{c.key==="Enter"&&d?.()},children:[e.jsx("div",{className:"w-8 h-8 rounded-lg bg-sidebar-accent border border-sidebar-border flex items-center justify-center shrink-0",children:e.jsx("span",{className:"text-[10px] font-bold text-foreground",children:i??r})}),e.jsxs("div",{className:"flex flex-col min-w-0",children:[e.jsx("span",{className:"text-sm font-semibold text-foreground truncate",children:a??r}),o&&e.jsx("span",{className:"text-[10px] text-muted-foreground/70 font-mono leading-none mt-0.5",children:o})]})]}),e.jsx(h.DropdownMenuSeparator,{}),e.jsx(h.DropdownMenuItem,{className:"gap-2.5 p-0",asChild:!0,children:u?e.jsxs(O.TDPLink,{path:u,navigationOptions:{newTab:!1},className:"flex items-center gap-2.5 w-full px-2 py-1.5 !no-underline hover:!no-underline",children:[e.jsx(N.ArrowLeft,{className:"w-4 h-4 text-muted-foreground"}),"Back to TDP Platform"]}):e.jsxs("button",{type:"button",className:"flex items-center gap-2.5 w-full px-2 py-1.5 bg-transparent border-none cursor-pointer",onClick:b,children:[e.jsx(N.ArrowLeft,{className:"w-4 h-4 text-muted-foreground"}),"Back to TDP Platform"]})})]})]})}),s&&e.jsx("div",{className:"shrink-0 mx-auto w-8 border-t border-sidebar-border"}),e.jsx("div",{className:l.cn("flex-1 min-h-0",s?"flex flex-col items-center gap-1 px-2 pt-3 overflow-y-auto":"flex flex-col py-2 overflow-y-auto"),children:t.map((c,j)=>e.jsxs(k.Fragment,{children:[j>0&&e.jsx("div",{className:l.cn("border-t border-sidebar-border",s?"w-8 my-2":"mx-3 my-1")}),!s&&c.label&&e.jsx("span",{className:"px-3 py-1 text-[10px] uppercase tracking-widest text-muted-foreground/60 font-semibold",children:c.label}),e.jsx("div",{className:l.cn("flex flex-col",s?"items-center gap-3 w-full":"gap-0.5"),children:c.pages.map(n=>{const g=n.icon,v=g?e.jsx(g,{className:l.cn("w-5 h-5",n.isActive?"text-primary":"text-muted-foreground")}):e.jsx("div",{className:l.cn("w-2 h-2 rounded-full",n.isActive?"bg-primary":"bg-muted-foreground/40")}),w=()=>{n.onClick?.(),y?.()};return s?e.jsxs(x.Tooltip,{children:[e.jsx(x.TooltipTrigger,{asChild:!0,children:e.jsxs("button",{type:"button",className:"flex flex-col items-center gap-0.5 cursor-pointer bg-transparent border-none p-0 w-full",onClick:w,children:[e.jsx("div",{className:l.cn(S({active:n.isActive??!1,compact:!0})),children:v}),e.jsx("span",{className:l.cn("text-[10px] font-medium leading-tight text-center",n.isActive?"text-foreground font-semibold":"text-muted-foreground"),children:n.label})]})}),e.jsx(x.TooltipContent,{side:"right",children:n.label})]},n.id):e.jsxs("button",{type:"button",className:l.cn("flex items-center gap-3 w-full px-3 py-2 text-sm cursor-pointer bg-transparent border-none text-left transition-colors duration-150 rounded-md mx-1",n.isActive?"bg-sidebar-accent text-sidebar-foreground font-medium":"text-muted-foreground hover:bg-sidebar-accent/60 hover:text-foreground"),onClick:w,children:[e.jsx("div",{className:l.cn(S({active:n.isActive??!1,compact:!1})),children:v}),e.jsx("span",{children:n.label})]},n.id)})})]},`${j}-${c.label??""}`))}),p&&e.jsxs(e.Fragment,{children:[s&&e.jsx("div",{className:"shrink-0 mx-auto w-8 border-t border-sidebar-border"}),e.jsx("div",{className:l.cn("shrink-0",s?"flex flex-col items-center py-2":"p-2 border-t border-sidebar-border"),children:p})]})]})}function M(r){return e.jsx("nav",{"data-slot":"data-app-sidebar-rail","aria-label":"Application navigation",className:"hidden md:flex w-[60px] flex-col shrink-0 bg-sidebar border-r border-sidebar-border h-full z-50",children:e.jsx(D,{compact:!0,...r})})}function L({breadcrumbs:r=[],onHelpClick:a,headerActions:i,mobileTrigger:o}){return e.jsxs("div",{"data-slot":"data-app-top-nav",className:"flex items-center h-10 px-3 bg-sidebar border-b border-sidebar-border sticky top-0 z-40 w-full gap-2",children:[o,e.jsx(f.Breadcrumb,{className:"flex-1 min-w-0",children:e.jsx(f.BreadcrumbList,{children:r.map((t,d)=>{const u=d===r.length-1,b=!u&&(!!t.href||!!t.onClick);return e.jsxs(k.Fragment,{children:[d>0&&e.jsx(f.BreadcrumbSeparator,{children:"/"}),e.jsx(f.BreadcrumbItem,{children:u?e.jsx(f.BreadcrumbPage,{children:t.label}):b&&t.href?e.jsx(f.BreadcrumbLink,{href:t.href,children:t.label}):b&&t.onClick?e.jsx("button",{type:"button",className:"text-[13px] text-primary hover:underline cursor-pointer bg-transparent border-none p-0 font-normal",onClick:t.onClick,children:t.label}):e.jsx("span",{className:"text-[13px] text-muted-foreground",children:t.label})})]},`${t.label}-${d}`)})})}),e.jsxs("div",{className:"flex items-center gap-2 shrink-0",children:[i,a&&e.jsx(x.TooltipProvider,{children:e.jsxs(x.Tooltip,{children:[e.jsx(x.TooltipTrigger,{asChild:!0,children:e.jsx(A.Button,{variant:"ghost",size:"icon",className:"w-7 h-7 text-muted-foreground",onClick:a,"aria-label":"Help",children:e.jsx(N.HelpCircle,{className:"w-4 h-4"})})}),e.jsx(x.TooltipContent,{side:"bottom",children:"Help"})]})})]})]})}function z({appName:r,appFullName:a,appIcon:i,version:o,navGroups:t,onAppNameClick:d,backToPlatformPath:u,onBackToPlatform:b,userMenu:p,breadcrumbs:s=[],onHelpClick:y,headerActions:c,sidebarPanel:j,showNavRail:n=!0,children:g,className:v}){const[w,C]=k.useState(!1),T={appName:r,appFullName:a,appIcon:i,version:o,navGroups:t,onAppNameClick:d,backToPlatformPath:u,onBackToPlatform:b,userMenu:p};return e.jsx(m.Sheet,{open:w,onOpenChange:C,children:e.jsxs("div",{"data-slot":"data-app-shell",className:l.cn("flex flex-row w-full h-screen overflow-hidden",v),children:[n&&e.jsx(M,{...T}),e.jsxs(m.SheetContent,{side:"left",showCloseButton:!1,className:"p-0 bg-sidebar border-r border-sidebar-border data-[side=left]:w-[220px] data-[side=left]:sm:w-[220px] data-[side=left]:sm:max-w-[220px] flex flex-col",children:[e.jsx(m.SheetTitle,{className:"sr-only",children:"Navigation"}),e.jsx(m.SheetDescription,{className:"sr-only",children:"Application navigation menu"}),e.jsx("nav",{"aria-label":"Application navigation",className:"flex flex-col h-full",children:e.jsx(D,{compact:!1,onAfterNavClick:()=>C(!1),...T})})]}),e.jsxs("div",{className:"flex flex-1 flex-col min-w-0 overflow-hidden",children:[e.jsx(L,{breadcrumbs:s,onHelpClick:y,headerActions:c,mobileTrigger:e.jsx(m.SheetTrigger,{asChild:!0,children:e.jsx(A.Button,{variant:"ghost",size:"icon","aria-label":"Open navigation menu",className:"md:hidden w-7 h-7 shrink-0 text-muted-foreground",children:e.jsx(N.Menu,{className:"w-4 h-4"})})})}),e.jsxs("div",{className:"flex flex-1 min-h-0 overflow-hidden",children:[j,e.jsx("main",{"data-slot":"data-app-shell-content",className:"flex-1 overflow-auto bg-background",children:g})]})]})]})})}exports.DataAppShell=z;
|
|
2
2
|
//# sourceMappingURL=DataAppShell.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DataAppShell.cjs","sources":["../../../../src/components/composed/DataAppShell/DataAppShell.tsx"],"sourcesContent":["import { cva } from \"class-variance-authority\";\nimport {\n ArrowLeft,\n HelpCircle,\n Menu,\n type LucideIcon,\n} from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { TDPLink } from \"@/components/composed/tdp-link\";\nimport {\n Breadcrumb,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbList,\n BreadcrumbPage,\n BreadcrumbSeparator,\n} from \"@/components/ui/breadcrumb\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"@/components/ui/dropdown-menu\";\nimport {\n Sheet,\n SheetContent,\n SheetDescription,\n SheetTitle,\n SheetTrigger,\n} from \"@/components/ui/sheet\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from \"@/components/ui/tooltip\";\nimport { cn } from \"@/lib/utils\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface NavPage {\n /** Unique identifier */\n id: string;\n /** Display label */\n label: string;\n /** Lucide icon or custom React SVG component */\n icon?: LucideIcon | React.FC<React.SVGProps<SVGSVGElement>>;\n /** Whether this page is currently active */\n isActive?: boolean;\n /** Click handler */\n onClick?: () => void;\n}\n\nexport interface NavGroup {\n /** Optional group label shown as a section header in expanded nav */\n label?: string;\n /** Page entries in this group */\n pages: NavPage[];\n}\n\nexport interface BreadcrumbItemConfig {\n /** Display label */\n label: string;\n /** If provided, renders as a link */\n href?: string;\n /** Click handler (used when no href is provided) */\n onClick?: () => void;\n}\n\nexport interface DataAppShellProps {\n // -- Sidebar --\n /** Application name/abbreviation shown in the logo button */\n appName: string;\n /** Full application name shown in the app dropdown and mobile nav header */\n appFullName?: string;\n /** Custom icon element shown in the logo area */\n appIcon?: React.ReactNode;\n /** Optional version string shown below the app name/icon in the sidebar header */\n version?: string;\n /** Navigation groups; each group contains one or more pages */\n navGroups: NavGroup[];\n /** Callback when the app name / icon is clicked in the dropdown */\n onAppNameClick?: () => void;\n /** TDP path to navigate to when \"Back to TDP Platform\" is clicked (uses TDPLink — requires TdpNavigationProvider) */\n backToPlatformPath?: string;\n /** Fallback callback when \"Back to TDP Platform\" is clicked and no backToPlatformPath is set */\n onBackToPlatform?: () => void;\n /** Slot rendered at the bottom of the sidebar (e.g. user avatar + menu) */\n userMenu?: React.ReactNode;\n\n // -- Top nav --\n /** Breadcrumb items from root to current page */\n breadcrumbs?: BreadcrumbItemConfig[];\n /** Callback when the help button is clicked; omit to hide the button */\n onHelpClick?: () => void;\n /** Slot for right-side actions in the top nav (e.g. data count pills, next button) */\n headerActions?: React.ReactNode;\n\n // -- Shell --\n /** Slot rendered between the icon rail and the content (e.g. WorkflowPanel) */\n sidebarPanel?: React.ReactNode;\n /** Main content area */\n children: React.ReactNode;\n /** Additional className for the root container */\n className?: string;\n}\n\n// =============================================================================\n// Sidebar shared body (used by desktop rail + mobile Sheet)\n// =============================================================================\n\ninterface SidebarBodyProps\n extends Pick<\n DataAppShellProps,\n | \"appName\"\n | \"appFullName\"\n | \"appIcon\"\n | \"version\"\n | \"navGroups\"\n | \"onAppNameClick\"\n | \"backToPlatformPath\"\n | \"onBackToPlatform\"\n | \"userMenu\"\n > {\n /**\n * compact=true → narrow icon rail (60px): icons + tiny labels stacked, tooltips on hover\n * compact=false → expanded mobile sheet (220px): icon + label side-by-side rows\n */\n compact: boolean;\n /** Called after a nav page item is clicked — used by mobile sheet to close itself */\n onAfterNavClick?: () => void;\n}\n\nconst pageIconVariants = cva(\n \"flex items-center justify-center rounded-lg transition-colors duration-150\",\n {\n variants: {\n active: {\n true: \"bg-primary/10\",\n false: \"bg-transparent\",\n },\n compact: {\n true: \"w-9 h-9 hover:bg-muted\",\n false: \"w-8 h-8\",\n },\n },\n defaultVariants: { active: false, compact: true },\n }\n);\n\nfunction SidebarBody({\n appName,\n appFullName,\n appIcon,\n version,\n navGroups,\n onAppNameClick,\n backToPlatformPath,\n onBackToPlatform,\n userMenu,\n compact,\n onAfterNavClick,\n}: SidebarBodyProps) {\n return (\n <TooltipProvider>\n {/* ── Header: app icon / name + version ──────────────────────────────── */}\n <div\n className={cn(\n \"shrink-0 border-b border-sidebar-border\",\n compact ? \"flex justify-center py-2\" : \"flex px-3 py-2.5\"\n )}\n >\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n className={cn(\n \"cursor-pointer bg-transparent border-none p-0\",\n !compact && \"flex items-center gap-3 w-full text-left\"\n )}\n >\n {/* Icon */}\n <span\n className={cn(\n \"flex items-center justify-center rounded-lg bg-sidebar-accent border border-sidebar-border font-bold text-foreground shrink-0\",\n compact ? \"w-9 h-9 text-[11px]\" : \"w-8 h-8 text-[10px]\"\n )}\n >\n {appIcon ?? appName}\n </span>\n\n {/* Name (expanded only — no version here) */}\n {!compact && (\n <span className=\"text-sm font-semibold text-foreground truncate leading-snug\">\n {appFullName ?? appName}\n </span>\n )}\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent side=\"right\" align=\"start\" className=\"min-w-[220px]\">\n <div\n className=\"flex items-center gap-3 px-3 py-2.5 cursor-pointer\"\n onClick={onAppNameClick}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") onAppNameClick?.();\n }}\n >\n <div className=\"w-8 h-8 rounded-lg bg-sidebar-accent border border-sidebar-border flex items-center justify-center shrink-0\">\n <span className=\"text-[10px] font-bold text-foreground\">\n {appIcon ?? appName}\n </span>\n </div>\n <div className=\"flex flex-col min-w-0\">\n <span className=\"text-sm font-semibold text-foreground truncate\">\n {appFullName ?? appName}\n </span>\n {version && (\n <span className=\"text-[10px] text-muted-foreground/70 font-mono leading-none mt-0.5\">\n {version}\n </span>\n )}\n </div>\n </div>\n <DropdownMenuSeparator />\n <DropdownMenuItem className=\"gap-2.5 p-0\" asChild>\n {backToPlatformPath ? (\n <TDPLink\n path={backToPlatformPath}\n navigationOptions={{ newTab: false }}\n className=\"flex items-center gap-2.5 w-full px-2 py-1.5 !no-underline hover:!no-underline\"\n >\n <ArrowLeft className=\"w-4 h-4 text-muted-foreground\" />\n Back to TDP Platform\n </TDPLink>\n ) : (\n <button\n type=\"button\"\n className=\"flex items-center gap-2.5 w-full px-2 py-1.5 bg-transparent border-none cursor-pointer\"\n onClick={onBackToPlatform}\n >\n <ArrowLeft className=\"w-4 h-4 text-muted-foreground\" />\n Back to TDP Platform\n </button>\n )}\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n\n {/* ── Nav groups ──────────────────────────────────────────────────────── */}\n <div\n className={cn(\n \"flex-1 min-h-0\",\n compact\n ? \"flex flex-col items-center gap-1 px-2 pt-3 overflow-y-auto\"\n : \"flex flex-col py-2 overflow-y-auto\"\n )}\n >\n {navGroups.map((group, groupIndex) => (\n <React.Fragment key={`${groupIndex}-${group.label ?? \"\"}`}>\n {groupIndex > 0 && (\n <div\n className={cn(\n \"border-t border-sidebar-border\",\n compact ? \"w-8 my-2\" : \"mx-3 my-1\"\n )}\n />\n )}\n {!compact && group.label && (\n <span className=\"px-3 py-1 text-[10px] uppercase tracking-widest text-muted-foreground/60 font-semibold\">\n {group.label}\n </span>\n )}\n <div\n className={cn(\n \"flex flex-col\",\n compact ? \"items-center gap-3 w-full\" : \"gap-0.5\"\n )}\n >\n {group.pages.map((page) => {\n const Icon = page.icon;\n const iconEl = Icon ? (\n <Icon\n className={cn(\n \"w-5 h-5\",\n page.isActive ? \"text-primary\" : \"text-muted-foreground\"\n )}\n />\n ) : (\n <div\n className={cn(\n \"w-2 h-2 rounded-full\",\n page.isActive ? \"bg-primary\" : \"bg-muted-foreground/40\"\n )}\n />\n );\n\n const handleClick = () => {\n page.onClick?.();\n onAfterNavClick?.();\n };\n\n if (compact) {\n return (\n <Tooltip key={page.id}>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n className=\"flex flex-col items-center gap-0.5 cursor-pointer bg-transparent border-none p-0 w-full\"\n onClick={handleClick}\n >\n <div className={cn(pageIconVariants({ active: page.isActive ?? false, compact: true }))}>\n {iconEl}\n </div>\n <span\n className={cn(\n \"text-[10px] font-medium leading-tight text-center\",\n page.isActive\n ? \"text-foreground font-semibold\"\n : \"text-muted-foreground\"\n )}\n >\n {page.label}\n </span>\n </button>\n </TooltipTrigger>\n <TooltipContent side=\"right\">{page.label}</TooltipContent>\n </Tooltip>\n );\n }\n\n // Expanded (mobile) row\n return (\n <button\n key={page.id}\n type=\"button\"\n className={cn(\n \"flex items-center gap-3 w-full px-3 py-2 text-sm cursor-pointer bg-transparent border-none text-left transition-colors duration-150 rounded-md mx-1\",\n page.isActive\n ? \"bg-sidebar-accent text-sidebar-foreground font-medium\"\n : \"text-muted-foreground hover:bg-sidebar-accent/60 hover:text-foreground\"\n )}\n onClick={handleClick}\n >\n <div className={cn(pageIconVariants({ active: page.isActive ?? false, compact: false }))}>\n {iconEl}\n </div>\n <span>{page.label}</span>\n </button>\n );\n })}\n </div>\n </React.Fragment>\n ))}\n </div>\n\n {/* ── Bottom: user menu slot ──────────────────────────────────────────── */}\n {userMenu && (\n <div\n className={cn(\n \"shrink-0 border-t border-sidebar-border\",\n compact ? \"flex flex-col items-center py-2\" : \"p-2\"\n )}\n >\n {userMenu}\n </div>\n )}\n </TooltipProvider>\n );\n}\n\n// =============================================================================\n// Icon rail sidebar (desktop only — hidden on mobile)\n// =============================================================================\n\nfunction IconRailSidebar(props: Omit<SidebarBodyProps, \"compact\" | \"onAfterNavClick\">) {\n return (\n <nav\n data-slot=\"data-app-sidebar-rail\"\n aria-label=\"Application navigation\"\n className=\"hidden md:flex w-[60px] flex-col shrink-0 bg-sidebar border-r border-sidebar-border h-full z-50\"\n >\n <SidebarBody compact {...props} />\n </nav>\n );\n}\n\n// =============================================================================\n// Top nav\n// =============================================================================\n\nfunction TopNav({\n breadcrumbs = [],\n onHelpClick,\n headerActions,\n mobileTrigger,\n}: {\n breadcrumbs?: BreadcrumbItemConfig[];\n onHelpClick?: () => void;\n headerActions?: React.ReactNode;\n mobileTrigger?: React.ReactNode;\n}) {\n return (\n <div\n data-slot=\"data-app-top-nav\"\n className=\"flex items-center h-10 px-3 bg-sidebar border-b border-sidebar-border sticky top-0 z-40 w-full gap-2\"\n >\n {/* Mobile hamburger (hidden on md+) */}\n {mobileTrigger}\n\n {/* Left: Breadcrumbs */}\n <Breadcrumb className=\"flex-1 min-w-0\">\n <BreadcrumbList>\n {breadcrumbs.map((item, index) => {\n const isLast = index === breadcrumbs.length - 1;\n const isClickable = !isLast && (!!item.href || !!item.onClick);\n return (\n <React.Fragment key={`${item.label}-${index}`}>\n {index > 0 && <BreadcrumbSeparator>/</BreadcrumbSeparator>}\n <BreadcrumbItem>\n {isLast ? (\n <BreadcrumbPage>{item.label}</BreadcrumbPage>\n ) : isClickable && item.href ? (\n <BreadcrumbLink href={item.href}>{item.label}</BreadcrumbLink>\n ) : isClickable && item.onClick ? (\n <button\n type=\"button\"\n className=\"text-[13px] text-primary hover:underline cursor-pointer bg-transparent border-none p-0 font-normal\"\n onClick={item.onClick}\n >\n {item.label}\n </button>\n ) : (\n <span className=\"text-[13px] text-muted-foreground\">{item.label}</span>\n )}\n </BreadcrumbItem>\n </React.Fragment>\n );\n })}\n </BreadcrumbList>\n </Breadcrumb>\n\n {/* Right: header actions + help */}\n <div className=\"flex items-center gap-2 shrink-0\">\n {headerActions}\n\n {onHelpClick && (\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"w-7 h-7 text-muted-foreground\"\n onClick={onHelpClick}\n aria-label=\"Help\"\n >\n <HelpCircle className=\"w-4 h-4\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent side=\"bottom\">Help</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n )}\n </div>\n </div>\n );\n}\n\n// =============================================================================\n// DataAppShell\n// =============================================================================\n\nfunction DataAppShell({\n appName,\n appFullName,\n appIcon,\n version,\n navGroups,\n onAppNameClick,\n backToPlatformPath,\n onBackToPlatform,\n userMenu,\n breadcrumbs = [],\n onHelpClick,\n headerActions,\n sidebarPanel,\n children,\n className,\n}: DataAppShellProps) {\n const [mobileNavOpen, setMobileNavOpen] = React.useState(false);\n\n const sidebarProps = {\n appName,\n appFullName,\n appIcon,\n version,\n navGroups,\n onAppNameClick,\n backToPlatformPath,\n onBackToPlatform,\n userMenu,\n };\n\n return (\n <Sheet open={mobileNavOpen} onOpenChange={setMobileNavOpen}>\n <div\n data-slot=\"data-app-shell\"\n className={cn(\"flex flex-row w-full h-screen overflow-hidden\", className)}\n >\n {/* Desktop icon rail (hidden on mobile) */}\n <IconRailSidebar {...sidebarProps} />\n\n {/* Mobile sidebar Sheet */}\n <SheetContent\n side=\"left\"\n showCloseButton={false}\n className=\"p-0 bg-sidebar border-r border-sidebar-border data-[side=left]:w-[220px] data-[side=left]:sm:w-[220px] data-[side=left]:sm:max-w-[220px] flex flex-col\"\n >\n <SheetTitle className=\"sr-only\">Navigation</SheetTitle>\n <SheetDescription className=\"sr-only\">\n Application navigation menu\n </SheetDescription>\n <nav aria-label=\"Application navigation\" className=\"flex flex-col h-full\">\n <SidebarBody\n compact={false}\n onAfterNavClick={() => setMobileNavOpen(false)}\n {...sidebarProps}\n />\n </nav>\n </SheetContent>\n\n {/* Right: top nav + panel + content */}\n <div className=\"flex flex-1 flex-col min-w-0 overflow-hidden\">\n <TopNav\n breadcrumbs={breadcrumbs}\n onHelpClick={onHelpClick}\n headerActions={headerActions}\n mobileTrigger={\n <SheetTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label=\"Open navigation menu\"\n className=\"md:hidden w-7 h-7 shrink-0 text-muted-foreground\"\n >\n <Menu className=\"w-4 h-4\" />\n </Button>\n </SheetTrigger>\n }\n />\n\n <div className=\"flex flex-1 min-h-0 overflow-hidden\">\n {/* Sidebar panel slot (e.g. WorkflowPanel) */}\n {sidebarPanel}\n\n {/* Content area */}\n <main\n data-slot=\"data-app-shell-content\"\n className=\"flex-1 overflow-auto bg-background\"\n >\n {children}\n </main>\n </div>\n </div>\n </div>\n </Sheet>\n );\n}\n\nexport default DataAppShell;\nexport { DataAppShell };\n"],"names":["pageIconVariants","cva","SidebarBody","appName","appFullName","appIcon","version","navGroups","onAppNameClick","backToPlatformPath","onBackToPlatform","userMenu","compact","onAfterNavClick","TooltipProvider","jsx","cn","DropdownMenu","DropdownMenuTrigger","jsxs","DropdownMenuContent","e","DropdownMenuSeparator","DropdownMenuItem","TDPLink","ArrowLeft","group","groupIndex","React","page","Icon","iconEl","handleClick","Tooltip","TooltipTrigger","TooltipContent","IconRailSidebar","props","TopNav","breadcrumbs","onHelpClick","headerActions","mobileTrigger","Breadcrumb","BreadcrumbList","item","index","isLast","isClickable","BreadcrumbSeparator","BreadcrumbItem","BreadcrumbPage","BreadcrumbLink","Button","HelpCircle","DataAppShell","sidebarPanel","children","className","mobileNavOpen","setMobileNavOpen","sidebarProps","Sheet","SheetContent","SheetTitle","SheetDescription","SheetTrigger","Menu"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DataAppShell.cjs","sources":["../../../../src/components/composed/DataAppShell/DataAppShell.tsx"],"sourcesContent":["import { cva } from \"class-variance-authority\";\nimport {\n ArrowLeft,\n HelpCircle,\n Menu,\n type LucideIcon,\n} from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { TDPLink } from \"@/components/composed/tdp-link\";\nimport {\n Breadcrumb,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbList,\n BreadcrumbPage,\n BreadcrumbSeparator,\n} from \"@/components/ui/breadcrumb\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"@/components/ui/dropdown-menu\";\nimport {\n Sheet,\n SheetContent,\n SheetDescription,\n SheetTitle,\n SheetTrigger,\n} from \"@/components/ui/sheet\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from \"@/components/ui/tooltip\";\nimport { cn } from \"@/lib/utils\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface NavPage {\n /** Unique identifier */\n id: string;\n /** Display label */\n label: string;\n /** Lucide icon or custom React SVG component */\n icon?: LucideIcon | React.FC<React.SVGProps<SVGSVGElement>>;\n /** Whether this page is currently active */\n isActive?: boolean;\n /** Click handler */\n onClick?: () => void;\n}\n\nexport interface NavGroup {\n /** Optional group label shown as a section header in expanded nav */\n label?: string;\n /** Page entries in this group */\n pages: NavPage[];\n}\n\nexport interface BreadcrumbItemConfig {\n /** Display label */\n label: string;\n /** If provided, renders as a link */\n href?: string;\n /** Click handler (used when no href is provided) */\n onClick?: () => void;\n}\n\nexport interface DataAppShellProps {\n // -- Sidebar --\n /** Application name/abbreviation shown in the logo button */\n appName: string;\n /** Full application name shown in the app dropdown and mobile nav header */\n appFullName?: string;\n /** Custom icon element shown in the logo area */\n appIcon?: React.ReactNode;\n /** Optional version string shown below the app name/icon in the sidebar header */\n version?: string;\n /** Navigation groups; each group contains one or more pages */\n navGroups: NavGroup[];\n /** Callback when the app name / icon is clicked in the dropdown */\n onAppNameClick?: () => void;\n /** TDP path to navigate to when \"Back to TDP Platform\" is clicked (uses TDPLink — requires TdpNavigationProvider) */\n backToPlatformPath?: string;\n /** Fallback callback when \"Back to TDP Platform\" is clicked and no backToPlatformPath is set */\n onBackToPlatform?: () => void;\n /** Slot rendered at the bottom of the sidebar (e.g. user avatar + menu) */\n userMenu?: React.ReactNode;\n\n // -- Top nav --\n /** Breadcrumb items from root to current page */\n breadcrumbs?: BreadcrumbItemConfig[];\n /** Callback when the help button is clicked; omit to hide the button */\n onHelpClick?: () => void;\n /** Slot for right-side actions in the top nav (e.g. data count pills, next button) */\n headerActions?: React.ReactNode;\n\n // -- Shell --\n /** Slot rendered between the icon rail and the content (e.g. WorkflowPanel) */\n sidebarPanel?: React.ReactNode;\n /** Show the desktop icon nav rail. Set false to reclaim width when the panel is collapsed. */\n showNavRail?: boolean; // default true\n /** Main content area */\n children: React.ReactNode;\n /** Additional className for the root container */\n className?: string;\n}\n\n// =============================================================================\n// Sidebar shared body (used by desktop rail + mobile Sheet)\n// =============================================================================\n\ninterface SidebarBodyProps\n extends Pick<\n DataAppShellProps,\n | \"appName\"\n | \"appFullName\"\n | \"appIcon\"\n | \"version\"\n | \"navGroups\"\n | \"onAppNameClick\"\n | \"backToPlatformPath\"\n | \"onBackToPlatform\"\n | \"userMenu\"\n > {\n /**\n * compact=true → narrow icon rail (60px): icons + tiny labels stacked, tooltips on hover\n * compact=false → expanded mobile sheet (220px): icon + label side-by-side rows\n */\n compact: boolean;\n /** Called after a nav page item is clicked — used by mobile sheet to close itself */\n onAfterNavClick?: () => void;\n}\n\nconst pageIconVariants = cva(\n \"flex items-center justify-center rounded-lg transition-colors duration-150\",\n {\n variants: {\n active: {\n true: \"bg-primary/10\",\n false: \"bg-transparent\",\n },\n compact: {\n true: \"w-9 h-9 hover:bg-accent\",\n false: \"w-8 h-8\",\n },\n },\n defaultVariants: { active: false, compact: true },\n }\n);\n\nfunction SidebarBody({\n appName,\n appFullName,\n appIcon,\n version,\n navGroups,\n onAppNameClick,\n backToPlatformPath,\n onBackToPlatform,\n userMenu,\n compact,\n onAfterNavClick,\n}: SidebarBodyProps) {\n return (\n <TooltipProvider>\n {/* ── Header: app icon / name + version ──────────────────────────────── */}\n <div\n className={cn(\n \"shrink-0 flex\",\n // Expanded: full-width header border. Collapsed: no full-width border —\n // a short centered divider (below) aligns under the icon column instead.\n compact ? \"justify-center py-2\" : \"px-3 py-2.5 border-b border-sidebar-border\"\n )}\n >\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n className={cn(\n \"cursor-pointer bg-transparent border-none p-0\",\n !compact && \"flex items-center gap-3 w-full text-left\"\n )}\n >\n {/* Icon */}\n <span\n className={cn(\n \"flex items-center justify-center rounded-lg bg-sidebar-accent border border-sidebar-border font-bold text-foreground shrink-0\",\n compact ? \"w-9 h-9 text-[11px]\" : \"w-8 h-8 text-[10px]\"\n )}\n >\n {appIcon ?? appName}\n </span>\n\n {/* Name (expanded only — no version here) */}\n {!compact && (\n <span className=\"text-sm font-semibold text-foreground truncate leading-snug\">\n {appFullName ?? appName}\n </span>\n )}\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent side=\"right\" align=\"start\" className=\"min-w-[220px]\">\n <div\n className=\"flex items-center gap-3 px-3 py-2.5 cursor-pointer\"\n onClick={onAppNameClick}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") onAppNameClick?.();\n }}\n >\n <div className=\"w-8 h-8 rounded-lg bg-sidebar-accent border border-sidebar-border flex items-center justify-center shrink-0\">\n <span className=\"text-[10px] font-bold text-foreground\">\n {appIcon ?? appName}\n </span>\n </div>\n <div className=\"flex flex-col min-w-0\">\n <span className=\"text-sm font-semibold text-foreground truncate\">\n {appFullName ?? appName}\n </span>\n {version && (\n <span className=\"text-[10px] text-muted-foreground/70 font-mono leading-none mt-0.5\">\n {version}\n </span>\n )}\n </div>\n </div>\n <DropdownMenuSeparator />\n <DropdownMenuItem className=\"gap-2.5 p-0\" asChild>\n {backToPlatformPath ? (\n <TDPLink\n path={backToPlatformPath}\n navigationOptions={{ newTab: false }}\n className=\"flex items-center gap-2.5 w-full px-2 py-1.5 !no-underline hover:!no-underline\"\n >\n <ArrowLeft className=\"w-4 h-4 text-muted-foreground\" />\n Back to TDP Platform\n </TDPLink>\n ) : (\n <button\n type=\"button\"\n className=\"flex items-center gap-2.5 w-full px-2 py-1.5 bg-transparent border-none cursor-pointer\"\n onClick={onBackToPlatform}\n >\n <ArrowLeft className=\"w-4 h-4 text-muted-foreground\" />\n Back to TDP Platform\n </button>\n )}\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n\n {/* Collapsed: short centered divider aligned under the icon column\n (matches the nav-group dividers). Expanded uses the header's border-b. */}\n {compact && <div className=\"shrink-0 mx-auto w-8 border-t border-sidebar-border\" />}\n\n {/* ── Nav groups ──────────────────────────────────────────────────────── */}\n <div\n className={cn(\n \"flex-1 min-h-0\",\n compact\n ? \"flex flex-col items-center gap-1 px-2 pt-3 overflow-y-auto\"\n : \"flex flex-col py-2 overflow-y-auto\"\n )}\n >\n {navGroups.map((group, groupIndex) => (\n <React.Fragment key={`${groupIndex}-${group.label ?? \"\"}`}>\n {groupIndex > 0 && (\n <div\n className={cn(\n \"border-t border-sidebar-border\",\n compact ? \"w-8 my-2\" : \"mx-3 my-1\"\n )}\n />\n )}\n {!compact && group.label && (\n <span className=\"px-3 py-1 text-[10px] uppercase tracking-widest text-muted-foreground/60 font-semibold\">\n {group.label}\n </span>\n )}\n <div\n className={cn(\n \"flex flex-col\",\n compact ? \"items-center gap-3 w-full\" : \"gap-0.5\"\n )}\n >\n {group.pages.map((page) => {\n const Icon = page.icon;\n const iconEl = Icon ? (\n <Icon\n className={cn(\n \"w-5 h-5\",\n page.isActive ? \"text-primary\" : \"text-muted-foreground\"\n )}\n />\n ) : (\n <div\n className={cn(\n \"w-2 h-2 rounded-full\",\n page.isActive ? \"bg-primary\" : \"bg-muted-foreground/40\"\n )}\n />\n );\n\n const handleClick = () => {\n page.onClick?.();\n onAfterNavClick?.();\n };\n\n if (compact) {\n return (\n <Tooltip key={page.id}>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n className=\"flex flex-col items-center gap-0.5 cursor-pointer bg-transparent border-none p-0 w-full\"\n onClick={handleClick}\n >\n <div className={cn(pageIconVariants({ active: page.isActive ?? false, compact: true }))}>\n {iconEl}\n </div>\n <span\n className={cn(\n \"text-[10px] font-medium leading-tight text-center\",\n page.isActive\n ? \"text-foreground font-semibold\"\n : \"text-muted-foreground\"\n )}\n >\n {page.label}\n </span>\n </button>\n </TooltipTrigger>\n <TooltipContent side=\"right\">{page.label}</TooltipContent>\n </Tooltip>\n );\n }\n\n // Expanded (mobile) row\n return (\n <button\n key={page.id}\n type=\"button\"\n className={cn(\n \"flex items-center gap-3 w-full px-3 py-2 text-sm cursor-pointer bg-transparent border-none text-left transition-colors duration-150 rounded-md mx-1\",\n page.isActive\n ? \"bg-sidebar-accent text-sidebar-foreground font-medium\"\n : \"text-muted-foreground hover:bg-sidebar-accent/60 hover:text-foreground\"\n )}\n onClick={handleClick}\n >\n <div className={cn(pageIconVariants({ active: page.isActive ?? false, compact: false }))}>\n {iconEl}\n </div>\n <span>{page.label}</span>\n </button>\n );\n })}\n </div>\n </React.Fragment>\n ))}\n </div>\n\n {/* ── Bottom: user menu slot ──────────────────────────────────────────── */}\n {userMenu && (\n <>\n {/* Collapsed: short centered divider aligned under the icon column.\n Expanded uses the full-width border on the wrapper below. */}\n {compact && (\n <div className=\"shrink-0 mx-auto w-8 border-t border-sidebar-border\" />\n )}\n <div\n className={cn(\n \"shrink-0\",\n compact\n ? \"flex flex-col items-center py-2\"\n : \"p-2 border-t border-sidebar-border\"\n )}\n >\n {userMenu}\n </div>\n </>\n )}\n </TooltipProvider>\n );\n}\n\n// =============================================================================\n// Icon rail sidebar (desktop only — hidden on mobile)\n// =============================================================================\n\nfunction IconRailSidebar(props: Omit<SidebarBodyProps, \"compact\" | \"onAfterNavClick\">) {\n return (\n <nav\n data-slot=\"data-app-sidebar-rail\"\n aria-label=\"Application navigation\"\n className=\"hidden md:flex w-[60px] flex-col shrink-0 bg-sidebar border-r border-sidebar-border h-full z-50\"\n >\n <SidebarBody compact {...props} />\n </nav>\n );\n}\n\n// =============================================================================\n// Top nav\n// =============================================================================\n\nfunction TopNav({\n breadcrumbs = [],\n onHelpClick,\n headerActions,\n mobileTrigger,\n}: {\n breadcrumbs?: BreadcrumbItemConfig[];\n onHelpClick?: () => void;\n headerActions?: React.ReactNode;\n mobileTrigger?: React.ReactNode;\n}) {\n return (\n <div\n data-slot=\"data-app-top-nav\"\n className=\"flex items-center h-10 px-3 bg-sidebar border-b border-sidebar-border sticky top-0 z-40 w-full gap-2\"\n >\n {/* Mobile hamburger (hidden on md+) */}\n {mobileTrigger}\n\n {/* Left: Breadcrumbs */}\n <Breadcrumb className=\"flex-1 min-w-0\">\n <BreadcrumbList>\n {breadcrumbs.map((item, index) => {\n const isLast = index === breadcrumbs.length - 1;\n const isClickable = !isLast && (!!item.href || !!item.onClick);\n return (\n <React.Fragment key={`${item.label}-${index}`}>\n {index > 0 && <BreadcrumbSeparator>/</BreadcrumbSeparator>}\n <BreadcrumbItem>\n {isLast ? (\n <BreadcrumbPage>{item.label}</BreadcrumbPage>\n ) : isClickable && item.href ? (\n <BreadcrumbLink href={item.href}>{item.label}</BreadcrumbLink>\n ) : isClickable && item.onClick ? (\n <button\n type=\"button\"\n className=\"text-[13px] text-primary hover:underline cursor-pointer bg-transparent border-none p-0 font-normal\"\n onClick={item.onClick}\n >\n {item.label}\n </button>\n ) : (\n <span className=\"text-[13px] text-muted-foreground\">{item.label}</span>\n )}\n </BreadcrumbItem>\n </React.Fragment>\n );\n })}\n </BreadcrumbList>\n </Breadcrumb>\n\n {/* Right: header actions + help */}\n <div className=\"flex items-center gap-2 shrink-0\">\n {headerActions}\n\n {onHelpClick && (\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"w-7 h-7 text-muted-foreground\"\n onClick={onHelpClick}\n aria-label=\"Help\"\n >\n <HelpCircle className=\"w-4 h-4\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent side=\"bottom\">Help</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n )}\n </div>\n </div>\n );\n}\n\n// =============================================================================\n// DataAppShell\n// =============================================================================\n\nfunction DataAppShell({\n appName,\n appFullName,\n appIcon,\n version,\n navGroups,\n onAppNameClick,\n backToPlatformPath,\n onBackToPlatform,\n userMenu,\n breadcrumbs = [],\n onHelpClick,\n headerActions,\n sidebarPanel,\n showNavRail = true,\n children,\n className,\n}: DataAppShellProps) {\n const [mobileNavOpen, setMobileNavOpen] = React.useState(false);\n\n const sidebarProps = {\n appName,\n appFullName,\n appIcon,\n version,\n navGroups,\n onAppNameClick,\n backToPlatformPath,\n onBackToPlatform,\n userMenu,\n };\n\n return (\n <Sheet open={mobileNavOpen} onOpenChange={setMobileNavOpen}>\n <div\n data-slot=\"data-app-shell\"\n className={cn(\"flex flex-row w-full h-screen overflow-hidden\", className)}\n >\n {/* Desktop icon rail (hidden on mobile, or when showNavRail is false) */}\n {showNavRail && <IconRailSidebar {...sidebarProps} />}\n\n {/* Mobile sidebar Sheet */}\n <SheetContent\n side=\"left\"\n showCloseButton={false}\n className=\"p-0 bg-sidebar border-r border-sidebar-border data-[side=left]:w-[220px] data-[side=left]:sm:w-[220px] data-[side=left]:sm:max-w-[220px] flex flex-col\"\n >\n <SheetTitle className=\"sr-only\">Navigation</SheetTitle>\n <SheetDescription className=\"sr-only\">\n Application navigation menu\n </SheetDescription>\n <nav aria-label=\"Application navigation\" className=\"flex flex-col h-full\">\n <SidebarBody\n compact={false}\n onAfterNavClick={() => setMobileNavOpen(false)}\n {...sidebarProps}\n />\n </nav>\n </SheetContent>\n\n {/* Right: top nav + panel + content */}\n <div className=\"flex flex-1 flex-col min-w-0 overflow-hidden\">\n <TopNav\n breadcrumbs={breadcrumbs}\n onHelpClick={onHelpClick}\n headerActions={headerActions}\n mobileTrigger={\n <SheetTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label=\"Open navigation menu\"\n className=\"md:hidden w-7 h-7 shrink-0 text-muted-foreground\"\n >\n <Menu className=\"w-4 h-4\" />\n </Button>\n </SheetTrigger>\n }\n />\n\n <div className=\"flex flex-1 min-h-0 overflow-hidden\">\n {/* Sidebar panel slot (e.g. WorkflowPanel) */}\n {sidebarPanel}\n\n {/* Content area */}\n <main\n data-slot=\"data-app-shell-content\"\n className=\"flex-1 overflow-auto bg-background\"\n >\n {children}\n </main>\n </div>\n </div>\n </div>\n </Sheet>\n );\n}\n\nexport default DataAppShell;\nexport { DataAppShell };\n"],"names":["pageIconVariants","cva","SidebarBody","appName","appFullName","appIcon","version","navGroups","onAppNameClick","backToPlatformPath","onBackToPlatform","userMenu","compact","onAfterNavClick","TooltipProvider","jsx","cn","DropdownMenu","DropdownMenuTrigger","jsxs","DropdownMenuContent","e","DropdownMenuSeparator","DropdownMenuItem","TDPLink","ArrowLeft","group","groupIndex","React","page","Icon","iconEl","handleClick","Tooltip","TooltipTrigger","TooltipContent","Fragment","IconRailSidebar","props","TopNav","breadcrumbs","onHelpClick","headerActions","mobileTrigger","Breadcrumb","BreadcrumbList","item","index","isLast","isClickable","BreadcrumbSeparator","BreadcrumbItem","BreadcrumbPage","BreadcrumbLink","Button","HelpCircle","DataAppShell","sidebarPanel","showNavRail","children","className","mobileNavOpen","setMobileNavOpen","sidebarProps","Sheet","SheetContent","SheetTitle","SheetDescription","SheetTrigger","Menu"],"mappings":"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"}
|