ioloco-charts 0.2.1 → 0.2.2

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.
@@ -2,7 +2,7 @@
2
2
  import{jsx as r}from"react/jsx-runtime"
3
3
  import{useRef as t,useEffect as o}from"react"
4
4
  import{max as e}from"d3-array"
5
- import{scaleBand as i,scaleLinear as a}from"d3-scale"
5
+ import{scaleBand as a,scaleLinear as i}from"d3-scale"
6
6
  import{select as s}from"d3-selection"
7
7
  import"d3-transition"
8
8
  import{chartPalette as m}from"../../tokens.stylex.js"
@@ -12,19 +12,20 @@ import{renderXAxis as c,renderYAxis as d}from"../shared/chartAxisLayout/render.j
12
12
  import{chartFrameInteractionProps as l,chartPointerHandlers as f}from"../shared/chartBinding.js"
13
13
  import{bindChartPointer as p,applyPointerOpacity as u}from"../shared/chartInteraction.js"
14
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"
15
+ import{appendBarSeriesGradient as x,sanitizeGradientKey as y,SHAPE_STROKE_WIDTH as g}from"../shared/chartVisualStyle.js"
16
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)
17
+ import{innerSize as b}from"../shared/chartUtils.js"
18
+ function v({data:v,title:$="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
19
  return M.current=A,o(()=>{const r=H.current
20
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}
21
+ const t=r.clientWidth||640,o=L?Math.min(w,280):w,n=h(L),l=n.margin,{width:k,height:$}=b(t,o,l),C=s(r)
22
+ C.selectAll("*").remove(),C.attr("viewBox",`0 0 ${t} ${o}`)
23
+ const F=C.append("defs")
24
+ v.forEach((r,t)=>{const o=r.color??m[t%m.length]
25
+ x(F,`bar-${y(r.label)}`,o,L)})
26
+ const A=C.append("g").attr("transform",`translate(${l.left},${l.top})`),D=a().domain(v.map(r=>r.label)).range([0,k]).padding(.25),R=i().domain([0,e(v,r=>r.value)??0]).nice().range([$,0])
27
+ c(A,D,$,n.x),d(A,R,n.y)
28
+ const S=A.selectAll("rect").data(v).join("rect").attr("x",r=>D(r.label)??0).attr("width",D.bandwidth()).attr("y",$).attr("height",0).attr("fill",r=>`url(#bar-${y(r.label)})`).attr("stroke",(r,t)=>r.color??m[t%m.length]).attr("stroke-width",g).attr("stroke-opacity",.35).attr("rx",4)
29
+ S.transition().duration(500).attr("y",r=>R(r.value)).attr("height",r=>$-R(r.value)),p(S,{keyFn:r=>r.label,hintFn:r=>j(r.label,r.value,B),...f(I),onClick:r=>M.current?.(r)})
30
+ const U=I.registerFocusApply(()=>{u(S,r=>r.label,I.getFocusOpacity)})
31
+ return()=>{U(),S.on("mouseenter mouseleave click",null)}},[L,v,w,I.getFocusOpacity,I.onHover,I.onHoverEnd,I.onToggleSelect,I.registerFocusApply,F,B]),r(n,{title:$,description:C,height:L?Math.min(w,280):w,compact:L,...l(I),svgRef:H})}export{v as BarChart}
@@ -1,6 +1,7 @@
1
1
  export type BarDatum = {
2
2
  label: string;
3
3
  value: number;
4
+ color?: string;
4
5
  };
5
6
  export type BarChartProps = {
6
7
  data: BarDatum[];
@@ -1,2 +1,2 @@
1
1
  import type { StackedBarChartProps } from './types';
2
- export declare function StackedBarChart({ data, seriesKeys, title, description, height, compact, valueLabel, hoverHint, onSegmentClick }: Readonly<StackedBarChartProps>): import("react").JSX.Element;
2
+ export declare function StackedBarChart({ data, seriesKeys, seriesColors, title, description, height, compact, valueLabel, hoverHint, onSegmentClick }: Readonly<StackedBarChartProps>): import("react").JSX.Element;
@@ -1,40 +1,40 @@
1
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{max as s}from"d3-array"
5
- import{scaleBand as a,scaleLinear as i,scaleOrdinal as n}from"d3-scale"
6
- import{select as c}from"d3-selection"
7
- import{stack as m}from"d3-shape"
2
+ import{jsx as r}from"react/jsx-runtime"
3
+ import{useRef as e,useMemo as t,useCallback as o,useEffect as s}from"react"
4
+ import{max as a}from"d3-array"
5
+ import{scaleBand as i,scaleLinear as n,scaleOrdinal as c}from"d3-scale"
6
+ import{select as m}from"d3-selection"
7
+ import{stack as l}from"d3-shape"
8
8
  import{chartPalette as d}from"../../tokens.stylex.js"
9
9
  import{ChartFrame as h}from"../shared/ChartFrame/index.js"
10
- import{ChartLegend as l}from"../shared/ChartLegend/index.js"
11
- import{renderXAxis as f,renderYAxis as p}from"../shared/chartAxisLayout/render.js"
12
- import{stackedBarChartAxisLayout as g}from"../shared/chartAxisLayout/stackedBarChart.js"
13
- import{chartFrameInteractionProps as u,chartPointerHandlers as j}from"../shared/chartBinding.js"
14
- import{bindChartPointer as k,applyPointerOpacity as y}from"../shared/chartInteraction.js"
15
- import{formatChartHint as $}from"../shared/chartLabels.js"
16
- import{useChartInteraction as b}from"../shared/useChartInteraction.js"
17
- import{useChartLegendToggle as x}from"../shared/useChartLegendToggle.js"
18
- import{innerSize as v}from"../shared/chartUtils.js"
19
- import{appendBarSeriesGradient as C,sanitizeGradientKey as L,SHAPE_STROKE_WIDTH as w}from"../shared/chartVisualStyle.js"
20
- function I(t){const r=new Set
21
- for(const e of t)for(const t of Object.keys(e.segments))r.add(t)
22
- return[...r]}function S({data:S,seriesKeys:B,title:F="Stacked bar chart",description:A,height:H=320,compact:M=!1,valueLabel:T,hoverHint:K="Hover a segment for details.",onSegmentClick:O}){const R=r(null),U=b(K),V=r(O)
23
- V.current=O
24
- const q=e(()=>B??I(S),[S,B]),{hiddenIds:z,visibleIds:D,toggle:E}=x(q),G=e(()=>q.filter(t=>D.includes(t)),[q,D])
25
- o(()=>{const t=R.current
26
- if(!t||0===G.length)return
27
- const r=S.map(t=>({label:t.label,...t.segments})),e=t.clientWidth||640,o=M?Math.min(H,280):H,h=g(M),l=h.margin,{width:u,height:b}=v(e,o,l),x=c(t)
28
- x.selectAll("*").remove(),x.attr("viewBox",`0 0 ${e} ${o}`)
29
- const I=x.append("defs")
30
- q.forEach((t,r)=>{if(!G.includes(t))return
31
- const e=d[r%d.length]
32
- C(I,`stacked-${L(t)}`,e,M)})
33
- const B=x.append("g").attr("transform",`translate(${l.left},${l.top})`),F=a().domain(r.map(t=>t.label)).range([0,u]).padding(.25),A=m().keys(G)(r),K=i().domain([0,s(A,t=>s(t,t=>t[1])??0)??0]).nice().range([b,0]),O=n().domain(q).range(q.map((t,r)=>d[r%d.length]))
34
- f(B,F,b,h.x),p(B,K,h.y),B.selectAll("g.layer").data(A).join("g").attr("class","layer").selectAll("rect").data(t=>t.map(r=>({...r,key:t.key}))).join("rect").attr("x",t=>F(t.data.label)??0).attr("y",t=>K(t[1])).attr("height",t=>K(t[0])-K(t[1])).attr("width",F.bandwidth()).attr("fill",t=>`url(#stacked-${L(t.key)})`).attr("stroke",t=>O(t.key)).attr("stroke-width",w).attr("stroke-opacity",.3)
35
- const z=B.selectAll("g.layer rect")
36
- k(z,{keyFn:t=>`${t.data.label}:${t.key}`,hintFn:t=>$(`${t.data.label} · ${t.key}`,t[1]-t[0],T),...j(U),onClick:t=>V.current?.({label:t.data.label,segment:t.key,value:t[1]-t[0]})})
37
- const D=U.registerFocusApply(()=>{y(z,t=>`${t.data.label}:${t.key}`,U.getFocusOpacity)})
38
- return()=>{D(),z.on("mouseenter mouseleave click",null)}},[M,S,H,U.getFocusOpacity,U.onHover,U.onHoverEnd,U.onPointerMove,U.onToggleSelect,U.registerFocusApply,K,T,q,G])
39
- const J=e(()=>t(l,{ariaLabel:"Series",hiddenIds:z,onToggle:E,items:q.map((t,r)=>({id:t,label:t,color:d[r%d.length]}))}),[z,q,E])
40
- return t(h,{title:F,description:A,height:M?Math.min(H,280):H,compact:M,...u(U),svgRef:R,legend:J})}export{S as StackedBarChart}
10
+ import{ChartLegend as f}from"../shared/ChartLegend/index.js"
11
+ import{renderXAxis as p,renderYAxis as g}from"../shared/chartAxisLayout/render.js"
12
+ import{stackedBarChartAxisLayout as u}from"../shared/chartAxisLayout/stackedBarChart.js"
13
+ import{chartFrameInteractionProps as j,chartPointerHandlers as k}from"../shared/chartBinding.js"
14
+ import{bindChartPointer as y,applyPointerOpacity as $}from"../shared/chartInteraction.js"
15
+ import{formatChartHint as b}from"../shared/chartLabels.js"
16
+ import{useChartInteraction as x}from"../shared/useChartInteraction.js"
17
+ import{useChartLegendToggle as v}from"../shared/useChartLegendToggle.js"
18
+ import{innerSize as C}from"../shared/chartUtils.js"
19
+ import{appendBarSeriesGradient as L,sanitizeGradientKey as w,SHAPE_STROKE_WIDTH as I}from"../shared/chartVisualStyle.js"
20
+ function S(r){const e=new Set
21
+ for(const t of r)for(const r of Object.keys(t.segments))e.add(r)
22
+ return[...e]}function B({data:B,seriesKeys:F,seriesColors:A,title:H="Stacked bar chart",description:M,height:T=320,compact:K=!1,valueLabel:O,hoverHint:R="Hover a segment for details.",onSegmentClick:U}){const V=e(null),q=x(R),z=e(U)
23
+ z.current=U
24
+ const D=t(()=>F??S(B),[B,F]),{hiddenIds:E,visibleIds:G,toggle:J}=v(D),N=t(()=>D.filter(r=>G.includes(r)),[D,G]),P=o((r,e)=>A?.[r]??d[e%d.length],[A])
25
+ s(()=>{const r=V.current
26
+ if(!r||0===N.length)return
27
+ const e=B.map(r=>({label:r.label,...r.segments})),t=r.clientWidth||640,o=K?Math.min(T,280):T,s=u(K),d=s.margin,{width:h,height:f}=C(t,o,d),j=m(r)
28
+ j.selectAll("*").remove(),j.attr("viewBox",`0 0 ${t} ${o}`)
29
+ const x=j.append("defs")
30
+ D.forEach((r,e)=>{if(!N.includes(r))return
31
+ const t=P(r,e)
32
+ L(x,`stacked-${w(r)}`,t,K)})
33
+ const v=j.append("g").attr("transform",`translate(${d.left},${d.top})`),S=i().domain(e.map(r=>r.label)).range([0,h]).padding(.25),F=l().keys(N)(e),A=n().domain([0,a(F,r=>a(r,r=>r[1])??0)??0]).nice().range([f,0]),H=c().domain(D).range(D.map((r,e)=>P(r,e)))
34
+ p(v,S,f,s.x),g(v,A,s.y),v.selectAll("g.layer").data(F).join("g").attr("class","layer").selectAll("rect").data(r=>r.map(e=>({...e,key:r.key}))).join("rect").attr("x",r=>S(r.data.label)??0).attr("y",r=>A(r[1])).attr("height",r=>A(r[0])-A(r[1])).attr("width",S.bandwidth()).attr("fill",r=>`url(#stacked-${w(r.key)})`).attr("stroke",r=>H(r.key)).attr("stroke-width",I).attr("stroke-opacity",.3)
35
+ const M=v.selectAll("g.layer rect")
36
+ y(M,{keyFn:r=>`${r.data.label}:${r.key}`,hintFn:r=>b(`${r.data.label} · ${r.key}`,r[1]-r[0],O),...k(q),onClick:r=>z.current?.({label:r.data.label,segment:r.key,value:r[1]-r[0]})})
37
+ const R=q.registerFocusApply(()=>{$(M,r=>`${r.data.label}:${r.key}`,q.getFocusOpacity)})
38
+ return()=>{R(),M.on("mouseenter mouseleave click",null)}},[P,K,B,T,q.getFocusOpacity,q.onHover,q.onHoverEnd,q.onPointerMove,q.onToggleSelect,q.registerFocusApply,R,O,D,A,N])
39
+ const Q=t(()=>r(f,{ariaLabel:"Series",hiddenIds:E,onToggle:J,items:D.map((r,e)=>({id:r,label:r,color:P(r,e)}))}),[P,E,D,J])
40
+ return r(h,{title:H,description:M,height:K?Math.min(T,280):T,compact:K,...j(q),svgRef:V,legend:Q})}export{B as StackedBarChart}
@@ -5,6 +5,8 @@ export type StackedBarRow = {
5
5
  export type StackedBarChartProps = {
6
6
  data: StackedBarRow[];
7
7
  seriesKeys?: string[];
8
+ /** Optional color per series key; falls back to the default chart palette. */
9
+ seriesColors?: Record<string, string>;
8
10
  title?: string;
9
11
  description?: string;
10
12
  height?: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ioloco-charts",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "Stylex D3 chart components for React",
5
5
  "author": {
6
6
  "name": "Besjan Sejrani"