ioloco-charts 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/D3/AreaChart/index.d.ts +1 -1
  2. package/dist/D3/AreaChart/index.js +44 -43
  3. package/dist/D3/AreaChart/types.d.ts +2 -0
  4. package/dist/D3/BarChart/index.d.ts +1 -1
  5. package/dist/D3/BarChart/index.js +28 -27
  6. package/dist/D3/BarChart/types.d.ts +3 -0
  7. package/dist/D3/DonutChart/index.d.ts +1 -1
  8. package/dist/D3/DonutChart/index.js +26 -25
  9. package/dist/D3/DonutChart/types.d.ts +5 -0
  10. package/dist/D3/FunnelChart/index.d.ts +1 -1
  11. package/dist/D3/FunnelChart/index.js +20 -19
  12. package/dist/D3/FunnelChart/types.d.ts +2 -0
  13. package/dist/D3/GanttTimeline/index.d.ts +1 -1
  14. package/dist/D3/GanttTimeline/index.js +21 -21
  15. package/dist/D3/GanttTimeline/types.d.ts +1 -0
  16. package/dist/D3/GaugeChart/index.d.ts +1 -1
  17. package/dist/D3/GaugeChart/index.js +15 -15
  18. package/dist/D3/GaugeChart/types.d.ts +1 -0
  19. package/dist/D3/HeatmapChart/index.d.ts +1 -1
  20. package/dist/D3/HeatmapChart/index.js +26 -25
  21. package/dist/D3/HeatmapChart/types.d.ts +2 -0
  22. package/dist/D3/LineChart/index.js +30 -30
  23. package/dist/D3/RadialBarChart/index.d.ts +1 -1
  24. package/dist/D3/RadialBarChart/index.js +27 -27
  25. package/dist/D3/RadialBarChart/types.d.ts +1 -0
  26. package/dist/D3/RelationshipDiagram/index.js +20 -20
  27. package/dist/D3/SankeyChart/index.d.ts +1 -1
  28. package/dist/D3/SankeyChart/index.js +24 -23
  29. package/dist/D3/SankeyChart/types.d.ts +2 -0
  30. package/dist/D3/ScatterPlot/index.d.ts +1 -1
  31. package/dist/D3/ScatterPlot/index.js +25 -25
  32. package/dist/D3/ScatterPlot/types.d.ts +1 -0
  33. package/dist/D3/SparklineChart/index.js +5 -5
  34. package/dist/D3/StackedBarChart/index.d.ts +1 -1
  35. package/dist/D3/StackedBarChart/index.js +30 -29
  36. package/dist/D3/StackedBarChart/types.d.ts +2 -0
  37. package/dist/D3/TreemapChart/index.d.ts +1 -1
  38. package/dist/D3/TreemapChart/index.js +23 -22
  39. package/dist/D3/TreemapChart/types.d.ts +2 -0
  40. package/dist/D3/index.d.ts +0 -2
  41. package/dist/D3/shared/chartLabels.d.ts +2 -0
  42. package/dist/D3/shared/chartLabels.js +2 -0
  43. package/dist/index.js +0 -1
  44. package/dist/ioloco-charts.css +1 -1
  45. package/package.json +1 -1
  46. package/dist/D3/KpiCard/index.d.ts +0 -2
  47. package/dist/D3/KpiCard/index.js +0 -12
  48. package/dist/D3/KpiCard/index.styles.d.ts +0 -108
  49. package/dist/D3/KpiCard/index.styles.js +0 -3
  50. package/dist/D3/KpiCard/types.d.ts +0 -16
@@ -1,2 +1,2 @@
1
1
  import type { AreaChartProps } from './types';
2
- export declare function AreaChart({ series, title, description, height, compact, onPointClick }: Readonly<AreaChartProps>): import("react").JSX.Element;
2
+ export declare function AreaChart({ series, title, description, height, compact, valueLabel, hoverHint, onPointClick }: Readonly<AreaChartProps>): import("react").JSX.Element;
@@ -5,50 +5,51 @@ import{max as n}from"d3-array"
5
5
  import{scalePoint as s,scaleLinear as i}from"d3-scale"
6
6
  import{select as a,pointer as l}from"d3-selection"
7
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"
8
+ import{chartPalette as m}from"../../tokens.stylex.js"
9
+ import{ChartFrame as d}from"../shared/ChartFrame/index.js"
10
+ import{ChartLegend as f}from"../shared/ChartLegend/index.js"
11
+ import{areaChartAxisLayout as u}from"../shared/chartAxisLayout/areaChart.js"
12
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
13
+ import{chartFrameInteractionProps as v,chartPointerHandlers as g}from"../shared/chartBinding.js"
14
+ import{CHART_SERIES_CURVE as j,sanitizeGradientKey as y,appendAreaSeriesGradient as x,chartLineStrokeWidth as k,seriesDimOpacity as L}from"../shared/chartVisualStyle.js"
15
+ import{useChartInteraction as b}from"../shared/useChartInteraction.js"
16
+ import{formatChartValue as C}from"../shared/chartLabels.js"
17
+ import{useChartLegendToggle as I}from"../shared/useChartLegendToggle.js"
18
+ import{innerSize as w}from"../shared/chartUtils.js"
19
+ function B(r,t,e){if(0===r.length)return
19
20
  let o=r[0],n=Infinity
20
21
  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)
22
+ i<n&&(n=i,o=s)}return o}function A(r,t,e,o){return`${r} · ${t}: ${C(e,o)}`}function M(r,t,e,o){const n=t.map(t=>{const n=t.points.find(t=>t.x===r)
23
+ if(!n)return null
24
+ const s=e.findIndex(r=>r.id===t.id)
25
+ return{color:t.color??m[s%m.length],label:t.id,value:C(n.y,o)}}).filter(r=>null!==r)
26
+ return{title:r,rows:n}}function H({series:C,title:H="Area chart",description:S,height:T=320,compact:F=!1,valueLabel:K,hoverHint:P="Hover the chart for values.",onPointClick:R}){const U=t(null),V=b(P),q=t(R)
27
+ q.current=R
28
+ const z=e(()=>C.map(r=>r.id),[C]),{hiddenIds:D,visibleIds:E,toggle:G}=I(z),J=e(()=>C.filter(r=>E.includes(r.id)),[C,E])
29
+ o(()=>{const r=U.current
30
+ if(!r||0===J.length)return
31
+ const t=r.clientWidth||640,e=F?Math.min(T,280):T,o=u(F),d=o.margin,{width:f,height:v}=w(t,e,d),b=k(F),I=g(V),H=a(r)
32
+ H.selectAll("*").remove(),H.attr("viewBox",`0 0 ${t} ${e}`)
33
+ const S=H.append("g").attr("transform",`translate(${d.left},${d.top})`),P=H.append("defs"),R=J[0]?.points.map(r=>r.x)??[],z=s().domain(R).range([0,f]).padding(.5),D=i().domain([0,n(J,r=>n(r.points,r=>r.y)??0)??0]).nice().range([v,0])
34
+ p(S,z,v,o.x),$(S,D,o.y)
35
+ const E=c().x(r=>z(r.x)??0).y0(v).y1(r=>D(r.y)).curve(j),G=h().x(r=>z(r.x)??0).y(r=>D(r.y)).curve(j)
36
+ J.forEach((r,t)=>{const e=C.findIndex(t=>t.id===r.id),o=r.color??m[e%m.length],n=`area-gradient-${y(r.id)}`
37
+ x(P,n,o,F),S.append("path").datum(r.points).attr("class",`area-fill-${t}`).attr("fill",`url(#${n})`).attr("stroke","none").attr("d",E).attr("pointer-events","none"),S.append("path").datum(r.points).attr("class",`area-line-${t}`).attr("fill","none").attr("stroke",o).attr("stroke-width",b).attr("stroke-linecap","round").attr("stroke-linejoin","round").attr("d",G).attr("pointer-events","none")})
38
+ let N=null
39
+ const O=(r,t)=>{const e=B(R,r,z)
40
+ if(e)for(let r=J.length-1;r>=0;r-=1){const o=J[r],n=o.points.find(r=>r.x===e)
41
+ if(n&&(t>=D(n.y)&&t<=v))return{seriesKey:o.id,point:n}}},Q=S.append("rect").attr("class","area-interaction-overlay").attr("x",0).attr("y",0).attr("width",f).attr("height",v).attr("fill","transparent").attr("pointer-events","all").attr("cursor","crosshair")
42
+ Q.on("mousemove",r=>{const[t,e]=l(r,S.node()),o=O(t,e)
43
+ if(!o)return void(N&&(N=null,I.onHoverEnd()))
44
+ const n=`${o.seriesKey}:${o.point.x}`,s=A(o.seriesKey,o.point.x,o.point.y,K),i=M(o.point.x,J,C,K)
45
+ if(n!==N)return N=n,void I.onHover(n,s,r,i)
46
+ I.onPointerMove?.(r)}).on("mouseleave",()=>{N=null,I.onHoverEnd()}).on("click",r=>{const[t,e]=l(r,S.node()),o=O(t,e)
46
47
  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}
48
+ const n=`${o.seriesKey}:${o.point.x}`,s=A(o.seriesKey,o.point.x,o.point.y,K)
49
+ I.onToggleSelect(n,s),q.current?.({seriesId:o.seriesKey,x:o.point.x,y:o.point.y})})
50
+ const W=V.registerFocusApply(()=>{const r=V.getHoverKey(),t=V.getSelectedKey()
51
+ J.forEach((e,o)=>{const n=e.id,s=!r&&!t||Boolean(r?.startsWith(`${n}:`))||Boolean(t?.startsWith(`${n}:`)),i=L(s)
52
+ S.select(`path.area-fill-${o}`).attr("opacity",i),S.select(`path.area-line-${o}`).attr("opacity",i)})})
53
+ return()=>{W(),Q.on("mousemove mouseleave click",null)}},[F,T,V.getHoverKey,V.getSelectedKey,V.onHover,V.onHoverEnd,V.onPointerMove,V.onToggleSelect,V.registerFocusApply,P,C,K,J])
54
+ const N=e(()=>r(f,{ariaLabel:"Series",hiddenIds:D,onToggle:G,items:C.map((r,t)=>({id:r.id,label:r.id,color:r.color??m[t%m.length]}))}),[D,C,G])
55
+ return r(d,{title:H,description:S,height:F?Math.min(T,280):T,compact:F,...v(V),svgRef:U,legend:N})}export{H as AreaChart}
@@ -12,6 +12,8 @@ export type AreaChartProps = {
12
12
  description?: string;
13
13
  height?: number;
14
14
  compact?: boolean;
15
+ valueLabel?: string;
16
+ hoverHint?: string;
15
17
  onPointClick?: (point: {
16
18
  seriesId: string;
17
19
  x: string;
@@ -1,3 +1,3 @@
1
1
  import 'd3-transition';
2
2
  import type { BarChartProps } from './types';
3
- export declare function BarChart({ data, title, description, height, compact, valueLabel, onDatumClick }: Readonly<BarChartProps>): import("react").JSX.Element;
3
+ export declare function BarChart({ data, title, description, height, compact, valueLabel, hoverHint, onDatumClick }: Readonly<BarChartProps>): import("react").JSX.Element;
@@ -1,29 +1,30 @@
1
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"
2
+ import{jsx as r}from"react/jsx-runtime"
3
+ import{useRef as t,useEffect as o}from"react"
4
+ import{max as e}from"d3-array"
5
+ import{scaleBand as i,scaleLinear as a}from"d3-scale"
6
+ import{select as s}from"d3-selection"
7
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}
8
+ import{chartPalette as m}from"../../tokens.stylex.js"
9
+ import{ChartFrame as n}from"../shared/ChartFrame/index.js"
10
+ import{barChartAxisLayout as h}from"../shared/chartAxisLayout/barChart.js"
11
+ import{renderXAxis as c,renderYAxis as d}from"../shared/chartAxisLayout/render.js"
12
+ import{chartFrameInteractionProps as l,chartPointerHandlers as f}from"../shared/chartBinding.js"
13
+ import{bindChartPointer as p,applyPointerOpacity as u}from"../shared/chartInteraction.js"
14
+ import{formatChartHint as j}from"../shared/chartLabels.js"
15
+ import{sanitizeGradientKey as g,appendBarSeriesGradient as x,SHAPE_STROKE_WIDTH as y}from"../shared/chartVisualStyle.js"
16
+ import{useChartInteraction as k}from"../shared/useChartInteraction.js"
17
+ import{innerSize as v}from"../shared/chartUtils.js"
18
+ function $({data:$,title:b="Bar chart",description:C,height:w=320,compact:L=!1,valueLabel:B,hoverHint:F="Hover a bar for details.",onDatumClick:A}){const H=t(null),I=k(F),M=t(A)
19
+ return M.current=A,o(()=>{const r=H.current
20
+ if(!r)return
21
+ const t=r.clientWidth||640,o=L?Math.min(w,280):w,n=h(L),l=n.margin,{width:k,height:b}=v(t,o,l),C=m[0],F=`bar-gradient-${g(C)}`,A=s(r)
22
+ A.selectAll("*").remove(),A.attr("viewBox",`0 0 ${t} ${o}`)
23
+ const D=A.append("defs")
24
+ x(D,F,C,L)
25
+ const R=A.append("g").attr("transform",`translate(${l.left},${l.top})`),S=i().domain($.map(r=>r.label)).range([0,k]).padding(.25),U=a().domain([0,e($,r=>r.value)??0]).nice().range([b,0])
26
+ c(R,S,b,n.x),d(R,U,n.y)
27
+ const V=R.selectAll("rect").data($).join("rect").attr("x",r=>S(r.label)??0).attr("width",S.bandwidth()).attr("y",b).attr("height",0).attr("fill",`url(#${F})`).attr("stroke",C).attr("stroke-width",y).attr("stroke-opacity",.35).attr("rx",4)
28
+ V.transition().duration(500).attr("y",r=>U(r.value)).attr("height",r=>b-U(r.value)),p(V,{keyFn:r=>r.label,hintFn:r=>j(r.label,r.value,B),...f(I),onClick:r=>M.current?.(r)})
29
+ const q=I.registerFocusApply(()=>{u(V,r=>r.label,I.getFocusOpacity)})
30
+ return()=>{q(),V.on("mouseenter mouseleave click",null)}},[L,$,w,I.getFocusOpacity,I.onHover,I.onHoverEnd,I.onToggleSelect,I.registerFocusApply,F,B]),r(n,{title:b,description:C,height:L?Math.min(w,280):w,compact:L,...l(I),svgRef:H})}export{$ as BarChart}
@@ -8,6 +8,9 @@ export type BarChartProps = {
8
8
  description?: string;
9
9
  height?: number;
10
10
  compact?: boolean;
11
+ /** Suffix for values in hover hints, e.g. "containers" or "CIs". */
11
12
  valueLabel?: string;
13
+ /** Initial interaction hint below the chart. */
14
+ hoverHint?: string;
12
15
  onDatumClick?: (datum: BarDatum) => void;
13
16
  };
@@ -1,2 +1,2 @@
1
1
  import type { DonutChartProps } from './types';
2
- export declare function DonutChart({ data, title, description, height, compact, innerRadiusRatio, onDatumClick }: Readonly<DonutChartProps>): import("react").JSX.Element;
2
+ export declare function DonutChart({ data, title, description, height, compact, innerRadiusRatio, valueLabel, totalLabel, hoverHint, onDatumClick }: Readonly<DonutChartProps>): import("react").JSX.Element;
@@ -2,34 +2,35 @@
2
2
  import{jsx as t}from"react/jsx-runtime"
3
3
  import{useRef as e,useMemo as r,useEffect as o}from"react"
4
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"
5
+ import{scaleOrdinal as i}from"d3-scale"
6
+ import{select as s}from"d3-selection"
7
+ import{pie as a,arc as m}from"d3-shape"
8
+ import{chartPalette as d}from"../../tokens.stylex.js"
9
9
  import{ChartFrame as l}from"../shared/ChartFrame/index.js"
10
10
  import{ChartLegend as c}from"../shared/ChartLegend/index.js"
11
11
  import{chartFrameInteractionProps as h,chartPointerHandlers as f}from"../shared/chartBinding.js"
12
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)
13
+ import{formatChartHint as u}from"../shared/chartLabels.js"
14
+ import{appendBarSeriesGradient as g,sanitizeGradientKey as j,chartSeriesStrokeColor as k}from"../shared/chartVisualStyle.js"
15
+ import{useChartInteraction as x}from"../shared/useChartInteraction.js"
16
+ import{useChartLegendToggle as v}from"../shared/useChartLegendToggle.js"
17
+ const b=.4,y=.75
18
+ function C({data:C,title:L="Donut chart",description:$,height:I=320,compact:M=!1,innerRadiusRatio:w=.58,valueLabel:F,totalLabel:R,hoverHint:z="Hover a segment for details.",onDatumClick:B}){const D=e(null),H=x(z),S=e(B)
19
+ S.current=B
20
+ const T=r(()=>C.map(t=>t.label),[C]),{hiddenIds:V,visibleIds:q,toggle:A}=v(T),E=r(()=>C.filter(t=>q.includes(t.label)),[C,q])
21
+ o(()=>{const t=D.current
22
+ if(!t||0===E.length)return
23
+ const e=t.clientWidth||480,r=M?Math.min(I,280):I,o=Math.min(e,r)/2-16,l=o*Math.min(y,Math.max(b,w)),c=s(t)
23
24
  c.selectAll("*").remove(),c.attr("viewBox",`0 0 ${e} ${r}`)
24
25
  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}
26
+ C.forEach((t,e)=>{if(!q.includes(t.label))return
27
+ const r=t.color??d[e%d.length]
28
+ g(h,`donut-${j(t.label)}`,r,M)})
29
+ const x=c.append("g").attr("transform",`translate(${e/2},${r/2})`),v=i().domain(C.map(t=>t.label)).range(C.map((t,e)=>t.color??d[e%d.length])),L=a().value(t=>t.value).sort(null).padAngle(.015),$=m().innerRadius(l).outerRadius(o),z=x.selectAll("path").data(L(E)).join("path").attr("fill",t=>`url(#donut-${j(t.data.label)})`).attr("stroke",t=>v(t.data.label)).attr("stroke-width",M?2.5:3).attr("stroke-linejoin","round").attr("d",$)
30
+ p(z,{keyFn:t=>t.data.label,hintFn:t=>u(t.data.label,t.data.value,F),...f(H),onClick:t=>S.current?.(t.data)})
31
+ const B=H.registerFocusApply(()=>{const t=H.getHoverKey()
32
+ z.attr("opacity",t=>H.getFocusOpacity(t.data.label)).attr("stroke",e=>{const r=v(e.data.label)
33
+ return e.data.label===t?k(r):r}).attr("stroke-width",e=>e.data.label===t?M?3:3.5:M?2.5:3)}),T=n(E,t=>t.value)
34
+ return x.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(T.toLocaleString()),R&&x.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(R),()=>{B(),z.on("mouseenter mouseleave click",null)}},[M,C,I,w,H.getFocusOpacity,H.onHover,H.onHoverEnd,H.onPointerMove,H.onToggleSelect,H.registerFocusApply,z,R,F,E,q])
35
+ const G=r(()=>t(c,{ariaLabel:"Segments",hiddenIds:V,onToggle:A,items:C.map((t,e)=>({id:t.label,label:t.label,color:t.color??d[e%d.length]}))}),[C,V,A])
36
+ return t(l,{title:L,description:$,height:M?Math.min(I,280):I,compact:M,...h(H),svgRef:D,legend:G})}export{C as DonutChart}
@@ -11,5 +11,10 @@ export type DonutChartProps = {
11
11
  compact?: boolean;
12
12
  /** Hole size as a fraction of the outer radius. Clamped to keep a visible donut ring. */
13
13
  innerRadiusRatio?: number;
14
+ /** Suffix for values in hover hints, e.g. "items". */
15
+ valueLabel?: string;
16
+ /** Label under the centre total; omitted when not set. */
17
+ totalLabel?: string;
18
+ hoverHint?: string;
14
19
  onDatumClick?: (datum: DonutDatum) => void;
15
20
  };
@@ -1,2 +1,2 @@
1
1
  import type { FunnelChartProps } from './types';
2
- export declare function FunnelChart({ data, title, description, height, compact, onStageClick }: Readonly<FunnelChartProps>): import("react").JSX.Element;
2
+ export declare function FunnelChart({ data, title, description, height, compact, valueLabel, hoverHint, onStageClick }: Readonly<FunnelChartProps>): import("react").JSX.Element;
@@ -3,25 +3,26 @@ import{jsx as t}from"react/jsx-runtime"
3
3
  import{useRef as e,useEffect as r}from"react"
4
4
  import{max as n}from"d3-array"
5
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"
6
+ import{chartPalette as i}from"../../tokens.stylex.js"
7
+ import{ChartFrame as s}from"../shared/ChartFrame/index.js"
8
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"
9
+ import{bindChartPointer as l,applyPointerOpacity as m}from"../shared/chartInteraction.js"
10
+ import{formatChartHint as h}from"../shared/chartLabels.js"
11
+ import{appendCenterWeightedGradient as f,sanitizeGradientKey as d,SHAPE_STROKE_WIDTH as p}from"../shared/chartVisualStyle.js"
11
12
  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
13
+ import{defaultMargin as x,innerSize as g}from"../shared/chartUtils.js"
14
+ function j({data:j,title:k="Funnel chart",description:v,height:y=340,compact:$=!1,valueLabel:w,hoverHint:b="Hover a stage for details.",onStageClick:C}){const F=e(null),z=u(b),B=e(C)
15
+ return B.current=C,r(()=>{const t=F.current
15
16
  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}
17
+ const e=t.clientWidth||520,r=$?Math.min(y,300):y,s={...x,left:120},{width:a,height:u}=g(e,r,s),k=o(t)
18
+ k.selectAll("*").remove(),k.attr("viewBox",`0 0 ${e} ${r}`)
19
+ const v=k.append("defs")
20
+ j.forEach((t,e)=>{const r=i[e%i.length]
21
+ f(v,`funnel-${d(t.label)}`,r,$)})
22
+ const b=k.append("g").attr("transform",`translate(${s.left},${s.top})`),C=n(j,t=>t.value)??0,H=u/j.length
23
+ j.forEach((t,e)=>{const r=t.value/C*a,n=(a-r)/2,o=e*H+4,s=i[e%i.length]
24
+ b.append("rect").attr("class","funnel-stage").attr("x",n).attr("y",o).attr("width",r).attr("height",H-8).attr("fill",`url(#funnel-${d(t.label)})`).attr("stroke",s).attr("stroke-width",p).attr("stroke-opacity",.35).attr("rx",6).datum(t),b.append("text").attr("x",-8).attr("y",o+(H-8)/2).attr("text-anchor","end").attr("dominant-baseline","middle").attr("font-size",11).attr("pointer-events","none").text(t.label),b.append("text").attr("x",n+r/2).attr("y",o+(H-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)})
25
+ const I=b.selectAll("rect.funnel-stage")
26
+ l(I,{keyFn:t=>t.label,hintFn:t=>h(t.label,t.value,w),...c(z),onClick:t=>B.current?.(t)})
27
+ const L=z.registerFocusApply(()=>{m(I,t=>t.label,z.getFocusOpacity)})
28
+ return()=>{L(),I.on("mouseenter mouseleave click",null)}},[$,j,y,z.getFocusOpacity,z.onHover,z.onHoverEnd,z.onPointerMove,z.onToggleSelect,z.registerFocusApply,b,w]),t(s,{title:k,description:v,height:$?Math.min(y,300):y,compact:$,...a(z),svgRef:F})}export{j as FunnelChart}
@@ -8,5 +8,7 @@ export type FunnelChartProps = {
8
8
  description?: string;
9
9
  height?: number;
10
10
  compact?: boolean;
11
+ valueLabel?: string;
12
+ hoverHint?: string;
11
13
  onStageClick?: (stage: FunnelStage) => void;
12
14
  };
@@ -1,2 +1,2 @@
1
1
  import type { GanttTimelineProps } from './types';
2
- export declare function GanttTimeline({ tasks, title, description, height, compact, onTaskClick }: Readonly<GanttTimelineProps>): import("react").JSX.Element;
2
+ export declare function GanttTimeline({ tasks, title, description, height, compact, hoverHint, onTaskClick }: Readonly<GanttTimelineProps>): import("react").JSX.Element;
@@ -3,34 +3,34 @@ import{jsx as t}from"react/jsx-runtime"
3
3
  import{useRef as r,useMemo as e,useEffect as o}from"react"
4
4
  import{extent as i}from"d3-array"
5
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"
6
+ import{select as m}from"d3-selection"
7
+ import{timeParse as h,timeFormat as d}from"d3-time-format"
8
8
  import{chartPalette as c}from"../../tokens.stylex.js"
9
9
  import{ChartFrame as l}from"../shared/ChartFrame/index.js"
10
10
  import{ChartLegend as f}from"../shared/ChartLegend/index.js"
11
11
  import{ganttTimelineAxisLayout as p}from"../shared/chartAxisLayout/ganttTimeline.js"
12
12
  import{renderXAxis as g,renderYAxis as u}from"../shared/chartAxisLayout/render.js"
13
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"
14
+ import{bindChartPointer as x,applyPointerOpacity as $}from"../shared/chartInteraction.js"
15
+ import{appendBarSeriesGradient as y,sanitizeGradientKey as v,SHAPE_STROKE_WIDTH as C}from"../shared/chartVisualStyle.js"
16
16
  import{useChartInteraction as b}from"../shared/useChartInteraction.js"
17
- import{useChartLegendToggle as v}from"../shared/useChartLegendToggle.js"
17
+ import{useChartLegendToggle as w}from"../shared/useChartLegendToggle.js"
18
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)
19
+ function L({tasks:L,title:O="Gantt timeline",description:T,height:F=360,compact:M=!1,hoverHint:A="Hover a bar for details.",onTaskClick:B}){const D=r(null),G=b(A),H=r(B)
20
+ H.current=B
21
+ const S=e(()=>[...new Set(L.map(t=>t.group??"Other"))],[L]),{hiddenIds:R,visibleIds:U,toggle:V}=w(S),Y=e(()=>S.filter(t=>U.includes(t)),[S,U]),q=e(()=>L.filter(t=>Y.includes(t.group??"Other")),[L,Y])
22
+ o(()=>{const t=D.current
23
+ if(!t||0===q.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=h("%Y-%m-%d"),w=q.map(t=>({...t,startDate:b(t.start),endDate:b(t.end)})).filter(t=>t.startDate&&t.endDate),L=m(t)
25
25
  L.selectAll("*").remove(),L.attr("viewBox",`0 0 ${r} ${e}`)
26
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}
27
+ S.forEach((t,r)=>{const e=c[r%c.length]
28
+ y(O,`gantt-${v(t)}`,e,M)})
29
+ const T=L.append("g").attr("transform",`translate(${l.left},${l.top})`),A=s().domain(i(w.flatMap(t=>[t.startDate,t.endDate]))).range([0,f]),B=a().domain(w.map(t=>t.label)).range([0,j]).padding(.25),R=n().domain(S).range(S.map((t,r)=>c[r%c.length]))
30
+ g(T,A,j,o.x,t=>t.ticks(M?4:6).tickFormat(d("%d %b"))),u(T,B,o.y)
31
+ const U=T.selectAll("rect").data(w).join("rect").attr("x",t=>A(t.startDate)).attr("y",t=>B(t.label)??0).attr("width",t=>Math.max(4,A(t.endDate)-A(t.startDate))).attr("height",B.bandwidth()).attr("fill",t=>`url(#gantt-${v(t.group??"Other")})`).attr("stroke",t=>R(t.group??"Other")).attr("stroke-width",C).attr("stroke-opacity",.35).attr("rx",4)
32
+ x(U,{keyFn:t=>t.id,hintFn:t=>`${t.label}: ${t.start} → ${t.end}`,...k(G),onClick:t=>H.current?.(t)})
33
+ const V=G.registerFocusApply(()=>{$(U,t=>t.id,G.getFocusOpacity)})
34
+ return()=>{V(),U.on("mouseenter mouseleave click",null)}},[M,S,F,G.getFocusOpacity,G.onHover,G.onHoverEnd,G.onPointerMove,G.onToggleSelect,G.registerFocusApply,L,q])
35
+ const z=e(()=>t(f,{ariaLabel:"Groups",hiddenIds:R,onToggle:V,items:S.map((t,r)=>({id:t,label:t,color:c[r%c.length]}))}),[S,R,V])
36
+ return t(l,{title:O,description:T,height:M?Math.min(F,320):F,compact:M,...j(G),svgRef:D,legend:z})}export{L as GanttTimeline}
@@ -11,5 +11,6 @@ export type GanttTimelineProps = {
11
11
  description?: string;
12
12
  height?: number;
13
13
  compact?: boolean;
14
+ hoverHint?: string;
14
15
  onTaskClick?: (task: GanttTask) => void;
15
16
  };
@@ -1,2 +1,2 @@
1
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;
2
+ export declare function GaugeChart({ value, min, max, title, description, height, compact, label, unit, hoverHint, onClick }: Readonly<GaugeChartProps>): import("react").JSX.Element;
@@ -2,21 +2,21 @@
2
2
  import{jsx as t}from"react/jsx-runtime"
3
3
  import{useRef as e,useEffect as o}from"react"
4
4
  import{scaleLinear as r}from"d3-scale"
5
- import{select as n}from"d3-selection"
6
- import{arc as i}from"d3-shape"
5
+ import{select as i}from"d3-selection"
6
+ import{arc as n}from"d3-shape"
7
7
  import{chartPalette as a}from"../../tokens.stylex.js"
8
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
9
+ import{chartFrameInteractionProps as l}from"../shared/chartBinding.js"
10
+ import{sanitizeGradientKey as m,appendArcSeriesGradient as c,chartLineStrokeWidth as h}from"../shared/chartVisualStyle.js"
11
+ import{useChartInteraction as u}from"../shared/useChartInteraction.js"
12
+ function f({value:f,min:p=0,max:d=100,title:g="Gauge chart",description:x,height:$=260,compact:v=!1,label:b="Value",unit:y="%",hoverHint:M,onClick:k}){const j=e(null),z=u(M??`${b}: ${f}${y}.`),w=e(k)
13
+ return w.current=k,o(()=>{const t=j.current
14
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}
15
+ const e=t.clientWidth||420,o=v?Math.min($,220):$,s=Math.min(e,2*o)/2-12,l=`${b}: ${f}${y} (${p}–${d})`,u=i(t)
16
+ u.selectAll("*").remove(),u.attr("viewBox",`0 0 ${e} ${o}`)
17
+ const g=a[0],x=`gauge-${m(g)}`,M=u.append("defs")
18
+ c(M,x,g,v)
19
+ const k=u.append("g").attr("transform",`translate(${e/2},${o-8})`),C=r().domain([p,d]).range([-Math.PI/2,Math.PI/2]),S=n().innerRadius(.62*s).outerRadius(s).startAngle(-Math.PI/2).endAngle(Math.PI/2)
20
+ k.append("path").attr("d",S).attr("fill","rgba(0,0,0,0.08)")
21
+ const B=n().innerRadius(.62*s).outerRadius(s).startAngle(-Math.PI/2).endAngle(C(f)),V=k.append("path").attr("d",B).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 V.on("mouseenter",t=>{V.attr("opacity",.85),z.onHover("gauge",l,t)}).on("mousemove",t=>{z.onPointerMove(t)}).on("mouseleave",()=>{V.attr("opacity",1),z.onHoverEnd()}).on("click",()=>{z.onToggleSelect("gauge",l),w.current?.({value:f,min:p,max:d,label:b})}),k.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}${y}`),k.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(b),k.append("text").attr("x",-s).attr("y",18).attr("font-size",11).attr("fill","rgba(0,0,0,0.45)").text(String(p)),k.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)),()=>{V.on("mouseenter mousemove mouseleave click",null)}},[v,$,z.onHover,z.onHoverEnd,z.onPointerMove,z.onToggleSelect,b,d,p,y,f]),t(s,{title:g,description:x,height:v?Math.min($,220):$,compact:v,...l(z),svgRef:j})}export{f as GaugeChart}
@@ -8,6 +8,7 @@ export type GaugeChartProps = {
8
8
  compact?: boolean;
9
9
  label?: string;
10
10
  unit?: string;
11
+ hoverHint?: string;
11
12
  onClick?: (payload: {
12
13
  value: number;
13
14
  min: number;
@@ -1,2 +1,2 @@
1
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;
2
+ export declare function HeatmapChart({ data, rows, columns, title, description, height, compact, rowAxisLabel, columnAxisLabel, valueLabel, hoverHint, onCellClick }: Readonly<HeatmapChartProps>): import("react").JSX.Element;