ioloco-charts 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/dist/D3/AreaChart/index.d.ts +2 -0
  2. package/dist/D3/AreaChart/index.js +54 -0
  3. package/dist/D3/AreaChart/types.d.ts +20 -0
  4. package/dist/D3/BarChart/index.d.ts +3 -0
  5. package/dist/D3/BarChart/index.js +29 -0
  6. package/dist/D3/BarChart/types.d.ts +13 -0
  7. package/dist/D3/DonutChart/index.d.ts +2 -0
  8. package/dist/D3/DonutChart/index.js +35 -0
  9. package/dist/D3/DonutChart/types.d.ts +15 -0
  10. package/dist/D3/FunnelChart/index.d.ts +2 -0
  11. package/dist/D3/FunnelChart/index.js +27 -0
  12. package/dist/D3/FunnelChart/types.d.ts +12 -0
  13. package/dist/D3/GanttTimeline/index.d.ts +2 -0
  14. package/dist/D3/GanttTimeline/index.js +36 -0
  15. package/dist/D3/GanttTimeline/types.d.ts +15 -0
  16. package/dist/D3/GaugeChart/index.d.ts +2 -0
  17. package/dist/D3/GaugeChart/index.js +22 -0
  18. package/dist/D3/GaugeChart/types.d.ts +17 -0
  19. package/dist/D3/HeatmapChart/heatmapLayout.d.ts +28 -0
  20. package/dist/D3/HeatmapChart/heatmapLayout.js +11 -0
  21. package/dist/D3/HeatmapChart/index.d.ts +2 -0
  22. package/dist/D3/HeatmapChart/index.js +31 -0
  23. package/dist/D3/HeatmapChart/types.d.ts +17 -0
  24. package/dist/D3/KpiCard/index.d.ts +2 -0
  25. package/dist/D3/KpiCard/index.js +12 -0
  26. package/dist/D3/KpiCard/index.styles.d.ts +108 -0
  27. package/dist/D3/KpiCard/index.styles.js +3 -0
  28. package/dist/D3/KpiCard/types.d.ts +16 -0
  29. package/dist/D3/LineChart/index.d.ts +2 -0
  30. package/dist/D3/LineChart/index.js +40 -0
  31. package/dist/D3/LineChart/types.d.ts +20 -0
  32. package/dist/D3/RadialBarChart/index.d.ts +2 -0
  33. package/dist/D3/RadialBarChart/index.js +34 -0
  34. package/dist/D3/RadialBarChart/types.d.ts +18 -0
  35. package/dist/D3/RelationshipDiagram/index.d.ts +3 -0
  36. package/dist/D3/RelationshipDiagram/index.js +34 -0
  37. package/dist/D3/RelationshipDiagram/index.styles.d.ts +66 -0
  38. package/dist/D3/RelationshipDiagram/index.styles.js +3 -0
  39. package/dist/D3/RelationshipDiagram/types.d.ts +25 -0
  40. package/dist/D3/SankeyChart/index.d.ts +2 -0
  41. package/dist/D3/SankeyChart/index.js +32 -0
  42. package/dist/D3/SankeyChart/types.d.ts +22 -0
  43. package/dist/D3/ScatterPlot/index.d.ts +2 -0
  44. package/dist/D3/ScatterPlot/index.js +39 -0
  45. package/dist/D3/ScatterPlot/scatterPlotUtils.d.ts +6 -0
  46. package/dist/D3/ScatterPlot/scatterPlotUtils.js +8 -0
  47. package/dist/D3/ScatterPlot/types.d.ts +17 -0
  48. package/dist/D3/SparklineChart/index.d.ts +2 -0
  49. package/dist/D3/SparklineChart/index.js +9 -0
  50. package/dist/D3/SparklineChart/index.styles.d.ts +35 -0
  51. package/dist/D3/SparklineChart/index.styles.js +3 -0
  52. package/dist/D3/SparklineChart/types.d.ts +14 -0
  53. package/dist/D3/StackedBarChart/index.d.ts +2 -0
  54. package/dist/D3/StackedBarChart/index.js +39 -0
  55. package/dist/D3/StackedBarChart/types.d.ts +17 -0
  56. package/dist/D3/TreemapChart/index.d.ts +2 -0
  57. package/dist/D3/TreemapChart/index.js +31 -0
  58. package/dist/D3/TreemapChart/types.d.ts +13 -0
  59. package/dist/D3/index.d.ts +43 -0
  60. package/dist/D3/shared/ChartFrame/index.d.ts +16 -0
  61. package/dist/D3/shared/ChartFrame/index.js +8 -0
  62. package/dist/D3/shared/ChartLegend/index.d.ts +3 -0
  63. package/dist/D3/shared/ChartLegend/index.js +7 -0
  64. package/dist/D3/shared/ChartLegend/types.d.ts +14 -0
  65. package/dist/D3/shared/ChartTooltip/index.d.ts +5 -0
  66. package/dist/D3/shared/ChartTooltip/index.js +7 -0
  67. package/dist/D3/shared/ChartTooltip/index.styles.d.ts +42 -0
  68. package/dist/D3/shared/ChartTooltip/index.styles.js +3 -0
  69. package/dist/D3/shared/Sparkline/index.d.ts +8 -0
  70. package/dist/D3/shared/Sparkline/index.js +18 -0
  71. package/dist/D3/shared/chartAxis.d.ts +16 -0
  72. package/dist/D3/shared/chartAxis.js +2 -0
  73. package/dist/D3/shared/chartAxisLayout/areaChart.d.ts +2 -0
  74. package/dist/D3/shared/chartAxisLayout/areaChart.js +2 -0
  75. package/dist/D3/shared/chartAxisLayout/barChart.d.ts +2 -0
  76. package/dist/D3/shared/chartAxisLayout/barChart.js +2 -0
  77. package/dist/D3/shared/chartAxisLayout/ganttTimeline.d.ts +2 -0
  78. package/dist/D3/shared/chartAxisLayout/ganttTimeline.js +2 -0
  79. package/dist/D3/shared/chartAxisLayout/heatmap.d.ts +8 -0
  80. package/dist/D3/shared/chartAxisLayout/heatmap.js +2 -0
  81. package/dist/D3/shared/chartAxisLayout/index.d.ts +9 -0
  82. package/dist/D3/shared/chartAxisLayout/lineChart.d.ts +2 -0
  83. package/dist/D3/shared/chartAxisLayout/lineChart.js +2 -0
  84. package/dist/D3/shared/chartAxisLayout/render.d.ts +8 -0
  85. package/dist/D3/shared/chartAxisLayout/render.js +11 -0
  86. package/dist/D3/shared/chartAxisLayout/scatterPlot.d.ts +2 -0
  87. package/dist/D3/shared/chartAxisLayout/scatterPlot.js +2 -0
  88. package/dist/D3/shared/chartAxisLayout/stackedBarChart.d.ts +2 -0
  89. package/dist/D3/shared/chartAxisLayout/stackedBarChart.js +2 -0
  90. package/dist/D3/shared/chartAxisLayout/types.d.ts +34 -0
  91. package/dist/D3/shared/chartBinding.d.ts +16 -0
  92. package/dist/D3/shared/chartBinding.js +1 -0
  93. package/dist/D3/shared/chartInteraction.d.ts +20 -0
  94. package/dist/D3/shared/chartInteraction.js +5 -0
  95. package/dist/D3/shared/chartTooltip.d.ts +20 -0
  96. package/dist/D3/shared/chartTooltip.js +2 -0
  97. package/dist/D3/shared/chartUtils.d.ts +11 -0
  98. package/dist/D3/shared/chartUtils.js +2 -0
  99. package/dist/D3/shared/chartVisualStyle.d.ts +24 -0
  100. package/dist/D3/shared/chartVisualStyle.js +10 -0
  101. package/dist/D3/shared/index.styles.d.ts +100 -0
  102. package/dist/D3/shared/index.styles.js +3 -0
  103. package/dist/D3/shared/useChartInteraction.d.ts +15 -0
  104. package/dist/D3/shared/useChartInteraction.js +17 -0
  105. package/dist/D3/shared/useChartLegendToggle.d.ts +6 -0
  106. package/dist/D3/shared/useChartLegendToggle.js +10 -0
  107. package/dist/index.d.ts +2 -0
  108. package/dist/index.js +35 -0
  109. package/dist/ioloco-charts.css +1 -0
  110. package/dist/tokens.stylex.d.ts +99 -0
  111. package/dist/tokens.stylex.js +3 -0
  112. package/package.json +135 -0
@@ -0,0 +1,2 @@
1
+ import type { AreaChartProps } from './types';
2
+ export declare function AreaChart({ series, title, description, height, compact, onPointClick }: Readonly<AreaChartProps>): import("react").JSX.Element;
@@ -0,0 +1,54 @@
1
+ "use client";
2
+ import{jsx as r}from"react/jsx-runtime"
3
+ import{useRef as t,useMemo as e,useEffect as o}from"react"
4
+ import{max as n}from"d3-array"
5
+ import{scalePoint as s,scaleLinear as i}from"d3-scale"
6
+ import{select as a,pointer as l}from"d3-selection"
7
+ import{area as c,line as h}from"d3-shape"
8
+ import{chartPalette as d}from"../../tokens.stylex.js"
9
+ import{ChartFrame as m}from"../shared/ChartFrame/index.js"
10
+ import{ChartLegend as u}from"../shared/ChartLegend/index.js"
11
+ import{areaChartAxisLayout as f}from"../shared/chartAxisLayout/areaChart.js"
12
+ import{renderXAxis as p,renderYAxis as $}from"../shared/chartAxisLayout/render.js"
13
+ import{chartFrameInteractionProps as g,chartPointerHandlers as v}from"../shared/chartBinding.js"
14
+ import{CHART_SERIES_CURVE as y,sanitizeGradientKey as j,appendAreaSeriesGradient as x,chartLineStrokeWidth as k,seriesDimOpacity as C}from"../shared/chartVisualStyle.js"
15
+ import{useChartInteraction as I}from"../shared/useChartInteraction.js"
16
+ import{useChartLegendToggle as w}from"../shared/useChartLegendToggle.js"
17
+ import{innerSize as b}from"../shared/chartUtils.js"
18
+ function L(r,t,e){if(0===r.length)return
19
+ let o=r[0],n=Infinity
20
+ for(const s of r){const r=e(s)??0,i=Math.abs(t-r)
21
+ i<n&&(n=i,o=s)}return o}function B(r,t,e){return`${r} · ${t}: ${e.toLocaleString()} CIs`}function M(r,t,e){const o=t.map(t=>{const o=t.points.find(t=>t.x===r)
22
+ if(!o)return null
23
+ const n=e.findIndex(r=>r.id===t.id)
24
+ return{color:t.color??d[n%d.length],label:t.id,value:`${o.y.toLocaleString()} CIs`}}).filter(r=>null!==r)
25
+ return{title:r,rows:o}}function q({series:q,title:A="Warranty expiries",description:P="Projected count of CIs reaching warranty end by quarter.",height:S=320,compact:T=!1,onPointClick:F}){const H=t(null),K=I("Hover the chart for the quarterly value."),R=t(F)
26
+ R.current=F
27
+ const U=e(()=>q.map(r=>r.id),[q]),{hiddenIds:V,visibleIds:W,toggle:z}=w(U),D=e(()=>q.filter(r=>W.includes(r.id)),[q,W])
28
+ o(()=>{const r=H.current
29
+ if(!r||0===D.length)return
30
+ const t=r.clientWidth||640,e=T?Math.min(S,280):S,o=f(T),m=o.margin,{width:u,height:g}=b(t,e,m),I=k(T),w=v(K),A=a(r)
31
+ A.selectAll("*").remove(),A.attr("viewBox",`0 0 ${t} ${e}`)
32
+ const P=A.append("g").attr("transform",`translate(${m.left},${m.top})`),F=A.append("defs"),U=D[0]?.points.map(r=>r.x)??[],V=s().domain(U).range([0,u]).padding(.5),W=i().domain([0,n(D,r=>n(r.points,r=>r.y)??0)??0]).nice().range([g,0])
33
+ p(P,V,g,o.x),$(P,W,o.y)
34
+ const z=c().x(r=>V(r.x)??0).y0(g).y1(r=>W(r.y)).curve(y),E=h().x(r=>V(r.x)??0).y(r=>W(r.y)).curve(y)
35
+ D.forEach((r,t)=>{const e=q.findIndex(t=>t.id===r.id),o=r.color??d[e%d.length],n=`area-gradient-${j(r.id)}`
36
+ x(F,n,o,T),P.append("path").datum(r.points).attr("class",`area-fill-${t}`).attr("fill",`url(#${n})`).attr("stroke","none").attr("d",z).attr("pointer-events","none"),P.append("path").datum(r.points).attr("class",`area-line-${t}`).attr("fill","none").attr("stroke",o).attr("stroke-width",I).attr("stroke-linecap","round").attr("stroke-linejoin","round").attr("d",E).attr("pointer-events","none")})
37
+ let G=null
38
+ const J=(r,t)=>{const e=L(U,r,V)
39
+ if(e)for(let r=D.length-1;r>=0;r-=1){const o=D[r],n=o.points.find(r=>r.x===e)
40
+ if(n&&(t>=W(n.y)&&t<=g))return{seriesKey:o.id,point:n}}},N=P.append("rect").attr("class","area-interaction-overlay").attr("x",0).attr("y",0).attr("width",u).attr("height",g).attr("fill","transparent").attr("pointer-events","all").attr("cursor","crosshair")
41
+ N.on("mousemove",r=>{const[t,e]=l(r,P.node()),o=J(t,e)
42
+ if(!o)return void(G&&(G=null,w.onHoverEnd()))
43
+ const n=`${o.seriesKey}:${o.point.x}`,s=B(o.seriesKey,o.point.x,o.point.y),i=M(o.point.x,D,q)
44
+ if(n!==G)return G=n,void w.onHover(n,s,r,i)
45
+ w.onPointerMove?.(r)}).on("mouseleave",()=>{G=null,w.onHoverEnd()}).on("click",r=>{const[t,e]=l(r,P.node()),o=J(t,e)
46
+ if(!o)return
47
+ const n=`${o.seriesKey}:${o.point.x}`,s=B(o.seriesKey,o.point.x,o.point.y)
48
+ w.onToggleSelect(n,s),R.current?.({seriesId:o.seriesKey,x:o.point.x,y:o.point.y})})
49
+ const O=K.registerFocusApply(()=>{const r=K.getHoverKey(),t=K.getSelectedKey()
50
+ D.forEach((e,o)=>{const n=e.id,s=!r&&!t||Boolean(r?.startsWith(`${n}:`))||Boolean(t?.startsWith(`${n}:`)),i=C(s)
51
+ P.select(`path.area-fill-${o}`).attr("opacity",i),P.select(`path.area-line-${o}`).attr("opacity",i)})})
52
+ return()=>{O(),N.on("mousemove mouseleave click",null)}},[T,S,K.getHoverKey,K.getSelectedKey,K.onHover,K.onHoverEnd,K.onPointerMove,K.onToggleSelect,K.registerFocusApply,q,D])
53
+ const E=e(()=>r(u,{ariaLabel:"Series",hiddenIds:V,onToggle:z,items:q.map((r,t)=>({id:r.id,label:r.id,color:r.color??d[t%d.length]}))}),[V,q,z])
54
+ return r(m,{title:A,description:P,height:T?Math.min(S,280):S,compact:T,...g(K),svgRef:H,legend:E})}export{q as AreaChart}
@@ -0,0 +1,20 @@
1
+ export type AreaSeries = {
2
+ id: string;
3
+ color?: string;
4
+ points: {
5
+ x: string;
6
+ y: number;
7
+ }[];
8
+ };
9
+ export type AreaChartProps = {
10
+ series: AreaSeries[];
11
+ title?: string;
12
+ description?: string;
13
+ height?: number;
14
+ compact?: boolean;
15
+ onPointClick?: (point: {
16
+ seriesId: string;
17
+ x: string;
18
+ y: number;
19
+ }) => void;
20
+ };
@@ -0,0 +1,3 @@
1
+ import 'd3-transition';
2
+ import type { BarChartProps } from './types';
3
+ export declare function BarChart({ data, title, description, height, compact, valueLabel, onDatumClick }: Readonly<BarChartProps>): import("react").JSX.Element;
@@ -0,0 +1,29 @@
1
+ "use client";
2
+ import{jsx as t}from"react/jsx-runtime"
3
+ import{useRef as r,useEffect as e}from"react"
4
+ import{max as o}from"d3-array"
5
+ import{scaleBand as i,scaleLinear as s}from"d3-scale"
6
+ import{select as a}from"d3-selection"
7
+ import"d3-transition"
8
+ import{chartPalette as n}from"../../tokens.stylex.js"
9
+ import{ChartFrame as m}from"../shared/ChartFrame/index.js"
10
+ import{barChartAxisLayout as c}from"../shared/chartAxisLayout/barChart.js"
11
+ import{renderXAxis as h,renderYAxis as d}from"../shared/chartAxisLayout/render.js"
12
+ import{chartFrameInteractionProps as l,chartPointerHandlers as p}from"../shared/chartBinding.js"
13
+ import{bindChartPointer as f,applyPointerOpacity as u}from"../shared/chartInteraction.js"
14
+ import{sanitizeGradientKey as g,appendBarSeriesGradient as y,SHAPE_STROKE_WIDTH as j}from"../shared/chartVisualStyle.js"
15
+ import{useChartInteraction as $}from"../shared/useChartInteraction.js"
16
+ import{innerSize as x}from"../shared/chartUtils.js"
17
+ function k({data:k,title:C="CIs by site",description:b="Count of registered configuration items per data centre site.",height:w=320,compact:v=!1,valueLabel:I="CIs",onDatumClick:F}){const L=r(null),A=$(`Vertical bars show ${I.toLowerCase()} per category.`),B=r(F)
18
+ return B.current=F,e(()=>{const t=L.current
19
+ if(!t)return
20
+ const r=t.clientWidth||640,e=v?Math.min(w,280):w,m=c(v),l=m.margin,{width:$,height:C}=x(r,e,l),b=n[0],F=`bar-gradient-${g(b)}`,M=a(t)
21
+ M.selectAll("*").remove(),M.attr("viewBox",`0 0 ${r} ${e}`)
22
+ const V=M.append("defs")
23
+ y(V,F,b,v)
24
+ const D=M.append("g").attr("transform",`translate(${l.left},${l.top})`),R=i().domain(k.map(t=>t.label)).range([0,$]).padding(.25),S=s().domain([0,o(k,t=>t.value)??0]).nice().range([C,0])
25
+ h(D,R,C,m.x),d(D,S,m.y)
26
+ const U=D.selectAll("rect").data(k).join("rect").attr("x",t=>R(t.label)??0).attr("width",R.bandwidth()).attr("y",C).attr("height",0).attr("fill",`url(#${F})`).attr("stroke",b).attr("stroke-width",j).attr("stroke-opacity",.35).attr("rx",4)
27
+ U.transition().duration(500).attr("y",t=>S(t.value)).attr("height",t=>C-S(t.value)),f(U,{keyFn:t=>t.label,hintFn:t=>`${t.label}: ${t.value.toLocaleString()} ${I}`,...p(A),onClick:t=>B.current?.(t)})
28
+ const q=A.registerFocusApply(()=>{u(U,t=>t.label,A.getFocusOpacity)})
29
+ return()=>{q(),U.on("mouseenter mouseleave click",null)}},[v,k,w,A.getFocusOpacity,A.onHover,A.onHoverEnd,A.onToggleSelect,A.registerFocusApply,I]),t(m,{title:C,description:b,height:v?Math.min(w,280):w,compact:v,...l(A),svgRef:L})}export{k as BarChart}
@@ -0,0 +1,13 @@
1
+ export type BarDatum = {
2
+ label: string;
3
+ value: number;
4
+ };
5
+ export type BarChartProps = {
6
+ data: BarDatum[];
7
+ title?: string;
8
+ description?: string;
9
+ height?: number;
10
+ compact?: boolean;
11
+ valueLabel?: string;
12
+ onDatumClick?: (datum: BarDatum) => void;
13
+ };
@@ -0,0 +1,2 @@
1
+ import type { DonutChartProps } from './types';
2
+ export declare function DonutChart({ data, title, description, height, compact, innerRadiusRatio, onDatumClick }: Readonly<DonutChartProps>): import("react").JSX.Element;
@@ -0,0 +1,35 @@
1
+ "use client";
2
+ import{jsx as t}from"react/jsx-runtime"
3
+ import{useRef as e,useMemo as r,useEffect as o}from"react"
4
+ import{sum as n}from"d3-array"
5
+ import{scaleOrdinal as s}from"d3-scale"
6
+ import{select as i}from"d3-selection"
7
+ import{pie as a,arc as d}from"d3-shape"
8
+ import{chartPalette as m}from"../../tokens.stylex.js"
9
+ import{ChartFrame as l}from"../shared/ChartFrame/index.js"
10
+ import{ChartLegend as c}from"../shared/ChartLegend/index.js"
11
+ import{chartFrameInteractionProps as h,chartPointerHandlers as f}from"../shared/chartBinding.js"
12
+ import{bindChartPointerLite as p}from"../shared/chartInteraction.js"
13
+ import{appendBarSeriesGradient as u,sanitizeGradientKey as g,chartSeriesStrokeColor as j}from"../shared/chartVisualStyle.js"
14
+ import{useChartInteraction as k}from"../shared/useChartInteraction.js"
15
+ import{useChartLegendToggle as x}from"../shared/useChartLegendToggle.js"
16
+ const C=.4,y=.75
17
+ function I({data:I,title:$="Asset class distribution",description:v="Registered CIs grouped by hardware class in the CMDB.",height:b=320,compact:M=!1,innerRadiusRatio:w=.58,onDatumClick:R}){const B=e(null),F=k("Hover a segment for details."),L=e(R)
18
+ L.current=R
19
+ const T=r(()=>I.map(t=>t.label),[I]),{hiddenIds:z,visibleIds:D,toggle:S}=x(T),A=r(()=>I.filter(t=>D.includes(t.label)),[I,D])
20
+ o(()=>{const t=B.current
21
+ if(!t||0===A.length)return
22
+ const e=t.clientWidth||480,r=M?Math.min(b,280):b,o=Math.min(e,r)/2-16,l=o*Math.min(y,Math.max(C,w)),c=i(t)
23
+ c.selectAll("*").remove(),c.attr("viewBox",`0 0 ${e} ${r}`)
24
+ const h=c.append("defs")
25
+ I.forEach((t,e)=>{if(!D.includes(t.label))return
26
+ const r=t.color??m[e%m.length]
27
+ u(h,`donut-${g(t.label)}`,r,M)})
28
+ const k=c.append("g").attr("transform",`translate(${e/2},${r/2})`),x=s().domain(I.map(t=>t.label)).range(I.map((t,e)=>t.color??m[e%m.length])),$=a().value(t=>t.value).sort(null).padAngle(.015),v=d().innerRadius(l).outerRadius(o),R=k.selectAll("path").data($(A)).join("path").attr("fill",t=>`url(#donut-${g(t.data.label)})`).attr("stroke",t=>x(t.data.label)).attr("stroke-width",M?2.5:3).attr("stroke-linejoin","round").attr("d",v)
29
+ p(R,{keyFn:t=>t.data.label,hintFn:t=>`${t.data.label}: ${t.data.value.toLocaleString()} CIs`,...f(F),onClick:t=>L.current?.(t.data)})
30
+ const T=F.registerFocusApply(()=>{const t=F.getHoverKey()
31
+ R.attr("opacity",t=>F.getFocusOpacity(t.data.label)).attr("stroke",e=>{const r=x(e.data.label)
32
+ return e.data.label===t?j(r):r}).attr("stroke-width",e=>e.data.label===t?M?3:3.5:M?2.5:3)}),z=n(A,t=>t.value)
33
+ return k.append("text").attr("text-anchor","middle").attr("dy","-0.2em").attr("font-size",M?18:22).attr("font-weight",700).attr("pointer-events","none").text(z.toLocaleString()),k.append("text").attr("text-anchor","middle").attr("dy","1.2em").attr("font-size",M?10:12).attr("fill","rgba(0,0,0,0.5)").attr("pointer-events","none").text("Total CIs"),()=>{T(),R.on("mouseenter mouseleave click",null)}},[M,I,b,w,F.getFocusOpacity,F.onHover,F.onHoverEnd,F.onPointerMove,F.onToggleSelect,F.registerFocusApply,A,D])
34
+ const H=r(()=>t(c,{ariaLabel:"Segments",hiddenIds:z,onToggle:S,items:I.map((t,e)=>({id:t.label,label:t.label,color:t.color??m[e%m.length]}))}),[I,z,S])
35
+ return t(l,{title:$,description:v,height:M?Math.min(b,280):b,compact:M,...h(F),svgRef:B,legend:H})}export{I as DonutChart}
@@ -0,0 +1,15 @@
1
+ export type DonutDatum = {
2
+ label: string;
3
+ value: number;
4
+ color?: string;
5
+ };
6
+ export type DonutChartProps = {
7
+ data: DonutDatum[];
8
+ title?: string;
9
+ description?: string;
10
+ height?: number;
11
+ compact?: boolean;
12
+ /** Hole size as a fraction of the outer radius. Clamped to keep a visible donut ring. */
13
+ innerRadiusRatio?: number;
14
+ onDatumClick?: (datum: DonutDatum) => void;
15
+ };
@@ -0,0 +1,2 @@
1
+ import type { FunnelChartProps } from './types';
2
+ export declare function FunnelChart({ data, title, description, height, compact, onStageClick }: Readonly<FunnelChartProps>): import("react").JSX.Element;
@@ -0,0 +1,27 @@
1
+ "use client";
2
+ import{jsx as t}from"react/jsx-runtime"
3
+ import{useRef as e,useEffect as r}from"react"
4
+ import{max as n}from"d3-array"
5
+ import{select as o}from"d3-selection"
6
+ import{chartPalette as s}from"../../tokens.stylex.js"
7
+ import{ChartFrame as i}from"../shared/ChartFrame/index.js"
8
+ import{chartFrameInteractionProps as a,chartPointerHandlers as c}from"../shared/chartBinding.js"
9
+ import{bindChartPointer as h,applyPointerOpacity as l}from"../shared/chartInteraction.js"
10
+ import{appendCenterWeightedGradient as m,sanitizeGradientKey as f,SHAPE_STROKE_WIDTH as d}from"../shared/chartVisualStyle.js"
11
+ import{useChartInteraction as u}from"../shared/useChartInteraction.js"
12
+ import{defaultMargin as p,innerSize as g}from"../shared/chartUtils.js"
13
+ function x({data:x,title:j="Change request funnel",description:k="Progression of CI change requests through approval stages this quarter.",height:y=340,compact:$=!1,onStageClick:v}){const C=e(null),w=u("Hover a stage for the count."),q=e(v)
14
+ return q.current=v,r(()=>{const t=C.current
15
+ if(!t)return
16
+ const e=t.clientWidth||520,r=$?Math.min(y,300):y,i={...p,left:120},{width:a,height:u}=g(e,r,i),j=o(t)
17
+ j.selectAll("*").remove(),j.attr("viewBox",`0 0 ${e} ${r}`)
18
+ const k=j.append("defs")
19
+ x.forEach((t,e)=>{const r=s[e%s.length]
20
+ m(k,`funnel-${f(t.label)}`,r,$)})
21
+ const v=j.append("g").attr("transform",`translate(${i.left},${i.top})`),F=n(x,t=>t.value)??0,I=u/x.length
22
+ x.forEach((t,e)=>{const r=t.value/F*a,n=(a-r)/2,o=e*I+4,i=s[e%s.length]
23
+ v.append("rect").attr("class","funnel-stage").attr("x",n).attr("y",o).attr("width",r).attr("height",I-8).attr("fill",`url(#funnel-${f(t.label)})`).attr("stroke",i).attr("stroke-width",d).attr("stroke-opacity",.35).attr("rx",6).datum(t),v.append("text").attr("x",-8).attr("y",o+(I-8)/2).attr("text-anchor","end").attr("dominant-baseline","middle").attr("font-size",11).attr("pointer-events","none").text(t.label),v.append("text").attr("x",n+r/2).attr("y",o+(I-8)/2).attr("text-anchor","middle").attr("dominant-baseline","middle").attr("font-size",12).attr("font-weight",600).attr("fill","#fff").attr("pointer-events","none").text(t.value)})
24
+ const b=v.selectAll("rect.funnel-stage")
25
+ h(b,{keyFn:t=>t.label,hintFn:t=>`${t.label}: ${t.value.toLocaleString()} requests`,...c(w),onClick:t=>q.current?.(t)})
26
+ const z=w.registerFocusApply(()=>{l(b,t=>t.label,w.getFocusOpacity)})
27
+ return()=>{z(),b.on("mouseenter mouseleave click",null)}},[$,x,y,w.getFocusOpacity,w.onHover,w.onHoverEnd,w.onPointerMove,w.onToggleSelect,w.registerFocusApply]),t(i,{title:j,description:k,height:$?Math.min(y,300):y,compact:$,...a(w),svgRef:C})}export{x as FunnelChart}
@@ -0,0 +1,12 @@
1
+ export type FunnelStage = {
2
+ label: string;
3
+ value: number;
4
+ };
5
+ export type FunnelChartProps = {
6
+ data: FunnelStage[];
7
+ title?: string;
8
+ description?: string;
9
+ height?: number;
10
+ compact?: boolean;
11
+ onStageClick?: (stage: FunnelStage) => void;
12
+ };
@@ -0,0 +1,2 @@
1
+ import type { GanttTimelineProps } from './types';
2
+ export declare function GanttTimeline({ tasks, title, description, height, compact, onTaskClick }: Readonly<GanttTimelineProps>): import("react").JSX.Element;
@@ -0,0 +1,36 @@
1
+ "use client";
2
+ import{jsx as t}from"react/jsx-runtime"
3
+ import{useRef as r,useMemo as e,useEffect as o}from"react"
4
+ import{extent as i}from"d3-array"
5
+ import{scaleTime as s,scaleBand as a,scaleOrdinal as n}from"d3-scale"
6
+ import{select as h}from"d3-selection"
7
+ import{timeParse as m,timeFormat as d}from"d3-time-format"
8
+ import{chartPalette as c}from"../../tokens.stylex.js"
9
+ import{ChartFrame as l}from"../shared/ChartFrame/index.js"
10
+ import{ChartLegend as f}from"../shared/ChartLegend/index.js"
11
+ import{ganttTimelineAxisLayout as p}from"../shared/chartAxisLayout/ganttTimeline.js"
12
+ import{renderXAxis as g,renderYAxis as u}from"../shared/chartAxisLayout/render.js"
13
+ import{chartFrameInteractionProps as j,chartPointerHandlers as k}from"../shared/chartBinding.js"
14
+ import{bindChartPointer as w,applyPointerOpacity as x}from"../shared/chartInteraction.js"
15
+ import{appendBarSeriesGradient as $,sanitizeGradientKey as y,SHAPE_STROKE_WIDTH as C}from"../shared/chartVisualStyle.js"
16
+ import{useChartInteraction as b}from"../shared/useChartInteraction.js"
17
+ import{useChartLegendToggle as v}from"../shared/useChartLegendToggle.js"
18
+ import{innerSize as I}from"../shared/chartUtils.js"
19
+ function L({tasks:L,title:O="Hardware change timeline",description:T="Scheduled maintenance and refresh windows for in-flight change records.",height:F=360,compact:M=!1,onTaskClick:S}){const A=r(null),B=b("Hover a bar for the change window."),D=r(S)
20
+ D.current=S
21
+ const H=e(()=>[...new Set(L.map(t=>t.group??"Other"))],[L]),{hiddenIds:G,visibleIds:R,toggle:U}=v(H),V=e(()=>H.filter(t=>R.includes(t)),[H,R]),Y=e(()=>L.filter(t=>V.includes(t.group??"Other")),[L,V])
22
+ o(()=>{const t=A.current
23
+ if(!t||0===Y.length)return
24
+ const r=t.clientWidth||720,e=M?Math.min(F,320):F,o=p(M),l=o.margin,{width:f,height:j}=I(r,e,l),b=m("%Y-%m-%d"),v=Y.map(t=>({...t,startDate:b(t.start),endDate:b(t.end)})).filter(t=>t.startDate&&t.endDate),L=h(t)
25
+ L.selectAll("*").remove(),L.attr("viewBox",`0 0 ${r} ${e}`)
26
+ const O=L.append("defs")
27
+ H.forEach((t,r)=>{const e=c[r%c.length]
28
+ $(O,`gantt-${y(t)}`,e,M)})
29
+ const T=L.append("g").attr("transform",`translate(${l.left},${l.top})`),S=s().domain(i(v.flatMap(t=>[t.startDate,t.endDate]))).range([0,f]),G=a().domain(v.map(t=>t.label)).range([0,j]).padding(.25),R=n().domain(H).range(H.map((t,r)=>c[r%c.length]))
30
+ g(T,S,j,o.x,t=>t.ticks(M?4:6).tickFormat(d("%d %b"))),u(T,G,o.y)
31
+ const U=T.selectAll("rect").data(v).join("rect").attr("x",t=>S(t.startDate)).attr("y",t=>G(t.label)??0).attr("width",t=>Math.max(4,S(t.endDate)-S(t.startDate))).attr("height",G.bandwidth()).attr("fill",t=>`url(#gantt-${y(t.group??"Other")})`).attr("stroke",t=>R(t.group??"Other")).attr("stroke-width",C).attr("stroke-opacity",.35).attr("rx",4)
32
+ w(U,{keyFn:t=>t.id,hintFn:t=>`${t.label}: ${t.start} → ${t.end}`,...k(B),onClick:t=>D.current?.(t)})
33
+ const V=B.registerFocusApply(()=>{x(U,t=>t.id,B.getFocusOpacity)})
34
+ return()=>{V(),U.on("mouseenter mouseleave click",null)}},[M,H,F,B.getFocusOpacity,B.onHover,B.onHoverEnd,B.onPointerMove,B.onToggleSelect,B.registerFocusApply,L,Y])
35
+ const q=e(()=>t(f,{ariaLabel:"Groups",hiddenIds:G,onToggle:U,items:H.map((t,r)=>({id:t,label:t,color:c[r%c.length]}))}),[H,G,U])
36
+ return t(l,{title:O,description:T,height:M?Math.min(F,320):F,compact:M,...j(B),svgRef:A,legend:q})}export{L as GanttTimeline}
@@ -0,0 +1,15 @@
1
+ export type GanttTask = {
2
+ id: string;
3
+ label: string;
4
+ group?: string;
5
+ start: string;
6
+ end: string;
7
+ };
8
+ export type GanttTimelineProps = {
9
+ tasks: GanttTask[];
10
+ title?: string;
11
+ description?: string;
12
+ height?: number;
13
+ compact?: boolean;
14
+ onTaskClick?: (task: GanttTask) => void;
15
+ };
@@ -0,0 +1,2 @@
1
+ import type { GaugeChartProps } from './types';
2
+ export declare function GaugeChart({ value, min, max, title, description, height, compact, label, unit, onClick }: Readonly<GaugeChartProps>): import("react").JSX.Element;
@@ -0,0 +1,22 @@
1
+ "use client";
2
+ import{jsx as t}from"react/jsx-runtime"
3
+ import{useRef as e,useEffect as o}from"react"
4
+ import{scaleLinear as r}from"d3-scale"
5
+ import{select as n}from"d3-selection"
6
+ import{arc as i}from"d3-shape"
7
+ import{chartPalette as a}from"../../tokens.stylex.js"
8
+ import{ChartFrame as s}from"../shared/ChartFrame/index.js"
9
+ import{chartFrameInteractionProps as m}from"../shared/chartBinding.js"
10
+ import{sanitizeGradientKey as l,appendArcSeriesGradient as c,chartLineStrokeWidth as h}from"../shared/chartVisualStyle.js"
11
+ import{useChartInteraction as p}from"../shared/useChartInteraction.js"
12
+ function f({value:f,min:u=0,max:d=100,title:g="CMDB completeness",description:x="Percentage of in-scope assets with a complete CI record.",height:$=260,compact:v=!1,label:M="Complete records",unit:b="%",onClick:y}){const k=e(null),C=p(`Current completeness: ${f}${b}.`),j=e(y)
13
+ return j.current=y,o(()=>{const t=k.current
14
+ if(!t)return
15
+ const e=t.clientWidth||420,o=v?Math.min($,220):$,s=Math.min(e,2*o)/2-12,m=`${M}: ${f}${b} (${u}–${d})`,p=n(t)
16
+ p.selectAll("*").remove(),p.attr("viewBox",`0 0 ${e} ${o}`)
17
+ const g=a[0],x=`gauge-${l(g)}`,y=p.append("defs")
18
+ c(y,x,g,v)
19
+ const w=p.append("g").attr("transform",`translate(${e/2},${o-8})`),z=r().domain([u,d]).range([-Math.PI/2,Math.PI/2]),B=i().innerRadius(.62*s).outerRadius(s).startAngle(-Math.PI/2).endAngle(Math.PI/2)
20
+ w.append("path").attr("d",B).attr("fill","rgba(0,0,0,0.08)")
21
+ const S=i().innerRadius(.62*s).outerRadius(s).startAngle(-Math.PI/2).endAngle(z(f)),I=w.append("path").attr("d",S).attr("fill",`url(#${x})`).attr("stroke",g).attr("stroke-width",h(v)).attr("stroke-linecap","round").attr("cursor","pointer").attr("role","button").attr("tabindex",0)
22
+ return I.on("mouseenter",t=>{I.attr("opacity",.85),C.onHover("gauge",m,t)}).on("mousemove",t=>{C.onPointerMove(t)}).on("mouseleave",()=>{I.attr("opacity",1),C.onHoverEnd()}).on("click",()=>{C.onToggleSelect("gauge",m),j.current?.({value:f,min:u,max:d,label:M})}),w.append("text").attr("text-anchor","middle").attr("y",.15*-s).attr("font-size",v?24:32).attr("font-weight",700).attr("pointer-events","none").text(`${f}${b}`),w.append("text").attr("text-anchor","middle").attr("y",.08*s).attr("font-size",12).attr("fill","rgba(0,0,0,0.5)").attr("pointer-events","none").text(M),w.append("text").attr("x",-s).attr("y",18).attr("font-size",11).attr("fill","rgba(0,0,0,0.45)").text(String(u)),w.append("text").attr("x",s).attr("y",18).attr("text-anchor","end").attr("font-size",11).attr("fill","rgba(0,0,0,0.45)").text(String(d)),()=>{I.on("mouseenter mousemove mouseleave click",null)}},[v,$,C.onHover,C.onHoverEnd,C.onPointerMove,C.onToggleSelect,M,d,u,b,f]),t(s,{title:g,description:x,height:v?Math.min($,220):$,compact:v,...m(C),svgRef:k})}export{f as GaugeChart}
@@ -0,0 +1,17 @@
1
+ export type GaugeChartProps = {
2
+ value: number;
3
+ min?: number;
4
+ max?: number;
5
+ title?: string;
6
+ description?: string;
7
+ height?: number;
8
+ compact?: boolean;
9
+ label?: string;
10
+ unit?: string;
11
+ onClick?: (payload: {
12
+ value: number;
13
+ min: number;
14
+ max: number;
15
+ label: string;
16
+ }) => void;
17
+ };
@@ -0,0 +1,28 @@
1
+ import type { Selection } from 'd3-selection';
2
+ export declare const AXIS_LABEL_STROKE = "#cbd5e1";
3
+ export declare const AXIS_TITLE_FILL = "#f3f4f6";
4
+ export declare function appendLabelBox(root: Selection<SVGGElement, unknown, null, undefined>, x: number, y: number, width: number, height: number, label: string, fontSize: number): void;
5
+ export declare function computeHeatmapLayout(rows: string[], columns: string[], innerWidth: number, innerHeight: number, compact: boolean): {
6
+ axisTitleSize: number;
7
+ rowLabelWidth: number;
8
+ colLabelHeight: number;
9
+ colLabelWidth: number;
10
+ cellGap: number;
11
+ cellSize: number;
12
+ gridWidth: number;
13
+ gridHeight: number;
14
+ gridX: number;
15
+ gridY: number;
16
+ columnLabelY: number;
17
+ columnTitleY: number;
18
+ rowLabelX: number;
19
+ titleFontSize: number;
20
+ labelFontSize: number;
21
+ columnLabelFontSize: number;
22
+ cellPosition: (row: string, column: string) => {
23
+ x: number;
24
+ y: number;
25
+ };
26
+ rowCenterY: (row: string) => number;
27
+ columnCenterX: (column: string) => number;
28
+ };
@@ -0,0 +1,11 @@
1
+ import{styleChartText as t,chartAxisColors as e}from"../shared/chartAxis.js"
2
+ import{heatmapAxisSpacing as i}from"../shared/chartAxisLayout/heatmap.js"
3
+ const o="#eef2f7",l="#cbd5e1",n="#f3f4f6"
4
+ function a(t,e,i=16){const o=.58*e
5
+ return Math.ceil(Math.max(...t.map(t=>t.length*o))+i)}function r(i,n,a,r,h,s,c){i.append("rect").attr("x",n).attr("y",a).attr("width",r).attr("height",h).attr("fill",o).attr("stroke",l).attr("stroke-width",1).attr("rx",2)
6
+ const d=s.split(/\s+/),b=d.length>1&&s.length>12?[d.slice(0,Math.ceil(d.length/2)).join(" "),d.slice(Math.ceil(d.length/2)).join(" ")]:[s],u=c+3,m=a+h/2-(b.length-1)*u/2,L=i.append("text").attr("x",n+r/2).attr("y",m).attr("text-anchor","middle").attr("dominant-baseline","middle").attr("pointer-events","none")
7
+ t(L,{size:c,weight:500,fill:e.title}),b.forEach((t,e)=>{L.append("tspan").attr("x",n+r/2).attr("dy",0===e?0:u).text(t)})}function h(t,e,o,l,n){const r=i(n,t.length,e.length),{axisTitleSize:h,rowLabelWidthMin:s,colLabelHeight:c,rowTitleToLabels:d,rowLabelsToGrid:b,gridToColumnLabels:u,columnLabelsToTitle:m,columnLabelInset:L,gridTop:M}=r,f=2,x=n?10:11,g=Math.max(s,a(t,n?11:12)),w=Math.max(a(e,x,14),c+6),p=Math.max(w,Math.floor(Math.min((o-h-d-g-b-(e.length-1)*f)/e.length,(l-M-(u+c+m+h)-(t.length-1)*f)/t.length,n?58:72))),T=e.length*p+(e.length-1)*f,z=t.length*p+(t.length-1)*f,S=h+d+g+b,y=M,W=Math.max(28,p-2*L),Y=new Map(e.map((t,e)=>[t,e])),C=new Map(t.map((t,e)=>[t,e]))
8
+ return{axisTitleSize:h,rowLabelWidth:g,colLabelHeight:c,colLabelWidth:W,cellGap:f,cellSize:p,gridWidth:T,gridHeight:z,gridX:S,gridY:y,columnLabelY:y+z+u,columnTitleY:y+z+u+c+m,rowLabelX:h+d,titleFontSize:n?11:12,labelFontSize:n?11:12,columnLabelFontSize:n?10:11,cellPosition(t,e){const i=Y.get(e)??0,o=C.get(t)??0
9
+ return{x:S+i*(p+f),y:y+o*(p+f)}},rowCenterY(t){const e=C.get(t)??0
10
+ return y+e*(p+f)+p/2},columnCenterX(t){const e=Y.get(t)??0
11
+ return S+e*(p+f)+p/2}}}export{l as AXIS_LABEL_STROKE,n as AXIS_TITLE_FILL,r as appendLabelBox,h as computeHeatmapLayout}
@@ -0,0 +1,2 @@
1
+ import type { HeatmapChartProps } from './types';
2
+ export declare function HeatmapChart({ data, rows, columns, title, description, height, compact, rowAxisLabel, columnAxisLabel, onCellClick }: Readonly<HeatmapChartProps>): import("react").JSX.Element;
@@ -0,0 +1,31 @@
1
+ "use client";
2
+ import{jsx as t}from"react/jsx-runtime"
3
+ import{useRef as e,useEffect as i}from"react"
4
+ import{extent as r}from"d3-array"
5
+ import{scaleQuantize as o}from"d3-scale"
6
+ import{select as n}from"d3-selection"
7
+ import{heatmapScale as l}from"../../tokens.stylex.js"
8
+ import{ChartFrame as a}from"../shared/ChartFrame/index.js"
9
+ import{styleAxisTitle as s,chartFontFamily as c,chartAxisColors as m}from"../shared/chartAxis.js"
10
+ import{heatmapChartMargin as h}from"../shared/chartAxisLayout/heatmap.js"
11
+ import{chartFrameInteractionProps as d,chartPointerHandlers as f}from"../shared/chartBinding.js"
12
+ import{bindChartPointer as u,applyPointerOpacity as p}from"../shared/chartInteraction.js"
13
+ import{useChartInteraction as x}from"../shared/useChartInteraction.js"
14
+ import{innerSize as g}from"../shared/chartUtils.js"
15
+ import{computeHeatmapLayout as y,AXIS_TITLE_FILL as w,AXIS_LABEL_STROKE as $,appendLabelBox as b}from"./heatmapLayout.js"
16
+ function L({data:L,rows:k,columns:j,title:C="Lifecycle by site",description:v="Server CI counts by lifecycle status and data centre site.",height:S=420,compact:z=!1,rowAxisLabel:F="Site",columnAxisLabel:I="Lifecycle status",onCellClick:A}){const Y=e(null),H=x("Hover a cell for the CI count."),M=e(A)
17
+ return M.current=A,i(()=>{const t=Y.current
18
+ if(!t)return
19
+ const e=t.clientWidth||640,i=z?Math.min(S,320):S,a=h(z),{width:d,height:x}=g(e,i,a),C=n(t)
20
+ C.selectAll("*").remove(),C.attr("viewBox",`0 0 ${e} ${i}`)
21
+ const v=C.append("g").attr("transform",`translate(${a.left},${a.top})`),A=y(k,j,d,x,z),{axisTitleSize:W,rowLabelWidth:X,colLabelHeight:B,colLabelWidth:T,cellSize:P,gridX:R,gridY:U,gridWidth:q,gridHeight:D,columnLabelY:E,columnTitleY:G,rowLabelX:J,titleFontSize:K,labelFontSize:N,columnLabelFontSize:O,cellPosition:Q,rowCenterY:V,columnCenterX:Z}=A,_=r(L,t=>t.value),tt=o().domain(_).range([...l]),et=t=>{const e=tt.range().indexOf(tt(t))
22
+ return e<0?0:e/Math.max(1,tt.range().length-1)}
23
+ v.append("rect").attr("x",0).attr("y",U).attr("width",W).attr("height",D).attr("fill",w).attr("stroke",$).attr("stroke-width",1)
24
+ const it=v.append("text").attr("transform",`translate(${W/2}, ${U+D/2}) rotate(-90)`).attr("text-anchor","middle").attr("dominant-baseline","middle").attr("letter-spacing","0.06em").text(F.toUpperCase())
25
+ s(it,K).attr("font-weight",700),k.forEach(t=>{b(v,J,V(t)-B/2,X,B,t,N)}),j.forEach(t=>{b(v,Z(t)-T/2,E,T,B,t,O)}),v.append("rect").attr("x",R).attr("y",G).attr("width",q).attr("height",W).attr("fill",w).attr("stroke",$).attr("stroke-width",1)
26
+ const rt=v.append("text").attr("x",R+q/2).attr("y",G+W/2).attr("text-anchor","middle").attr("dominant-baseline","middle").attr("letter-spacing","0.06em").text(I.toUpperCase())
27
+ s(rt,K).attr("font-weight",700)
28
+ const ot=v.selectAll("rect.cell").data(L).join("rect").attr("class","cell").attr("x",t=>Q(t.row,t.column).x).attr("y",t=>Q(t.row,t.column).y).attr("width",P).attr("height",P).attr("fill",t=>tt(t.value)).attr("stroke","#fff").attr("stroke-width",2)
29
+ u(ot,{keyFn:t=>`${t.row}:${t.column}`,hintFn:t=>`${t.row} · ${t.column}: ${t.value.toLocaleString()} CIs`,...f(H),onClick:t=>M.current?.(t)})
30
+ const nt=v.selectAll("text.value").data(L).join("text").attr("class","value").attr("x",t=>Q(t.row,t.column).x+P/2).attr("y",t=>Q(t.row,t.column).y+P/2).attr("text-anchor","middle").attr("dominant-baseline","middle").attr("font-family",c).attr("font-size",z?14:16).attr("font-weight",700).attr("fill",t=>et(t.value)>=.5?"#fff":m.title).style("user-select","none").attr("pointer-events","none").text(t=>t.value),lt=H.registerFocusApply(()=>{p(ot,t=>`${t.row}:${t.column}`,H.getFocusOpacity),nt.attr("opacity",t=>1===H.getFocusOpacity(`${t.row}:${t.column}`)?1:.55)})
31
+ return()=>{lt(),ot.on("mouseenter mouseleave click",null)}},[I,j,z,L,S,H.getFocusOpacity,H.onHover,H.onHoverEnd,H.onPointerMove,H.onToggleSelect,H.registerFocusApply,F,k]),t(a,{title:C,description:v,height:z?Math.min(S,320):S,compact:z,...d(H),svgRef:Y})}export{L as HeatmapChart}
@@ -0,0 +1,17 @@
1
+ export type HeatmapCell = {
2
+ row: string;
3
+ column: string;
4
+ value: number;
5
+ };
6
+ export type HeatmapChartProps = {
7
+ data: HeatmapCell[];
8
+ rows: string[];
9
+ columns: string[];
10
+ title?: string;
11
+ description?: string;
12
+ height?: number;
13
+ compact?: boolean;
14
+ rowAxisLabel?: string;
15
+ columnAxisLabel?: string;
16
+ onCellClick?: (cell: HeatmapCell) => void;
17
+ };
@@ -0,0 +1,2 @@
1
+ import type { KpiCardProps } from './types';
2
+ export declare function KpiCard({ metrics, title, description, compact, onMetricClick }: Readonly<KpiCardProps>): import("react").JSX.Element;
@@ -0,0 +1,12 @@
1
+ "use client";
2
+ import{jsxs as e,jsx as n}from"react/jsx-runtime"
3
+ import*as o from"@stylexjs/stylex"
4
+ import{chartPalette as r}from"../../tokens.stylex.js"
5
+ import{ChartTooltip as i}from"../shared/ChartTooltip/index.js"
6
+ import{useChartInteraction as t}from"../shared/useChartInteraction.js"
7
+ import{Sparkline as l}from"../shared/Sparkline/index.js"
8
+ import{styles as c}from"./index.styles.js"
9
+ function d(e){const n=`${e.value.toLocaleString()}${e.unit?` ${e.unit}`:""}`
10
+ return void 0===e.delta?`${e.label}\n${n}`:`${e.label}\n${n}\n${e.delta>=0?"+":""}${e.delta}% ${e.deltaLabel??""}`}function s({metric:i,index:t,isHovered:d,isSelected:s,onHover:a,onPointerMove:m,onHoverEnd:u,onToggleSelect:v,onClick:h}){const p=i.delta,f=void 0===p?c.deltaNeutral:p>=0?c.deltaUp:c.deltaDown,$=void 0===p?"":p>=0?"+":""
11
+ return e("article",{...o.props(c.card,c.cardInteractive,d?c.cardHovered:null,s?c.cardSelected:null),"aria-label":i.label,role:"button",tabIndex:0,onMouseEnter:a,onMouseMove:m,onMouseLeave:u,onClick(){v(),h?.(i)},onKeyDown(e){"Enter"!==e.key&&" "!==e.key||(e.preventDefault(),v(),h?.(i))},children:[n("span",{...o.props(c.label),children:i.label}),e("div",{...o.props(c.valueRow),children:[n("span",{...o.props(c.value),children:i.value.toLocaleString()}),i.unit?n("span",{...o.props(c.unit),children:i.unit}):null]}),void 0!==p?e("span",{...o.props(f),children:[$,p,"% ",i.deltaLabel??""]}):null,i.sparkline?n(l,{values:i.sparkline,color:r[t%r.length]}):null]})}function a({metrics:r,title:l="CMDB KPIs",description:a="Headline configuration management metrics with recent trend.",compact:m=!1,onMetricClick:u}){const v=t("Hover a KPI card for details.")
12
+ return e("div",{...o.props(c.root),children:[e("div",{...o.props(c.header),children:[n("h4",{...o.props(c.headerTitle),children:l}),m?null:n("p",{...o.props(c.headerDescription),children:a})]}),e("div",{ref:v.setTooltipContainer,...o.props(c.grid,c.gridRelative,m?c.gridCompact:null),children:[r.map((e,o)=>n(s,{metric:e,index:o,isHovered:v.getHoverKey()===e.id,isSelected:v.getSelectedKey()===e.id,onHover:n=>v.onHover(e.id,d(e),n.nativeEvent),onPointerMove:e=>v.onPointerMove(e.nativeEvent),onHoverEnd:v.onHoverEnd,onToggleSelect:()=>v.onToggleSelect(e.id,`${e.label}: ${e.value.toLocaleString()}`),onClick:u},e.id)),n(i,{tooltip:v.tooltip})]}),n("span",{...o.props(c.footerHint,v.isPinned?c.footerHintPinned:null),children:v.hint})]})}export{a as KpiCard}
@@ -0,0 +1,108 @@
1
+ import * as stylex from '@stylexjs/stylex';
2
+ export declare const styles: Readonly<{
3
+ readonly root: Readonly<{
4
+ readonly display: stylex.StyleXClassNameFor<"display", "flex">;
5
+ readonly flexDirection: stylex.StyleXClassNameFor<"flexDirection", "column">;
6
+ readonly gap: stylex.StyleXClassNameFor<"gap", "1.2rem">;
7
+ readonly width: stylex.StyleXClassNameFor<"width", "100%">;
8
+ }>;
9
+ readonly header: Readonly<{
10
+ readonly display: stylex.StyleXClassNameFor<"display", "flex">;
11
+ readonly flexDirection: stylex.StyleXClassNameFor<"flexDirection", "column">;
12
+ readonly gap: stylex.StyleXClassNameFor<"gap", "0.4rem">;
13
+ }>;
14
+ readonly headerTitle: Readonly<{
15
+ readonly fontSize: stylex.StyleXClassNameFor<"fontSize", "1.8rem">;
16
+ readonly fontWeight: stylex.StyleXClassNameFor<"fontWeight", "600">;
17
+ readonly lineHeight: stylex.StyleXClassNameFor<"lineHeight", "1.2">;
18
+ readonly margin: stylex.StyleXClassNameFor<"margin", 0>;
19
+ }>;
20
+ readonly headerDescription: Readonly<{
21
+ readonly fontSize: stylex.StyleXClassNameFor<"fontSize", "1.3rem">;
22
+ readonly color: stylex.StyleXClassNameFor<"color", string>;
23
+ readonly margin: stylex.StyleXClassNameFor<"margin", 0>;
24
+ }>;
25
+ readonly grid: Readonly<{
26
+ readonly display: stylex.StyleXClassNameFor<"display", "grid">;
27
+ readonly gridTemplateColumns: stylex.StyleXClassNameFor<"gridTemplateColumns", "repeat(auto-fit, minmax(18rem, 1fr))">;
28
+ readonly gap: stylex.StyleXClassNameFor<"gap", "1.2rem">;
29
+ }>;
30
+ readonly gridRelative: Readonly<{
31
+ readonly position: stylex.StyleXClassNameFor<"position", "relative">;
32
+ }>;
33
+ readonly gridCompact: Readonly<{
34
+ readonly gridTemplateColumns: stylex.StyleXClassNameFor<"gridTemplateColumns", "1fr">;
35
+ readonly gap: stylex.StyleXClassNameFor<"gap", "0.8rem">;
36
+ }>;
37
+ readonly card: Readonly<{
38
+ readonly display: stylex.StyleXClassNameFor<"display", "flex">;
39
+ readonly flexDirection: stylex.StyleXClassNameFor<"flexDirection", "column">;
40
+ readonly gap: stylex.StyleXClassNameFor<"gap", "0.8rem">;
41
+ readonly padding: stylex.StyleXClassNameFor<"padding", "1.6rem">;
42
+ readonly borderWidth: stylex.StyleXClassNameFor<"borderWidth", "1px">;
43
+ readonly borderStyle: stylex.StyleXClassNameFor<"borderStyle", "solid">;
44
+ readonly borderColor: stylex.StyleXClassNameFor<"borderColor", string>;
45
+ readonly borderRadius: stylex.StyleXClassNameFor<"borderRadius", "0.8rem">;
46
+ readonly backgroundColor: stylex.StyleXClassNameFor<"backgroundColor", string>;
47
+ }>;
48
+ readonly cardInteractive: Readonly<{
49
+ readonly cursor: stylex.StyleXClassNameFor<"cursor", "pointer">;
50
+ readonly transitionProperty: stylex.StyleXClassNameFor<"transitionProperty", "box-shadow, transform">;
51
+ readonly transitionDuration: stylex.StyleXClassNameFor<"transitionDuration", "0.15s">;
52
+ readonly transitionTimingFunction: stylex.StyleXClassNameFor<"transitionTimingFunction", "ease">;
53
+ }>;
54
+ readonly cardHovered: Readonly<{
55
+ readonly borderColor: stylex.StyleXClassNameFor<"borderColor", string>;
56
+ readonly boxShadow: stylex.StyleXClassNameFor<"boxShadow", "0 4px 14px rgba(0, 0, 0, 0.08)">;
57
+ }>;
58
+ readonly cardSelected: Readonly<{
59
+ readonly borderColor: stylex.StyleXClassNameFor<"borderColor", string>;
60
+ readonly boxShadow: stylex.StyleXClassNameFor<"boxShadow", "0 0 0 2px rgba(0, 0, 0, 0.08)">;
61
+ }>;
62
+ readonly label: Readonly<{
63
+ readonly fontSize: stylex.StyleXClassNameFor<"fontSize", "1.2rem">;
64
+ readonly color: stylex.StyleXClassNameFor<"color", string>;
65
+ readonly fontWeight: stylex.StyleXClassNameFor<"fontWeight", "500">;
66
+ }>;
67
+ readonly valueRow: Readonly<{
68
+ readonly display: stylex.StyleXClassNameFor<"display", "flex">;
69
+ readonly alignItems: stylex.StyleXClassNameFor<"alignItems", "baseline">;
70
+ readonly gap: stylex.StyleXClassNameFor<"gap", "0.4rem">;
71
+ }>;
72
+ readonly value: Readonly<{
73
+ readonly fontSize: stylex.StyleXClassNameFor<"fontSize", "2.4rem">;
74
+ readonly fontWeight: stylex.StyleXClassNameFor<"fontWeight", "700">;
75
+ readonly lineHeight: stylex.StyleXClassNameFor<"lineHeight", "1.1">;
76
+ }>;
77
+ readonly unit: Readonly<{
78
+ readonly fontSize: stylex.StyleXClassNameFor<"fontSize", "1.3rem">;
79
+ readonly color: stylex.StyleXClassNameFor<"color", string>;
80
+ }>;
81
+ readonly deltaUp: Readonly<{
82
+ readonly fontSize: stylex.StyleXClassNameFor<"fontSize", "1.2rem">;
83
+ readonly color: stylex.StyleXClassNameFor<"color", string>;
84
+ readonly fontWeight: stylex.StyleXClassNameFor<"fontWeight", "600">;
85
+ }>;
86
+ readonly deltaDown: Readonly<{
87
+ readonly fontSize: stylex.StyleXClassNameFor<"fontSize", "1.2rem">;
88
+ readonly color: stylex.StyleXClassNameFor<"color", string>;
89
+ readonly fontWeight: stylex.StyleXClassNameFor<"fontWeight", "600">;
90
+ }>;
91
+ readonly deltaNeutral: Readonly<{
92
+ readonly fontSize: stylex.StyleXClassNameFor<"fontSize", "1.2rem">;
93
+ readonly color: stylex.StyleXClassNameFor<"color", string>;
94
+ }>;
95
+ readonly sparkline: Readonly<{
96
+ readonly width: stylex.StyleXClassNameFor<"width", "100%">;
97
+ readonly height: stylex.StyleXClassNameFor<"height", "3.2rem">;
98
+ readonly display: stylex.StyleXClassNameFor<"display", "block">;
99
+ }>;
100
+ readonly footerHint: Readonly<{
101
+ readonly fontSize: stylex.StyleXClassNameFor<"fontSize", "1.2rem">;
102
+ readonly color: stylex.StyleXClassNameFor<"color", string>;
103
+ }>;
104
+ readonly footerHintPinned: Readonly<{
105
+ readonly color: stylex.StyleXClassNameFor<"color", string>;
106
+ readonly fontWeight: stylex.StyleXClassNameFor<"fontWeight", "500">;
107
+ }>;
108
+ }>;
@@ -0,0 +1,3 @@
1
+ import"@stylexjs/stylex"
2
+ const k={root:{k1xSpc:"_78zum5",kXwgrk:"_dt5ytf",kOIVth:"_bhn5rf",kzqmXN:"_h8yej3",$$css:!0},header:{k1xSpc:"_78zum5",kXwgrk:"_dt5ytf",kOIVth:"_1neeqzj",$$css:!0},headerTitle:{kGuDYH:"_1elmx46",k63SB2:"_1s688f",kLWn49:"_1u7k74",kogj98:"_1ghz6dp",$$css:!0},headerDescription:{kGuDYH:"_1xebwwb",kMwMTN:"_qdq3cf",kogj98:"_1ghz6dp",$$css:!0},grid:{k1xSpc:"_rvj5dj",kumcoG:"_19vp1m2",kOIVth:"_bhn5rf",$$css:!0},gridRelative:{kVAEAm:"_1n2onr6",$$css:!0},gridCompact:{kumcoG:"_1y6fwsi",kOIVth:"_1rq4zhh",$$css:!0},card:{k1xSpc:"_78zum5",kXwgrk:"_dt5ytf",kOIVth:"_1rq4zhh",kmVPX3:"_qo3fwf",kMzoRj:"_mkeg23",ksu8eU:"_1y0btm7",kVAM5u:"_1yf9t2n",kaIpWk:"_1o5ta1t",kWkggS:"_1a1xyot",$$css:!0},cardInteractive:{kkrTdU:"_1ypdohk",k1ekBW:"_hd6ntr",kIyJzY:"_x6bhzk",kAMwcw:"_wji4o3",$$css:!0},cardHovered:{kVAM5u:"_45n503",kGVxlE:"_14nb6pt",$$css:!0},cardSelected:{kVAM5u:"_45n503",kGVxlE:"_1rvjved",$$css:!0},label:{kGuDYH:"_vewgow",kMwMTN:"_qdq3cf",k63SB2:"_k50ysn",$$css:!0},valueRow:{k1xSpc:"_78zum5",kGNEyG:"_1pha0wt",kOIVth:"_1neeqzj",$$css:!0},value:{kGuDYH:"_19orhxu",k63SB2:"_1xlr1w8",kLWn49:"_1159mfc",$$css:!0},unit:{kGuDYH:"_1xebwwb",kMwMTN:"_qdq3cf",$$css:!0},deltaUp:{kGuDYH:"_vewgow",kMwMTN:"_5zgiyw",k63SB2:"_1s688f",$$css:!0},deltaDown:{kGuDYH:"_vewgow",kMwMTN:"_67euey",k63SB2:"_1s688f",$$css:!0},deltaNeutral:{kGuDYH:"_vewgow",kMwMTN:"_qdq3cf",$$css:!0},footerHint:{kGuDYH:"_vewgow",kMwMTN:"_qdq3cf",$$css:!0},footerHintPinned:{kMwMTN:"_4iqcr8",k63SB2:"_k50ysn",$$css:!0}}
3
+ export{k as styles}
@@ -0,0 +1,16 @@
1
+ export type KpiMetric = {
2
+ id: string;
3
+ label: string;
4
+ value: number;
5
+ unit?: string;
6
+ delta?: number;
7
+ deltaLabel?: string;
8
+ sparkline?: number[];
9
+ };
10
+ export type KpiCardProps = {
11
+ metrics: KpiMetric[];
12
+ title?: string;
13
+ description?: string;
14
+ compact?: boolean;
15
+ onMetricClick?: (metric: KpiMetric) => void;
16
+ };
@@ -0,0 +1,2 @@
1
+ import type { LineChartProps } from './types';
2
+ export declare function LineChart({ series, title, description, height, compact, onPointClick }: Readonly<LineChartProps>): import("react").JSX.Element;