ioloco-charts 0.1.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;
@@ -26,8 +26,6 @@ export { TreemapChart } from './TreemapChart';
26
26
  export type { TreemapChartProps, TreemapNode } from './TreemapChart/types';
27
27
  export { SparklineChart } from './SparklineChart';
28
28
  export type { SparklineChartProps, SparklineSeries } from './SparklineChart/types';
29
- export { KpiCard } from './KpiCard';
30
- export type { KpiCardProps, KpiMetric } from './KpiCard/types';
31
29
  export { RelationshipDiagram, type DependencyGraph, type DependencyLink, type DependencyNode, type DependencyNodeType, type DependencyRelationship, type RelationshipDiagramProps } from './RelationshipDiagram';
32
30
  export { ChartFrame, type ChartFrameProps } from './shared/ChartFrame';
33
31
  export { ChartLegend, type ChartLegendItem, type ChartLegendProps } from './shared/ChartLegend';
package/dist/index.js CHANGED
@@ -12,7 +12,6 @@ export{GanttTimeline}from"./D3/GanttTimeline/index.js"
12
12
  export{SankeyChart}from"./D3/SankeyChart/index.js"
13
13
  export{TreemapChart}from"./D3/TreemapChart/index.js"
14
14
  export{SparklineChart}from"./D3/SparklineChart/index.js"
15
- export{KpiCard}from"./D3/KpiCard/index.js"
16
15
  export{RelationshipDiagram}from"./D3/RelationshipDiagram/index.js"
17
16
  export{ChartFrame}from"./D3/shared/ChartFrame/index.js"
18
17
  export{ChartLegend}from"./D3/shared/ChartLegend/index.js"
@@ -1 +1 @@
1
- @layer priority1{._q7jof,:root{--_3kibph:#0000001f;--_nu89q3:var(--blackWhiteColor);--_nlcxv4:#0000008c;--_1l3ajwk:#374151;--_dtq5hu:#374151;--_i53b70:#00c595;--_1e1ve05:#00bfff;--_s8vpk3:#f57373;--_1c781:orange;--_yoxkkg:var(--secondaryColor);--_i86ma6:var(--secondaryColor);--_1vga2en:var(--quaternaryColor);--_1jrvoj:#0000001f;--_1w671vd:var(--blackWhiteColor);--_1de526y:#374151}._1jknjb,:root{--color-primary-50:#f9fafb;--color-primary-100:#f3f4f6;--color-primary-200:#e5e7eb;--color-primary-300:#d1d5db;--color-primary-400:#9ca3af;--color-primary-500:#6b7280;--color-primary-600:#4b5563;--color-primary-700:#374151;--color-primary-800:#1f2937;--color-primary-900:#000;--color-secondary-50:#f0fdfa;--color-secondary-100:#ccfbf1;--color-secondary-200:#99f6e4;--color-secondary-300:#5eead4;--color-secondary-400:#2dd4bf;--color-secondary-500:#00c595;--color-secondary-600:#00a082;--color-secondary-700:#007a6b;--color-secondary-800:#005d55;--color-secondary-900:#004d47;--color-tertiary-50:#f0f9ff;--color-tertiary-100:#e0f2fe;--color-tertiary-200:#bae6fd;--color-tertiary-300:#7dd3fc;--color-tertiary-400:#38bdf8;--color-tertiary-500:#00bfff;--color-tertiary-600:#0ea5e9;--color-tertiary-700:#0284c7;--color-tertiary-800:#0369a1;--color-tertiary-900:#0c4a6e;--color-quaternary-50:#fef7f7;--color-quaternary-100:#feeaea;--color-quaternary-200:#fecaca;--color-quaternary-300:#fca5a5;--color-quaternary-400:#f87171;--color-quaternary-500:#f57373;--color-quaternary-600:#ef4444;--color-quaternary-700:#dc2626;--color-quaternary-800:#b91c1c;--color-quaternary-900:#991b1b;--color-quinary-50:#fff7ed;--color-quinary-100:#ffedd5;--color-quinary-200:#fed7aa;--color-quinary-300:#fdba74;--color-quinary-400:#fb923c;--color-quinary-500:orange;--color-quinary-600:#ff8c00;--color-quinary-700:#e67e00;--color-quinary-800:#cc7000;--color-quinary-900:#b36200;--primaryColor:var(--color-primary-900);--secondaryColor:var(--color-secondary-500);--tertiaryColor:var(--color-tertiary-500);--quaternaryColor:var(--color-quaternary-500);--quinaryColor:var(--color-quinary-500);--blackWhiteColor:#fff;--whiteBlackColor:#000;--disabledColor:#0000001a}}@layer priority2{._1ghz6dp{margin:0}._kaxd7b{padding:.6rem .9rem}._3vcqe7{padding:1.2rem}._qo3fwf{padding:1.6rem}}@layer priority3{._r1djjy{border-color:var(--_1jrvoj)}._1yf9t2n{border-color:var(--_3kibph)}._45n503{border-color:var(--_yoxkkg)}._1xh8lfz{border-radius:.2rem}._18jy0o0{border-radius:.4rem}._9mmeec{border-radius:.6rem}._1o5ta1t{border-radius:.8rem}._1e6avla{border-radius:999px}._1y0btm7{border-style:solid}._mkeg23{border-width:1px}._73f2yu{gap:.35rem}._1neeqzj{gap:.4rem}._praio3{gap:.55rem}._13z6uf9{gap:.5rem}._1p549t4{gap:.6rem 1rem}._rpnz5g{gap:.8rem 1.6rem}._1rq4zhh{gap:.8rem}._bhn5rf{gap:1.2rem}._8fetqu{gap:1rem}._1uexzyd{margin-left:-.3rem;margin-right:-.3rem}._b3r6kr{overflow:hidden}._3rcno1{padding-top:.2rem;padding-bottom:.2rem}._11pq3io{padding-left:.3rem;padding-right:.3rem}._mqliwb{text-decoration:line-through}}@layer priority4{._1winvzj{-webkit-user-select:none}._1pha0wt{align-items:baseline}._6s0dn4{align-items:center}._1cy8zhl{align-items:flex-start}._1asp76r{background-color:var(--_1w671vd)}._1a1xyot{background-color:var(--_nu89q3)}._1rvjved{box-shadow:0 0 0 2px #00000014}._14nb6pt{box-shadow:0 4px 14px #00000014}._1xa3opb{box-shadow:0 6px 18px #0000001f}._gnmr2x{color:var(--_1de526y)}._67euey{color:var(--_1vga2en)}._5zgiyw{color:var(--_i86ma6)}._qdq3cf{color:var(--_nlcxv4)}._4iqcr8{color:var(--_yoxkkg)}._1jm3nie{cursor:grab}._1ypdohk{cursor:pointer}._1lliihq{display:block}._78zum5{display:flex}._rvj5dj{display:grid}._dt5ytf{flex-direction:column}._2lah0s{flex-shrink:0}._1a02dak{flex-wrap:wrap}._rlpt6b{font-family:var(--font-inter,inter,Inter,system-ui,-apple-system,BlinkMacSystemFont,sans-serif)}._1hptrd9{font-size:1.1rem}._vewgow{font-size:1.2rem}._1xebwwb{font-size:1.3rem}._1elmx46{font-size:1.8rem}._19orhxu{font-size:2.4rem}._k50ysn{font-weight:500}._1s688f{font-weight:600}._1xlr1w8{font-weight:700}._1y6fwsi{grid-template-columns:1fr}._1de81ps{grid-template-columns:minmax(10rem,14rem) 1fr}._17b3u6i{grid-template-columns:minmax(8rem,10rem) 1fr}._19vp1m2{grid-template-columns:repeat(auto-fit,minmax(18rem,1fr))}._1qughib{justify-content:space-between}._1159mfc{line-height:1.1}._1u7k74{line-height:1.2}._37zpob{line-height:1.4}._3onkmb{opacity:.35}._yd83as{opacity:.45}._47corl{pointer-events:none}._10l6tqk{position:absolute}._1n2onr6{position:relative}._tuk9sc{transform:translate(12px,-50%)}._x6bhzk{transition-duration:.15s}._hd6ntr{transition-property:box-shadow,transform}._npjden{transition-property:opacity,background-color}._wji4o3{transition-timing-function:ease}._87ps6o{-webkit-user-select:none;user-select:none}._eaf4i8{white-space:normal}._1fj9vlw{white-space:pre-line}._htitgo{z-index:2}._ddrp5s:hover{background-color:#0000000a}}@layer priority5{._1lut4zz{height:.8rem}._1l36t39{height:1rem}._1r7j5eq{height:3.2rem}._1p62t0q{height:42rem}._1i2h5o5{margin-bottom:.15rem}._yccheo{margin-bottom:.4rem}._dj266r{margin-top:0}._owlazn{max-width:24rem}._1sfyvwd{min-height:3.2rem}._1j9c18f{min-height:36rem}._17zuyli{min-height:42rem}._oml2pt{width:.8rem}._h8yej3{width:100%}._cdlrvm{width:1rem}}
1
+ @layer priority1{._q7jof,:root{--_3kibph:#0000001f;--_nu89q3:var(--blackWhiteColor);--_nlcxv4:#0000008c;--_1l3ajwk:#374151;--_dtq5hu:#374151;--_i53b70:#00c595;--_1e1ve05:#00bfff;--_s8vpk3:#f57373;--_1c781:orange;--_yoxkkg:var(--secondaryColor);--_i86ma6:var(--secondaryColor);--_1vga2en:var(--quaternaryColor);--_1jrvoj:#0000001f;--_1w671vd:var(--blackWhiteColor);--_1de526y:#374151}._1jknjb,:root{--color-primary-50:#f9fafb;--color-primary-100:#f3f4f6;--color-primary-200:#e5e7eb;--color-primary-300:#d1d5db;--color-primary-400:#9ca3af;--color-primary-500:#6b7280;--color-primary-600:#4b5563;--color-primary-700:#374151;--color-primary-800:#1f2937;--color-primary-900:#000;--color-secondary-50:#f0fdfa;--color-secondary-100:#ccfbf1;--color-secondary-200:#99f6e4;--color-secondary-300:#5eead4;--color-secondary-400:#2dd4bf;--color-secondary-500:#00c595;--color-secondary-600:#00a082;--color-secondary-700:#007a6b;--color-secondary-800:#005d55;--color-secondary-900:#004d47;--color-tertiary-50:#f0f9ff;--color-tertiary-100:#e0f2fe;--color-tertiary-200:#bae6fd;--color-tertiary-300:#7dd3fc;--color-tertiary-400:#38bdf8;--color-tertiary-500:#00bfff;--color-tertiary-600:#0ea5e9;--color-tertiary-700:#0284c7;--color-tertiary-800:#0369a1;--color-tertiary-900:#0c4a6e;--color-quaternary-50:#fef7f7;--color-quaternary-100:#feeaea;--color-quaternary-200:#fecaca;--color-quaternary-300:#fca5a5;--color-quaternary-400:#f87171;--color-quaternary-500:#f57373;--color-quaternary-600:#ef4444;--color-quaternary-700:#dc2626;--color-quaternary-800:#b91c1c;--color-quaternary-900:#991b1b;--color-quinary-50:#fff7ed;--color-quinary-100:#ffedd5;--color-quinary-200:#fed7aa;--color-quinary-300:#fdba74;--color-quinary-400:#fb923c;--color-quinary-500:orange;--color-quinary-600:#ff8c00;--color-quinary-700:#e67e00;--color-quinary-800:#cc7000;--color-quinary-900:#b36200;--primaryColor:var(--color-primary-900);--secondaryColor:var(--color-secondary-500);--tertiaryColor:var(--color-tertiary-500);--quaternaryColor:var(--color-quaternary-500);--quinaryColor:var(--color-quinary-500);--blackWhiteColor:#fff;--whiteBlackColor:#000;--disabledColor:#0000001a}}@layer priority2{._1ghz6dp{margin:0}._kaxd7b{padding:.6rem .9rem}._3vcqe7{padding:1.2rem}._qo3fwf{padding:1.6rem}}@layer priority3{._r1djjy{border-color:var(--_1jrvoj)}._1yf9t2n{border-color:var(--_3kibph)}._1xh8lfz{border-radius:.2rem}._18jy0o0{border-radius:.4rem}._9mmeec{border-radius:.6rem}._1o5ta1t{border-radius:.8rem}._1e6avla{border-radius:999px}._1y0btm7{border-style:solid}._mkeg23{border-width:1px}._73f2yu{gap:.35rem}._praio3{gap:.55rem}._13z6uf9{gap:.5rem}._1p549t4{gap:.6rem 1rem}._rpnz5g{gap:.8rem 1.6rem}._1rq4zhh{gap:.8rem}._bhn5rf{gap:1.2rem}._8fetqu{gap:1rem}._1uexzyd{margin-left:-.3rem;margin-right:-.3rem}._b3r6kr{overflow:hidden}._3rcno1{padding-top:.2rem;padding-bottom:.2rem}._11pq3io{padding-left:.3rem;padding-right:.3rem}._mqliwb{text-decoration:line-through}}@layer priority4{._1winvzj{-webkit-user-select:none}._6s0dn4{align-items:center}._1cy8zhl{align-items:flex-start}._1asp76r{background-color:var(--_1w671vd)}._1a1xyot{background-color:var(--_nu89q3)}._1xa3opb{box-shadow:0 6px 18px #0000001f}._gnmr2x{color:var(--_1de526y)}._qdq3cf{color:var(--_nlcxv4)}._4iqcr8{color:var(--_yoxkkg)}._1jm3nie{cursor:grab}._1ypdohk{cursor:pointer}._1lliihq{display:block}._78zum5{display:flex}._rvj5dj{display:grid}._dt5ytf{flex-direction:column}._2lah0s{flex-shrink:0}._1a02dak{flex-wrap:wrap}._rlpt6b{font-family:var(--font-inter,inter,Inter,system-ui,-apple-system,BlinkMacSystemFont,sans-serif)}._1hptrd9{font-size:1.1rem}._vewgow{font-size:1.2rem}._1xebwwb{font-size:1.3rem}._1elmx46{font-size:1.8rem}._k50ysn{font-weight:500}._1s688f{font-weight:600}._1de81ps{grid-template-columns:minmax(10rem,14rem) 1fr}._17b3u6i{grid-template-columns:minmax(8rem,10rem) 1fr}._1qughib{justify-content:space-between}._1u7k74{line-height:1.2}._37zpob{line-height:1.4}._3onkmb{opacity:.35}._yd83as{opacity:.45}._47corl{pointer-events:none}._10l6tqk{position:absolute}._1n2onr6{position:relative}._tuk9sc{transform:translate(12px,-50%)}._x6bhzk{transition-duration:.15s}._npjden{transition-property:opacity,background-color}._87ps6o{-webkit-user-select:none;user-select:none}._eaf4i8{white-space:normal}._1fj9vlw{white-space:pre-line}._htitgo{z-index:2}._ddrp5s:hover{background-color:#0000000a}}@layer priority5{._1lut4zz{height:.8rem}._1l36t39{height:1rem}._1p62t0q{height:42rem}._1i2h5o5{margin-bottom:.15rem}._yccheo{margin-bottom:.4rem}._dj266r{margin-top:0}._owlazn{max-width:24rem}._1sfyvwd{min-height:3.2rem}._1j9c18f{min-height:36rem}._17zuyli{min-height:42rem}._oml2pt{width:.8rem}._h8yej3{width:100%}._cdlrvm{width:1rem}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ioloco-charts",
3
- "version": "0.1.1",
3
+ "version": "0.2.2",
4
4
  "description": "Stylex D3 chart components for React",
5
5
  "author": {
6
6
  "name": "Besjan Sejrani"
@@ -1,2 +0,0 @@
1
- import type { KpiCardProps } from './types';
2
- export declare function KpiCard({ metrics, title, description, compact, hoverHint, onMetricClick }: Readonly<KpiCardProps>): import("react").JSX.Element;
@@ -1,12 +0,0 @@
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 l}from"../shared/useChartInteraction.js"
7
- import{Sparkline as t}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:l,isHovered:d,isSelected:s,onHover:a,onPointerMove:u,onHoverEnd:v,onToggleSelect:h,onClick:m}){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:u,onMouseLeave:v,onClick(){h(),m?.(i)},onKeyDown(e){"Enter"!==e.key&&" "!==e.key||(e.preventDefault(),h(),m?.(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(t,{values:i.sparkline,color:r[l%r.length]}):null]})}function a({metrics:r,title:t="KPIs",description:a,compact:u=!1,hoverHint:v="Hover a KPI card for details.",onMetricClick:h}){const m=l(v)
12
- return e("div",{...o.props(c.root),children:[e("div",{...o.props(c.header),children:[n("h4",{...o.props(c.headerTitle),children:t}),u?null:n("p",{...o.props(c.headerDescription),children:a})]}),e("div",{ref:m.setTooltipContainer,...o.props(c.grid,c.gridRelative,u?c.gridCompact:null),children:[r.map((e,o)=>n(s,{metric:e,index:o,isHovered:m.getHoverKey()===e.id,isSelected:m.getSelectedKey()===e.id,onHover:n=>m.onHover(e.id,d(e),n.nativeEvent),onPointerMove:e=>m.onPointerMove(e.nativeEvent),onHoverEnd:m.onHoverEnd,onToggleSelect:()=>m.onToggleSelect(e.id,`${e.label}: ${e.value.toLocaleString()}`),onClick:h},e.id)),n(i,{tooltip:m.tooltip})]}),n("span",{...o.props(c.footerHint,m.isPinned?c.footerHintPinned:null),children:m.hint})]})}export{a as KpiCard}
@@ -1,108 +0,0 @@
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
- }>;
@@ -1,3 +0,0 @@
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}
@@ -1,17 +0,0 @@
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
- hoverHint?: string;
16
- onMetricClick?: (metric: KpiMetric) => void;
17
- };