chordia-ui 3.6.1 → 3.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ChartRenderer.cjs.js +3 -0
- package/dist/ChartRenderer.cjs.js.map +1 -0
- package/dist/ChartRenderer.es.js +301 -0
- package/dist/ChartRenderer.es.js.map +1 -0
- package/dist/Toast.cjs.js +2 -2
- package/dist/Toast.cjs.js.map +1 -1
- package/dist/Toast.es.js +294 -269
- package/dist/Toast.es.js.map +1 -1
- package/dist/components/UpdatedInteractionDetails.cjs.js +4 -4
- package/dist/components/UpdatedInteractionDetails.cjs.js.map +1 -1
- package/dist/components/UpdatedInteractionDetails.es.js +972 -859
- package/dist/components/UpdatedInteractionDetails.es.js.map +1 -1
- package/dist/components/chat.cjs.js +7 -8
- package/dist/components/chat.cjs.js.map +1 -1
- package/dist/components/chat.es.js +516 -809
- package/dist/components/chat.es.js.map +1 -1
- package/dist/components/common.cjs.js +1 -1
- package/dist/components/common.es.js +30 -28
- package/dist/components/common.es.js.map +1 -1
- package/dist/components/data.cjs.js +1 -1
- package/dist/components/data.cjs.js.map +1 -1
- package/dist/components/data.es.js +5 -4
- package/dist/components/data.es.js.map +1 -1
- package/dist/index.cjs.js +1 -1
- package/dist/index.es.js +48 -47
- package/dist/index.es.js.map +1 -1
- package/dist/pages/interactionDetails.cjs.js +1 -1
- package/dist/pages/interactionDetails.es.js +1 -1
- package/package.json +1 -1
- package/src/components/UpdatedInteractionDetails/UpdatedCompassScore.jsx +94 -34
- package/src/components/UpdatedInteractionDetails/UpdatedInteractionDetails.jsx +124 -44
- package/src/components/common/AskCompass.jsx +49 -21
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
"use strict";const t=require("react/jsx-runtime"),E=require("react"),e=require("recharts"),a=["#5E88B0","#9B7AA8","#C98A5A","#7BA89D","#D17B6B","#6B7C93","#9B8E6F","#8A9BAF","#B8976A","#A8C76B"],_={fill:"var(--text-muted, #666)",fontSize:12},j={stroke:"var(--border, #e0e0e0)"},M="var(--border, #e0e0e0)",R={contentStyle:{backgroundColor:"var(--paper-elevated, #fff)",border:"1px solid var(--border, #e0e0e0)",borderRadius:"var(--radius-sm, 4px)",boxShadow:"0 2px 8px rgba(0, 0, 0, 0.1)",color:"var(--text-ink, #1e2125)"},labelStyle:{color:"var(--text-strong, #1e2125)"}},N={color:"var(--text-ink, #1e2125)",fontSize:"12px"},q=(l,c)=>{if(!l)return!1;const d=l.toLowerCase();return c.filter(s=>String(s).toLowerCase().includes(d)).length<c.length*.5},V=async(l,c)=>{const d=l.querySelector("svg");if(!d)return;const i=d.cloneNode(!0),s=d.clientWidth||600,x=d.clientHeight||300;i.setAttribute("width",s),i.setAttribute("height",x),i.setAttribute("xmlns","http://www.w3.org/2000/svg");const S=document.createElement("style");S.textContent='text { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; }',i.insertBefore(S,i.firstChild);const k=new XMLSerializer().serializeToString(i),u=new Blob([k],{type:"image/svg+xml;charset=utf-8"}),h=URL.createObjectURL(u),m=new Image;m.onload=()=>{const g=document.createElement("canvas"),b=2;g.width=s*b,g.height=x*b;const y=g.getContext("2d");y.fillStyle="#ffffff",y.fillRect(0,0,g.width,g.height),y.scale(b,b),y.drawImage(m,0,0,s,x),URL.revokeObjectURL(h);const B=document.createElement("a");B.download=`${(c||"chart").replace(/[^a-z0-9]+/gi,"_")}.png`,B.href=g.toDataURL("image/png"),B.click()},m.src=h},H=(l,c)=>{const d=["",...l.map(x=>x.name)].join(","),i=c.map(x=>{const S=l.map(k=>{const u=k.data.find(h=>h.x===x);return u?u.y:""});return[x,...S].join(",")}),s=[d,...i].join(`
|
|
2
|
+
`);navigator.clipboard.writeText(s)},$=({onDownload:l,onCopy:c,copied:d})=>t.jsxs("div",{style:{display:"flex",gap:6,justifyContent:"flex-end",marginBottom:8,opacity:.7,transition:"opacity 0.15s"},children:[t.jsx("button",{onClick:c,title:"Copy data as CSV",style:{background:"none",border:"1px solid var(--border, #e0e0e0)",borderRadius:"var(--radius-sm, 4px)",padding:"3px 8px",fontSize:11,color:"var(--text-muted, #666)",cursor:"pointer",display:"flex",alignItems:"center",gap:4},children:d?"✓ Copied":"📋 CSV"}),t.jsx("button",{onClick:l,title:"Download as PNG",style:{background:"none",border:"1px solid var(--border, #e0e0e0)",borderRadius:"var(--radius-sm, 4px)",padding:"3px 8px",fontSize:11,color:"var(--text-muted, #666)",cursor:"pointer",display:"flex",alignItems:"center",gap:4},children:"📥 PNG"})]}),J=({chartType:l,title:c,xLabel:d,yLabel:i,series:s})=>{const x=E.useRef(null),[S,k]=E.useState(!1);if(!s||s.length===0)return null;const u=[...new Set(s.flatMap(n=>n.data.map(r=>r.x)))],h=u.map(n=>{const r={x:n};return s.forEach(p=>{const o=p.data.find(f=>f.x===n);r[p.name]=o?o.y:null}),r}),m=s.map(n=>n.name),g=m.length===1,b=q(d,u),y=b?20:5,D=Math.max(...u.map(n=>String(n).length))>12||u.length>8,G={background:"var(--paper-elevated, #fff)",border:"1px solid var(--border, #e0e0e0)",borderRadius:"var(--radius-md, 8px)",padding:"16px",marginBottom:"16px"},O={color:"var(--text-strong, #1e2125)",fontSize:"14px",fontWeight:"600",marginBottom:"12px"},P={dataKey:"x",tick:D?{fill:"var(--text-muted, #666)",fontSize:11,angle:-35,textAnchor:"end"}:_,axisLine:j,tickLine:j,...b?{label:{value:d,position:"insideBottom",offset:-10,style:{textAnchor:"middle",fill:"var(--text-muted, #666)"}}}:{}},X={tick:_,axisLine:j,tickLine:j,...i?{label:{value:i,angle:-90,position:"insideLeft",style:{textAnchor:"middle",fill:"var(--text-muted, #666)"}}}:{}},U=()=>{switch(l){case"bar":return t.jsx(e.ResponsiveContainer,{width:"100%",height:300,children:t.jsxs(e.BarChart,{data:h,margin:{top:5,right:30,left:20,bottom:D?40:y},children:[t.jsx(e.CartesianGrid,{strokeDasharray:"3 3",stroke:M}),t.jsx(e.XAxis,{...P}),t.jsx(e.YAxis,{...X}),t.jsx(e.Tooltip,{...R}),!g&&t.jsx(e.Legend,{wrapperStyle:N}),m.map((n,r)=>t.jsx(e.Bar,{dataKey:n,fill:a[r%a.length],radius:[2,2,0,0],children:g&&h.map((p,o)=>t.jsx(e.Cell,{fill:a[o%a.length]},o))},n))]})});case"horizontal_bar":return t.jsx(e.ResponsiveContainer,{width:"100%",height:Math.max(300,h.length*40),children:t.jsxs(e.BarChart,{data:h,layout:"vertical",margin:{top:5,right:30,left:100,bottom:5},children:[t.jsx(e.CartesianGrid,{strokeDasharray:"3 3",stroke:M}),t.jsx(e.XAxis,{type:"number",tick:_,axisLine:j,tickLine:j,...i?{label:{value:i,position:"insideBottom",offset:-5,style:{textAnchor:"middle",fill:"var(--text-muted, #666)"}}}:{}}),t.jsx(e.YAxis,{type:"category",dataKey:"x",tick:{fill:"var(--text-muted, #666)",fontSize:11},width:90,axisLine:j,tickLine:j}),t.jsx(e.Tooltip,{...R}),!g&&t.jsx(e.Legend,{wrapperStyle:N}),m.map((n,r)=>t.jsx(e.Bar,{dataKey:n,fill:a[r%a.length],radius:[0,2,2,0],children:g&&h.map((p,o)=>t.jsx(e.Cell,{fill:a[o%a.length]},o))},n))]})});case"line":return t.jsx(e.ResponsiveContainer,{width:"100%",height:300,children:t.jsxs(e.LineChart,{data:h,margin:{top:5,right:30,left:20,bottom:D?40:y},children:[t.jsx(e.CartesianGrid,{strokeDasharray:"3 3",stroke:M}),t.jsx(e.XAxis,{...P}),t.jsx(e.YAxis,{...X}),t.jsx(e.Tooltip,{...R}),t.jsx(e.Legend,{wrapperStyle:N}),m.map((n,r)=>t.jsx(e.Line,{type:"monotone",dataKey:n,stroke:a[r%a.length],strokeWidth:2,dot:{r:4,fill:a[r%a.length]},activeDot:{r:6,fill:a[r%a.length]}},n))]})});case"area":return t.jsx(e.ResponsiveContainer,{width:"100%",height:300,children:t.jsxs(e.AreaChart,{data:h,margin:{top:5,right:30,left:20,bottom:D?40:y},children:[t.jsx(e.CartesianGrid,{strokeDasharray:"3 3",stroke:M}),t.jsx(e.XAxis,{...P}),t.jsx(e.YAxis,{...X}),t.jsx(e.Tooltip,{...R}),t.jsx(e.Legend,{wrapperStyle:N}),m.map((n,r)=>t.jsx(e.Area,{type:"monotone",dataKey:n,stroke:a[r%a.length],strokeWidth:2,fill:a[r%a.length],fillOpacity:.15},n))]})});case"pie":{const n=s[0].data.map((o,f)=>({name:o.x,value:o.y,fill:a[f%a.length]})),r=Math.PI/180,p=({cx:o,cy:f,midAngle:C,innerRadius:A,outerRadius:K,percent:w,name:L})=>{const z=K+20,I=o+z*Math.cos(-C*r),T=f+z*Math.sin(-C*r);return w<.04?null:t.jsxs("text",{x:I,y:T,fill:"var(--text-ink, #1e2125)",fontSize:11,textAnchor:I>o?"start":"end",dominantBaseline:"central",children:[L," (",(w*100).toFixed(0),"%)"]})};return t.jsx(e.ResponsiveContainer,{width:"100%",height:320,children:t.jsxs(e.PieChart,{children:[t.jsx(e.Pie,{data:n,cx:"50%",cy:"50%",outerRadius:100,dataKey:"value",label:p,labelLine:{stroke:"var(--text-muted, #666)"},children:n.map((o,f)=>t.jsx(e.Cell,{fill:o.fill},f))}),t.jsx(e.Tooltip,{...R})]})})}case"metric":{const n=s[0],r=n.data[0],p=n.data.length>1?n.data[1]:null,o=r.y,f=r.x||"",C=p!==null,A=C?o-p.y:0,K=C&&p.y!==0?A/Math.abs(p.y)*100:0,w=A>0,L=A<0,z=w?"#7BA89D":L?"#D17B6B":"var(--text-muted, #666)",I=w?"↑":L?"↓":"→",T=v=>Number.isInteger(v)&&Math.abs(v)>=1e3?v.toLocaleString():typeof v=="number"?v%1===0?v.toString():v.toFixed(v<10?2:1):String(v);return t.jsxs("div",{style:{display:"flex",alignItems:"baseline",gap:12,padding:"8px 0"},children:[t.jsx("div",{style:{fontSize:"36px",fontWeight:700,lineHeight:1,color:"var(--text-strong, #1e2125)",fontVariantNumeric:"tabular-nums"},children:T(o)}),f&&t.jsx("div",{style:{fontSize:"14px",color:"var(--text-muted, #666)",fontWeight:500},children:f}),C&&t.jsxs("div",{style:{display:"flex",alignItems:"center",gap:4,fontSize:"13px",fontWeight:600,color:z,background:w?"rgba(123,168,157,0.12)":L?"rgba(209,123,107,0.12)":"rgba(128,128,128,0.08)",padding:"3px 8px",borderRadius:"var(--radius-sm, 4px)"},children:[t.jsx("span",{children:I}),t.jsxs("span",{children:[T(Math.abs(A))," (",Math.abs(K).toFixed(1),"%)"]})]}),C&&t.jsxs("div",{style:{fontSize:"11px",color:"var(--text-faint, #999)"},children:["vs ",p.x||"previous"]})]})}default:return t.jsxs("div",{style:{color:"var(--text-muted)",fontSize:12,padding:8},children:["Unsupported chart type: ",l]})}},W=E.useCallback(()=>{x.current&&V(x.current,c)},[c]),F=E.useCallback(()=>{H(s,u),k(!0),setTimeout(()=>k(!1),2e3)},[s,u]),Y=l!=="metric";return t.jsxs("div",{style:G,children:[c&&t.jsx("div",{style:O,children:c}),Y&&t.jsx($,{onDownload:W,onCopy:F,copied:S}),t.jsx("div",{ref:x,children:U()})]})};exports.ChartRenderer=J;
|
|
3
|
+
//# sourceMappingURL=ChartRenderer.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChartRenderer.cjs.js","sources":["../src/components/chat/ChartRenderer.jsx"],"sourcesContent":["\"use client\";\nimport React, { useRef, useCallback } from 'react';\nimport {\n ResponsiveContainer, BarChart, Bar, Cell, LineChart, Line,\n XAxis, YAxis, CartesianGrid, Tooltip, Legend,\n PieChart, Pie, AreaChart, Area,\n} from 'recharts';\n\n// Chordia design system rail colors — ordered for max visual distinction\nconst COLORS = [\n '#5E88B0', // rail-discovery / rail-blue\n '#9B7AA8', // rail-purple / rail-tone\n '#C98A5A', // rail-compliance / rail-orange\n '#7BA89D', // rail-signal-upsell (teal-green)\n '#D17B6B', // rail-coral / rail-signal-churn\n '#6B7C93', // rail-slate / rail-outcome\n '#9B8E6F', // rail-olive / rail-signal-satisfaction\n '#8A9BAF', // rail-quality\n '#B8976A', // rail-teal (warm gold)\n '#A8C76B', // green accent (complementary)\n];\n\n// Shared axis/tooltip/legend styling\nconst AXIS_TICK = { fill: 'var(--text-muted, #666)', fontSize: 12 };\nconst AXIS_LINE = { stroke: 'var(--border, #e0e0e0)' };\nconst GRID_STROKE = 'var(--border, #e0e0e0)';\nconst TOOLTIP_STYLE = {\n contentStyle: {\n backgroundColor: 'var(--paper-elevated, #fff)',\n border: '1px solid var(--border, #e0e0e0)',\n borderRadius: 'var(--radius-sm, 4px)',\n boxShadow: '0 2px 8px rgba(0, 0, 0, 0.1)',\n color: 'var(--text-ink, #1e2125)',\n },\n labelStyle: { color: 'var(--text-strong, #1e2125)' },\n};\nconst LEGEND_STYLE = { color: 'var(--text-ink, #1e2125)', fontSize: '12px' };\n\n// Smart label: skip x_label if tick values already contain the label text\nconst shouldShowAxisLabel = (label, tickValues) => {\n if (!label) return false;\n const lower = label.toLowerCase();\n // If most ticks contain the label word, it's redundant\n const matches = tickValues.filter(v => String(v).toLowerCase().includes(lower));\n return matches.length < tickValues.length * 0.5;\n};\n\n// --- Export utilities ---\nconst downloadPng = async (containerEl, title) => {\n const svg = containerEl.querySelector('svg');\n if (!svg) return;\n const clone = svg.cloneNode(true);\n // Ensure dimensions\n const w = svg.clientWidth || 600;\n const h = svg.clientHeight || 300;\n clone.setAttribute('width', w);\n clone.setAttribute('height', h);\n clone.setAttribute('xmlns', 'http://www.w3.org/2000/svg');\n // Inline computed styles for export fidelity\n const styleEl = document.createElement('style');\n styleEl.textContent = `text { font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif; }`;\n clone.insertBefore(styleEl, clone.firstChild);\n const xml = new XMLSerializer().serializeToString(clone);\n const blob = new Blob([xml], { type: 'image/svg+xml;charset=utf-8' });\n const url = URL.createObjectURL(blob);\n const img = new Image();\n img.onload = () => {\n const canvas = document.createElement('canvas');\n const scale = 2; // retina\n canvas.width = w * scale;\n canvas.height = h * scale;\n const ctx = canvas.getContext('2d');\n ctx.fillStyle = '#ffffff';\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n ctx.scale(scale, scale);\n ctx.drawImage(img, 0, 0, w, h);\n URL.revokeObjectURL(url);\n const link = document.createElement('a');\n link.download = `${(title || 'chart').replace(/[^a-z0-9]+/gi, '_')}.png`;\n link.href = canvas.toDataURL('image/png');\n link.click();\n };\n img.src = url;\n};\n\nconst copyAsCsv = (series, allXValues) => {\n const header = ['', ...series.map(s => s.name)].join(',');\n const rows = allXValues.map(x => {\n const vals = series.map(s => {\n const match = s.data.find(d => d.x === x);\n return match ? match.y : '';\n });\n return [x, ...vals].join(',');\n });\n const csv = [header, ...rows].join('\\n');\n navigator.clipboard.writeText(csv);\n};\n\nconst ActionBar = ({ onDownload, onCopy, copied }) => (\n <div style={{\n display: 'flex', gap: 6, justifyContent: 'flex-end',\n marginBottom: 8, opacity: 0.7, transition: 'opacity 0.15s',\n }}>\n <button onClick={onCopy} title=\"Copy data as CSV\" style={{\n background: 'none', border: '1px solid var(--border, #e0e0e0)',\n borderRadius: 'var(--radius-sm, 4px)', padding: '3px 8px',\n fontSize: 11, color: 'var(--text-muted, #666)', cursor: 'pointer',\n display: 'flex', alignItems: 'center', gap: 4,\n }}>\n {copied ? '✓ Copied' : '📋 CSV'}\n </button>\n <button onClick={onDownload} title=\"Download as PNG\" style={{\n background: 'none', border: '1px solid var(--border, #e0e0e0)',\n borderRadius: 'var(--radius-sm, 4px)', padding: '3px 8px',\n fontSize: 11, color: 'var(--text-muted, #666)', cursor: 'pointer',\n display: 'flex', alignItems: 'center', gap: 4,\n }}>\n 📥 PNG\n </button>\n </div>\n);\n\nconst ChartRenderer = ({ chartType, title, xLabel, yLabel, series }) => {\n const chartRef = useRef(null);\n const [copied, setCopied] = React.useState(false);\n\n if (!series || series.length === 0) return null;\n\n // Transform: merge all series into [{x, series1: val, series2: val}, ...]\n const allXValues = [...new Set(series.flatMap(s => s.data.map(d => d.x)))];\n const chartData = allXValues.map(x => {\n const point = { x };\n series.forEach(s => {\n const match = s.data.find(d => d.x === x);\n point[s.name] = match ? match.y : null;\n });\n return point;\n });\n\n const seriesNames = series.map(s => s.name);\n const isSingleSeries = seriesNames.length === 1;\n\n // Determine if axis labels are redundant\n const showXLabel = shouldShowAxisLabel(xLabel, allXValues);\n const bottomMargin = showXLabel ? 20 : 5;\n\n // Check if x-axis labels are long (rotate them)\n const maxTickLen = Math.max(...allXValues.map(v => String(v).length));\n const rotateXTicks = maxTickLen > 12 || allXValues.length > 8;\n\n const containerStyle = {\n background: 'var(--paper-elevated, #fff)',\n border: '1px solid var(--border, #e0e0e0)',\n borderRadius: 'var(--radius-md, 8px)',\n padding: '16px',\n marginBottom: '16px',\n };\n\n const titleStyle = {\n color: 'var(--text-strong, #1e2125)',\n fontSize: '14px',\n fontWeight: '600',\n marginBottom: '12px',\n };\n\n const xAxisProps = {\n dataKey: 'x',\n tick: rotateXTicks\n ? { fill: 'var(--text-muted, #666)', fontSize: 11, angle: -35, textAnchor: 'end' }\n : AXIS_TICK,\n axisLine: AXIS_LINE,\n tickLine: AXIS_LINE,\n ...(showXLabel ? {\n label: { value: xLabel, position: 'insideBottom', offset: -10, style: { textAnchor: 'middle', fill: 'var(--text-muted, #666)' } }\n } : {}),\n };\n\n const yAxisProps = {\n tick: AXIS_TICK,\n axisLine: AXIS_LINE,\n tickLine: AXIS_LINE,\n ...(yLabel ? {\n label: { value: yLabel, angle: -90, position: 'insideLeft', style: { textAnchor: 'middle', fill: 'var(--text-muted, #666)' } }\n } : {}),\n };\n\n const renderChart = () => {\n switch (chartType) {\n case 'bar':\n return (\n <ResponsiveContainer width=\"100%\" height={300}>\n <BarChart data={chartData} margin={{ top: 5, right: 30, left: 20, bottom: rotateXTicks ? 40 : bottomMargin }}>\n <CartesianGrid strokeDasharray=\"3 3\" stroke={GRID_STROKE} />\n <XAxis {...xAxisProps} />\n <YAxis {...yAxisProps} />\n <Tooltip {...TOOLTIP_STYLE} />\n {!isSingleSeries && <Legend wrapperStyle={LEGEND_STYLE} />}\n {seriesNames.map((name, i) => (\n <Bar key={name} dataKey={name} fill={COLORS[i % COLORS.length]} radius={[2, 2, 0, 0]}>\n {isSingleSeries && chartData.map((_, idx) => (\n <Cell key={idx} fill={COLORS[idx % COLORS.length]} />\n ))}\n </Bar>\n ))}\n </BarChart>\n </ResponsiveContainer>\n );\n\n case 'horizontal_bar': {\n // Horizontal bar: swap X/Y, use YAxis for categories\n return (\n <ResponsiveContainer width=\"100%\" height={Math.max(300, chartData.length * 40)}>\n <BarChart data={chartData} layout=\"vertical\" margin={{ top: 5, right: 30, left: 100, bottom: 5 }}>\n <CartesianGrid strokeDasharray=\"3 3\" stroke={GRID_STROKE} />\n <XAxis type=\"number\" tick={AXIS_TICK} axisLine={AXIS_LINE} tickLine={AXIS_LINE}\n {...(yLabel ? { label: { value: yLabel, position: 'insideBottom', offset: -5, style: { textAnchor: 'middle', fill: 'var(--text-muted, #666)' } } } : {})}\n />\n <YAxis type=\"category\" dataKey=\"x\" tick={{ fill: 'var(--text-muted, #666)', fontSize: 11 }} width={90} axisLine={AXIS_LINE} tickLine={AXIS_LINE} />\n <Tooltip {...TOOLTIP_STYLE} />\n {!isSingleSeries && <Legend wrapperStyle={LEGEND_STYLE} />}\n {seriesNames.map((name, i) => (\n <Bar key={name} dataKey={name} fill={COLORS[i % COLORS.length]} radius={[0, 2, 2, 0]}>\n {isSingleSeries && chartData.map((_, idx) => (\n <Cell key={idx} fill={COLORS[idx % COLORS.length]} />\n ))}\n </Bar>\n ))}\n </BarChart>\n </ResponsiveContainer>\n );\n }\n\n case 'line':\n return (\n <ResponsiveContainer width=\"100%\" height={300}>\n <LineChart data={chartData} margin={{ top: 5, right: 30, left: 20, bottom: rotateXTicks ? 40 : bottomMargin }}>\n <CartesianGrid strokeDasharray=\"3 3\" stroke={GRID_STROKE} />\n <XAxis {...xAxisProps} />\n <YAxis {...yAxisProps} />\n <Tooltip {...TOOLTIP_STYLE} />\n <Legend wrapperStyle={LEGEND_STYLE} />\n {seriesNames.map((name, i) => (\n <Line key={name} type=\"monotone\" dataKey={name}\n stroke={COLORS[i % COLORS.length]} strokeWidth={2}\n dot={{ r: 4, fill: COLORS[i % COLORS.length] }}\n activeDot={{ r: 6, fill: COLORS[i % COLORS.length] }}\n />\n ))}\n </LineChart>\n </ResponsiveContainer>\n );\n\n case 'area':\n return (\n <ResponsiveContainer width=\"100%\" height={300}>\n <AreaChart data={chartData} margin={{ top: 5, right: 30, left: 20, bottom: rotateXTicks ? 40 : bottomMargin }}>\n <CartesianGrid strokeDasharray=\"3 3\" stroke={GRID_STROKE} />\n <XAxis {...xAxisProps} />\n <YAxis {...yAxisProps} />\n <Tooltip {...TOOLTIP_STYLE} />\n <Legend wrapperStyle={LEGEND_STYLE} />\n {seriesNames.map((name, i) => (\n <Area key={name} type=\"monotone\" dataKey={name}\n stroke={COLORS[i % COLORS.length]} strokeWidth={2}\n fill={COLORS[i % COLORS.length]} fillOpacity={0.15}\n />\n ))}\n </AreaChart>\n </ResponsiveContainer>\n );\n\n case 'pie': {\n // Pie uses first series only\n const pieData = series[0].data.map((d, i) => ({\n name: d.x,\n value: d.y,\n fill: COLORS[i % COLORS.length],\n }));\n const RADIAN = Math.PI / 180;\n const renderLabel = ({ cx, cy, midAngle, innerRadius, outerRadius, percent, name }) => {\n const radius = outerRadius + 20;\n const x = cx + radius * Math.cos(-midAngle * RADIAN);\n const y = cy + radius * Math.sin(-midAngle * RADIAN);\n if (percent < 0.04) return null;\n return (\n <text x={x} y={y} fill=\"var(--text-ink, #1e2125)\" fontSize={11}\n textAnchor={x > cx ? 'start' : 'end'} dominantBaseline=\"central\">\n {name} ({(percent * 100).toFixed(0)}%)\n </text>\n );\n };\n return (\n <ResponsiveContainer width=\"100%\" height={320}>\n <PieChart>\n <Pie data={pieData} cx=\"50%\" cy=\"50%\" outerRadius={100}\n dataKey=\"value\" label={renderLabel} labelLine={{ stroke: 'var(--text-muted, #666)' }}>\n {pieData.map((entry, i) => (\n <Cell key={i} fill={entry.fill} />\n ))}\n </Pie>\n <Tooltip {...TOOLTIP_STYLE} />\n </PieChart>\n </ResponsiveContainer>\n );\n }\n\n case 'metric': {\n const s = series[0];\n const current = s.data[0];\n const previous = s.data.length > 1 ? s.data[1] : null;\n const value = current.y;\n const unit = current.x || '';\n const hasTrend = previous !== null;\n const change = hasTrend ? value - previous.y : 0;\n const pctChange = hasTrend && previous.y !== 0 ? ((change / Math.abs(previous.y)) * 100) : 0;\n const isPositive = change > 0;\n const isNegative = change < 0;\n const trendColor = isPositive ? '#7BA89D' : isNegative ? '#D17B6B' : 'var(--text-muted, #666)';\n const trendArrow = isPositive ? '↑' : isNegative ? '↓' : '→';\n\n // Format large numbers nicely\n const fmt = (n) => {\n if (Number.isInteger(n) && Math.abs(n) >= 1000) return n.toLocaleString();\n if (typeof n === 'number') return n % 1 === 0 ? n.toString() : n.toFixed(n < 10 ? 2 : 1);\n return String(n);\n };\n\n return (\n <div style={{ display: 'flex', alignItems: 'baseline', gap: 12, padding: '8px 0' }}>\n <div style={{\n fontSize: '36px', fontWeight: 700, lineHeight: 1,\n color: 'var(--text-strong, #1e2125)',\n fontVariantNumeric: 'tabular-nums',\n }}>\n {fmt(value)}\n </div>\n {unit && (\n <div style={{ fontSize: '14px', color: 'var(--text-muted, #666)', fontWeight: 500 }}>\n {unit}\n </div>\n )}\n {hasTrend && (\n <div style={{\n display: 'flex', alignItems: 'center', gap: 4,\n fontSize: '13px', fontWeight: 600, color: trendColor,\n background: isPositive ? 'rgba(123,168,157,0.12)' : isNegative ? 'rgba(209,123,107,0.12)' : 'rgba(128,128,128,0.08)',\n padding: '3px 8px', borderRadius: 'var(--radius-sm, 4px)',\n }}>\n <span>{trendArrow}</span>\n <span>{fmt(Math.abs(change))} ({Math.abs(pctChange).toFixed(1)}%)</span>\n </div>\n )}\n {hasTrend && (\n <div style={{ fontSize: '11px', color: 'var(--text-faint, #999)' }}>\n vs {previous.x || 'previous'}\n </div>\n )}\n </div>\n );\n }\n\n default:\n return <div style={{ color: 'var(--text-muted)', fontSize: 12, padding: 8 }}>Unsupported chart type: {chartType}</div>;\n }\n };\n\n const handleDownload = useCallback(() => {\n if (chartRef.current) downloadPng(chartRef.current, title);\n }, [title]);\n\n const handleCopy = useCallback(() => {\n copyAsCsv(series, allXValues);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n }, [series, allXValues]);\n\n const showActions = chartType !== 'metric';\n\n return (\n <div style={containerStyle}>\n {title && <div style={titleStyle}>{title}</div>}\n {showActions && <ActionBar onDownload={handleDownload} onCopy={handleCopy} copied={copied} />}\n <div ref={chartRef}>\n {renderChart()}\n </div>\n </div>\n );\n};\n\nexport default ChartRenderer;\n"],"names":["COLORS","AXIS_TICK","AXIS_LINE","GRID_STROKE","TOOLTIP_STYLE","LEGEND_STYLE","shouldShowAxisLabel","label","tickValues","lower","v","downloadPng","containerEl","title","svg","clone","w","h","styleEl","xml","blob","url","img","canvas","scale","ctx","link","copyAsCsv","series","allXValues","header","s","rows","vals","match","d","csv","ActionBar","onDownload","onCopy","copied","jsxs","jsx","ChartRenderer","chartType","xLabel","yLabel","chartRef","useRef","setCopied","React","chartData","x","point","seriesNames","isSingleSeries","showXLabel","bottomMargin","rotateXTicks","containerStyle","titleStyle","xAxisProps","yAxisProps","renderChart","ResponsiveContainer","BarChart","CartesianGrid","XAxis","YAxis","Tooltip","Legend","name","i","Bar","_","idx","Cell","LineChart","Line","AreaChart","Area","pieData","RADIAN","renderLabel","cx","cy","midAngle","innerRadius","outerRadius","percent","radius","y","PieChart","Pie","entry","current","previous","value","unit","hasTrend","change","pctChange","isPositive","isNegative","trendColor","trendArrow","fmt","n","handleDownload","useCallback","handleCopy","showActions"],"mappings":"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"}
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import { jsxs as d, jsx as t } from "react/jsx-runtime";
|
|
2
|
+
import et, { useRef as nt, useCallback as Y } from "react";
|
|
3
|
+
import { ResponsiveContainer as R, PieChart as rt, Pie as at, Cell as G, Tooltip as D, AreaChart as ot, CartesianGrid as N, XAxis as P, YAxis as K, Legend as j, Area as it, LineChart as lt, Line as st, BarChart as H, Bar as q } from "recharts";
|
|
4
|
+
const r = [
|
|
5
|
+
"#5E88B0",
|
|
6
|
+
// rail-discovery / rail-blue
|
|
7
|
+
"#9B7AA8",
|
|
8
|
+
// rail-purple / rail-tone
|
|
9
|
+
"#C98A5A",
|
|
10
|
+
// rail-compliance / rail-orange
|
|
11
|
+
"#7BA89D",
|
|
12
|
+
// rail-signal-upsell (teal-green)
|
|
13
|
+
"#D17B6B",
|
|
14
|
+
// rail-coral / rail-signal-churn
|
|
15
|
+
"#6B7C93",
|
|
16
|
+
// rail-slate / rail-outcome
|
|
17
|
+
"#9B8E6F",
|
|
18
|
+
// rail-olive / rail-signal-satisfaction
|
|
19
|
+
"#8A9BAF",
|
|
20
|
+
// rail-quality
|
|
21
|
+
"#B8976A",
|
|
22
|
+
// rail-teal (warm gold)
|
|
23
|
+
"#A8C76B"
|
|
24
|
+
// green accent (complementary)
|
|
25
|
+
], V = { fill: "var(--text-muted, #666)", fontSize: 12 }, b = { stroke: "var(--border, #e0e0e0)" }, O = "var(--border, #e0e0e0)", z = {
|
|
26
|
+
contentStyle: {
|
|
27
|
+
backgroundColor: "var(--paper-elevated, #fff)",
|
|
28
|
+
border: "1px solid var(--border, #e0e0e0)",
|
|
29
|
+
borderRadius: "var(--radius-sm, 4px)",
|
|
30
|
+
boxShadow: "0 2px 8px rgba(0, 0, 0, 0.1)",
|
|
31
|
+
color: "var(--text-ink, #1e2125)"
|
|
32
|
+
},
|
|
33
|
+
labelStyle: { color: "var(--text-strong, #1e2125)" }
|
|
34
|
+
}, U = { color: "var(--text-ink, #1e2125)", fontSize: "12px" }, ct = (l, s) => {
|
|
35
|
+
if (!l)
|
|
36
|
+
return !1;
|
|
37
|
+
const c = l.toLowerCase();
|
|
38
|
+
return s.filter((o) => String(o).toLowerCase().includes(c)).length < s.length * 0.5;
|
|
39
|
+
}, dt = async (l, s) => {
|
|
40
|
+
const c = l.querySelector("svg");
|
|
41
|
+
if (!c)
|
|
42
|
+
return;
|
|
43
|
+
const i = c.cloneNode(!0), o = c.clientWidth || 600, h = c.clientHeight || 300;
|
|
44
|
+
i.setAttribute("width", o), i.setAttribute("height", h), i.setAttribute("xmlns", "http://www.w3.org/2000/svg");
|
|
45
|
+
const k = document.createElement("style");
|
|
46
|
+
k.textContent = 'text { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; }', i.insertBefore(k, i.firstChild);
|
|
47
|
+
const C = new XMLSerializer().serializeToString(i), u = new Blob([C], { type: "image/svg+xml;charset=utf-8" }), p = URL.createObjectURL(u), x = new Image();
|
|
48
|
+
x.onload = () => {
|
|
49
|
+
const g = document.createElement("canvas"), S = 2;
|
|
50
|
+
g.width = o * S, g.height = h * S;
|
|
51
|
+
const y = g.getContext("2d");
|
|
52
|
+
y.fillStyle = "#ffffff", y.fillRect(0, 0, g.width, g.height), y.scale(S, S), y.drawImage(x, 0, 0, o, h), URL.revokeObjectURL(p);
|
|
53
|
+
const I = document.createElement("a");
|
|
54
|
+
I.download = `${(s || "chart").replace(/[^a-z0-9]+/gi, "_")}.png`, I.href = g.toDataURL("image/png"), I.click();
|
|
55
|
+
}, x.src = p;
|
|
56
|
+
}, ht = (l, s) => {
|
|
57
|
+
const c = ["", ...l.map((h) => h.name)].join(","), i = s.map((h) => {
|
|
58
|
+
const k = l.map((C) => {
|
|
59
|
+
const u = C.data.find((p) => p.x === h);
|
|
60
|
+
return u ? u.y : "";
|
|
61
|
+
});
|
|
62
|
+
return [h, ...k].join(",");
|
|
63
|
+
}), o = [c, ...i].join(`
|
|
64
|
+
`);
|
|
65
|
+
navigator.clipboard.writeText(o);
|
|
66
|
+
}, pt = ({ onDownload: l, onCopy: s, copied: c }) => /* @__PURE__ */ d("div", { style: {
|
|
67
|
+
display: "flex",
|
|
68
|
+
gap: 6,
|
|
69
|
+
justifyContent: "flex-end",
|
|
70
|
+
marginBottom: 8,
|
|
71
|
+
opacity: 0.7,
|
|
72
|
+
transition: "opacity 0.15s"
|
|
73
|
+
}, children: [
|
|
74
|
+
/* @__PURE__ */ t("button", { onClick: s, title: "Copy data as CSV", style: {
|
|
75
|
+
background: "none",
|
|
76
|
+
border: "1px solid var(--border, #e0e0e0)",
|
|
77
|
+
borderRadius: "var(--radius-sm, 4px)",
|
|
78
|
+
padding: "3px 8px",
|
|
79
|
+
fontSize: 11,
|
|
80
|
+
color: "var(--text-muted, #666)",
|
|
81
|
+
cursor: "pointer",
|
|
82
|
+
display: "flex",
|
|
83
|
+
alignItems: "center",
|
|
84
|
+
gap: 4
|
|
85
|
+
}, children: c ? "✓ Copied" : "📋 CSV" }),
|
|
86
|
+
/* @__PURE__ */ t("button", { onClick: l, title: "Download as PNG", style: {
|
|
87
|
+
background: "none",
|
|
88
|
+
border: "1px solid var(--border, #e0e0e0)",
|
|
89
|
+
borderRadius: "var(--radius-sm, 4px)",
|
|
90
|
+
padding: "3px 8px",
|
|
91
|
+
fontSize: 11,
|
|
92
|
+
color: "var(--text-muted, #666)",
|
|
93
|
+
cursor: "pointer",
|
|
94
|
+
display: "flex",
|
|
95
|
+
alignItems: "center",
|
|
96
|
+
gap: 4
|
|
97
|
+
}, children: "📥 PNG" })
|
|
98
|
+
] }), xt = ({ chartType: l, title: s, xLabel: c, yLabel: i, series: o }) => {
|
|
99
|
+
const h = nt(null), [k, C] = et.useState(!1);
|
|
100
|
+
if (!o || o.length === 0)
|
|
101
|
+
return null;
|
|
102
|
+
const u = [...new Set(o.flatMap((e) => e.data.map((n) => n.x)))], p = u.map((e) => {
|
|
103
|
+
const n = { x: e };
|
|
104
|
+
return o.forEach((f) => {
|
|
105
|
+
const a = f.data.find((m) => m.x === e);
|
|
106
|
+
n[f.name] = a ? a.y : null;
|
|
107
|
+
}), n;
|
|
108
|
+
}), x = o.map((e) => e.name), g = x.length === 1, S = ct(c, u), y = S ? 20 : 5, E = Math.max(...u.map((e) => String(e).length)) > 12 || u.length > 8, $ = {
|
|
109
|
+
background: "var(--paper-elevated, #fff)",
|
|
110
|
+
border: "1px solid var(--border, #e0e0e0)",
|
|
111
|
+
borderRadius: "var(--radius-md, 8px)",
|
|
112
|
+
padding: "16px",
|
|
113
|
+
marginBottom: "16px"
|
|
114
|
+
}, J = {
|
|
115
|
+
color: "var(--text-strong, #1e2125)",
|
|
116
|
+
fontSize: "14px",
|
|
117
|
+
fontWeight: "600",
|
|
118
|
+
marginBottom: "12px"
|
|
119
|
+
}, W = {
|
|
120
|
+
dataKey: "x",
|
|
121
|
+
tick: E ? { fill: "var(--text-muted, #666)", fontSize: 11, angle: -35, textAnchor: "end" } : V,
|
|
122
|
+
axisLine: b,
|
|
123
|
+
tickLine: b,
|
|
124
|
+
...S ? {
|
|
125
|
+
label: { value: c, position: "insideBottom", offset: -10, style: { textAnchor: "middle", fill: "var(--text-muted, #666)" } }
|
|
126
|
+
} : {}
|
|
127
|
+
}, X = {
|
|
128
|
+
tick: V,
|
|
129
|
+
axisLine: b,
|
|
130
|
+
tickLine: b,
|
|
131
|
+
...i ? {
|
|
132
|
+
label: { value: i, angle: -90, position: "insideLeft", style: { textAnchor: "middle", fill: "var(--text-muted, #666)" } }
|
|
133
|
+
} : {}
|
|
134
|
+
}, Q = () => {
|
|
135
|
+
switch (l) {
|
|
136
|
+
case "bar":
|
|
137
|
+
return /* @__PURE__ */ t(R, { width: "100%", height: 300, children: /* @__PURE__ */ d(H, { data: p, margin: { top: 5, right: 30, left: 20, bottom: E ? 40 : y }, children: [
|
|
138
|
+
/* @__PURE__ */ t(N, { strokeDasharray: "3 3", stroke: O }),
|
|
139
|
+
/* @__PURE__ */ t(P, { ...W }),
|
|
140
|
+
/* @__PURE__ */ t(K, { ...X }),
|
|
141
|
+
/* @__PURE__ */ t(D, { ...z }),
|
|
142
|
+
!g && /* @__PURE__ */ t(j, { wrapperStyle: U }),
|
|
143
|
+
x.map((e, n) => /* @__PURE__ */ t(q, { dataKey: e, fill: r[n % r.length], radius: [2, 2, 0, 0], children: g && p.map((f, a) => /* @__PURE__ */ t(G, { fill: r[a % r.length] }, a)) }, e))
|
|
144
|
+
] }) });
|
|
145
|
+
case "horizontal_bar":
|
|
146
|
+
return /* @__PURE__ */ t(R, { width: "100%", height: Math.max(300, p.length * 40), children: /* @__PURE__ */ d(H, { data: p, layout: "vertical", margin: { top: 5, right: 30, left: 100, bottom: 5 }, children: [
|
|
147
|
+
/* @__PURE__ */ t(N, { strokeDasharray: "3 3", stroke: O }),
|
|
148
|
+
/* @__PURE__ */ t(
|
|
149
|
+
P,
|
|
150
|
+
{
|
|
151
|
+
type: "number",
|
|
152
|
+
tick: V,
|
|
153
|
+
axisLine: b,
|
|
154
|
+
tickLine: b,
|
|
155
|
+
...i ? { label: { value: i, position: "insideBottom", offset: -5, style: { textAnchor: "middle", fill: "var(--text-muted, #666)" } } } : {}
|
|
156
|
+
}
|
|
157
|
+
),
|
|
158
|
+
/* @__PURE__ */ t(K, { type: "category", dataKey: "x", tick: { fill: "var(--text-muted, #666)", fontSize: 11 }, width: 90, axisLine: b, tickLine: b }),
|
|
159
|
+
/* @__PURE__ */ t(D, { ...z }),
|
|
160
|
+
!g && /* @__PURE__ */ t(j, { wrapperStyle: U }),
|
|
161
|
+
x.map((e, n) => /* @__PURE__ */ t(q, { dataKey: e, fill: r[n % r.length], radius: [0, 2, 2, 0], children: g && p.map((f, a) => /* @__PURE__ */ t(G, { fill: r[a % r.length] }, a)) }, e))
|
|
162
|
+
] }) });
|
|
163
|
+
case "line":
|
|
164
|
+
return /* @__PURE__ */ t(R, { width: "100%", height: 300, children: /* @__PURE__ */ d(lt, { data: p, margin: { top: 5, right: 30, left: 20, bottom: E ? 40 : y }, children: [
|
|
165
|
+
/* @__PURE__ */ t(N, { strokeDasharray: "3 3", stroke: O }),
|
|
166
|
+
/* @__PURE__ */ t(P, { ...W }),
|
|
167
|
+
/* @__PURE__ */ t(K, { ...X }),
|
|
168
|
+
/* @__PURE__ */ t(D, { ...z }),
|
|
169
|
+
/* @__PURE__ */ t(j, { wrapperStyle: U }),
|
|
170
|
+
x.map((e, n) => /* @__PURE__ */ t(
|
|
171
|
+
st,
|
|
172
|
+
{
|
|
173
|
+
type: "monotone",
|
|
174
|
+
dataKey: e,
|
|
175
|
+
stroke: r[n % r.length],
|
|
176
|
+
strokeWidth: 2,
|
|
177
|
+
dot: { r: 4, fill: r[n % r.length] },
|
|
178
|
+
activeDot: { r: 6, fill: r[n % r.length] }
|
|
179
|
+
},
|
|
180
|
+
e
|
|
181
|
+
))
|
|
182
|
+
] }) });
|
|
183
|
+
case "area":
|
|
184
|
+
return /* @__PURE__ */ t(R, { width: "100%", height: 300, children: /* @__PURE__ */ d(ot, { data: p, margin: { top: 5, right: 30, left: 20, bottom: E ? 40 : y }, children: [
|
|
185
|
+
/* @__PURE__ */ t(N, { strokeDasharray: "3 3", stroke: O }),
|
|
186
|
+
/* @__PURE__ */ t(P, { ...W }),
|
|
187
|
+
/* @__PURE__ */ t(K, { ...X }),
|
|
188
|
+
/* @__PURE__ */ t(D, { ...z }),
|
|
189
|
+
/* @__PURE__ */ t(j, { wrapperStyle: U }),
|
|
190
|
+
x.map((e, n) => /* @__PURE__ */ t(
|
|
191
|
+
it,
|
|
192
|
+
{
|
|
193
|
+
type: "monotone",
|
|
194
|
+
dataKey: e,
|
|
195
|
+
stroke: r[n % r.length],
|
|
196
|
+
strokeWidth: 2,
|
|
197
|
+
fill: r[n % r.length],
|
|
198
|
+
fillOpacity: 0.15
|
|
199
|
+
},
|
|
200
|
+
e
|
|
201
|
+
))
|
|
202
|
+
] }) });
|
|
203
|
+
case "pie": {
|
|
204
|
+
const e = o[0].data.map((a, m) => ({
|
|
205
|
+
name: a.x,
|
|
206
|
+
value: a.y,
|
|
207
|
+
fill: r[m % r.length]
|
|
208
|
+
})), n = Math.PI / 180;
|
|
209
|
+
return /* @__PURE__ */ t(R, { width: "100%", height: 320, children: /* @__PURE__ */ d(rt, { children: [
|
|
210
|
+
/* @__PURE__ */ t(
|
|
211
|
+
at,
|
|
212
|
+
{
|
|
213
|
+
data: e,
|
|
214
|
+
cx: "50%",
|
|
215
|
+
cy: "50%",
|
|
216
|
+
outerRadius: 100,
|
|
217
|
+
dataKey: "value",
|
|
218
|
+
label: ({ cx: a, cy: m, midAngle: w, innerRadius: L, outerRadius: F, percent: A, name: B }) => {
|
|
219
|
+
const M = F + 20, T = a + M * Math.cos(-w * n), _ = m + M * Math.sin(-w * n);
|
|
220
|
+
return A < 0.04 ? null : /* @__PURE__ */ d(
|
|
221
|
+
"text",
|
|
222
|
+
{
|
|
223
|
+
x: T,
|
|
224
|
+
y: _,
|
|
225
|
+
fill: "var(--text-ink, #1e2125)",
|
|
226
|
+
fontSize: 11,
|
|
227
|
+
textAnchor: T > a ? "start" : "end",
|
|
228
|
+
dominantBaseline: "central",
|
|
229
|
+
children: [
|
|
230
|
+
B,
|
|
231
|
+
" (",
|
|
232
|
+
(A * 100).toFixed(0),
|
|
233
|
+
"%)"
|
|
234
|
+
]
|
|
235
|
+
}
|
|
236
|
+
);
|
|
237
|
+
},
|
|
238
|
+
labelLine: { stroke: "var(--text-muted, #666)" },
|
|
239
|
+
children: e.map((a, m) => /* @__PURE__ */ t(G, { fill: a.fill }, m))
|
|
240
|
+
}
|
|
241
|
+
),
|
|
242
|
+
/* @__PURE__ */ t(D, { ...z })
|
|
243
|
+
] }) });
|
|
244
|
+
}
|
|
245
|
+
case "metric": {
|
|
246
|
+
const e = o[0], n = e.data[0], f = e.data.length > 1 ? e.data[1] : null, a = n.y, m = n.x || "", w = f !== null, L = w ? a - f.y : 0, F = w && f.y !== 0 ? L / Math.abs(f.y) * 100 : 0, A = L > 0, B = L < 0, M = A ? "#7BA89D" : B ? "#D17B6B" : "var(--text-muted, #666)", T = A ? "↑" : B ? "↓" : "→", _ = (v) => Number.isInteger(v) && Math.abs(v) >= 1e3 ? v.toLocaleString() : typeof v == "number" ? v % 1 === 0 ? v.toString() : v.toFixed(v < 10 ? 2 : 1) : String(v);
|
|
247
|
+
return /* @__PURE__ */ d("div", { style: { display: "flex", alignItems: "baseline", gap: 12, padding: "8px 0" }, children: [
|
|
248
|
+
/* @__PURE__ */ t("div", { style: {
|
|
249
|
+
fontSize: "36px",
|
|
250
|
+
fontWeight: 700,
|
|
251
|
+
lineHeight: 1,
|
|
252
|
+
color: "var(--text-strong, #1e2125)",
|
|
253
|
+
fontVariantNumeric: "tabular-nums"
|
|
254
|
+
}, children: _(a) }),
|
|
255
|
+
m && /* @__PURE__ */ t("div", { style: { fontSize: "14px", color: "var(--text-muted, #666)", fontWeight: 500 }, children: m }),
|
|
256
|
+
w && /* @__PURE__ */ d("div", { style: {
|
|
257
|
+
display: "flex",
|
|
258
|
+
alignItems: "center",
|
|
259
|
+
gap: 4,
|
|
260
|
+
fontSize: "13px",
|
|
261
|
+
fontWeight: 600,
|
|
262
|
+
color: M,
|
|
263
|
+
background: A ? "rgba(123,168,157,0.12)" : B ? "rgba(209,123,107,0.12)" : "rgba(128,128,128,0.08)",
|
|
264
|
+
padding: "3px 8px",
|
|
265
|
+
borderRadius: "var(--radius-sm, 4px)"
|
|
266
|
+
}, children: [
|
|
267
|
+
/* @__PURE__ */ t("span", { children: T }),
|
|
268
|
+
/* @__PURE__ */ d("span", { children: [
|
|
269
|
+
_(Math.abs(L)),
|
|
270
|
+
" (",
|
|
271
|
+
Math.abs(F).toFixed(1),
|
|
272
|
+
"%)"
|
|
273
|
+
] })
|
|
274
|
+
] }),
|
|
275
|
+
w && /* @__PURE__ */ d("div", { style: { fontSize: "11px", color: "var(--text-faint, #999)" }, children: [
|
|
276
|
+
"vs ",
|
|
277
|
+
f.x || "previous"
|
|
278
|
+
] })
|
|
279
|
+
] });
|
|
280
|
+
}
|
|
281
|
+
default:
|
|
282
|
+
return /* @__PURE__ */ d("div", { style: { color: "var(--text-muted)", fontSize: 12, padding: 8 }, children: [
|
|
283
|
+
"Unsupported chart type: ",
|
|
284
|
+
l
|
|
285
|
+
] });
|
|
286
|
+
}
|
|
287
|
+
}, Z = Y(() => {
|
|
288
|
+
h.current && dt(h.current, s);
|
|
289
|
+
}, [s]), tt = Y(() => {
|
|
290
|
+
ht(o, u), C(!0), setTimeout(() => C(!1), 2e3);
|
|
291
|
+
}, [o, u]);
|
|
292
|
+
return /* @__PURE__ */ d("div", { style: $, children: [
|
|
293
|
+
s && /* @__PURE__ */ t("div", { style: J, children: s }),
|
|
294
|
+
l !== "metric" && /* @__PURE__ */ t(pt, { onDownload: Z, onCopy: tt, copied: k }),
|
|
295
|
+
/* @__PURE__ */ t("div", { ref: h, children: Q() })
|
|
296
|
+
] });
|
|
297
|
+
};
|
|
298
|
+
export {
|
|
299
|
+
xt as C
|
|
300
|
+
};
|
|
301
|
+
//# sourceMappingURL=ChartRenderer.es.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChartRenderer.es.js","sources":["../src/components/chat/ChartRenderer.jsx"],"sourcesContent":["\"use client\";\nimport React, { useRef, useCallback } from 'react';\nimport {\n ResponsiveContainer, BarChart, Bar, Cell, LineChart, Line,\n XAxis, YAxis, CartesianGrid, Tooltip, Legend,\n PieChart, Pie, AreaChart, Area,\n} from 'recharts';\n\n// Chordia design system rail colors — ordered for max visual distinction\nconst COLORS = [\n '#5E88B0', // rail-discovery / rail-blue\n '#9B7AA8', // rail-purple / rail-tone\n '#C98A5A', // rail-compliance / rail-orange\n '#7BA89D', // rail-signal-upsell (teal-green)\n '#D17B6B', // rail-coral / rail-signal-churn\n '#6B7C93', // rail-slate / rail-outcome\n '#9B8E6F', // rail-olive / rail-signal-satisfaction\n '#8A9BAF', // rail-quality\n '#B8976A', // rail-teal (warm gold)\n '#A8C76B', // green accent (complementary)\n];\n\n// Shared axis/tooltip/legend styling\nconst AXIS_TICK = { fill: 'var(--text-muted, #666)', fontSize: 12 };\nconst AXIS_LINE = { stroke: 'var(--border, #e0e0e0)' };\nconst GRID_STROKE = 'var(--border, #e0e0e0)';\nconst TOOLTIP_STYLE = {\n contentStyle: {\n backgroundColor: 'var(--paper-elevated, #fff)',\n border: '1px solid var(--border, #e0e0e0)',\n borderRadius: 'var(--radius-sm, 4px)',\n boxShadow: '0 2px 8px rgba(0, 0, 0, 0.1)',\n color: 'var(--text-ink, #1e2125)',\n },\n labelStyle: { color: 'var(--text-strong, #1e2125)' },\n};\nconst LEGEND_STYLE = { color: 'var(--text-ink, #1e2125)', fontSize: '12px' };\n\n// Smart label: skip x_label if tick values already contain the label text\nconst shouldShowAxisLabel = (label, tickValues) => {\n if (!label) return false;\n const lower = label.toLowerCase();\n // If most ticks contain the label word, it's redundant\n const matches = tickValues.filter(v => String(v).toLowerCase().includes(lower));\n return matches.length < tickValues.length * 0.5;\n};\n\n// --- Export utilities ---\nconst downloadPng = async (containerEl, title) => {\n const svg = containerEl.querySelector('svg');\n if (!svg) return;\n const clone = svg.cloneNode(true);\n // Ensure dimensions\n const w = svg.clientWidth || 600;\n const h = svg.clientHeight || 300;\n clone.setAttribute('width', w);\n clone.setAttribute('height', h);\n clone.setAttribute('xmlns', 'http://www.w3.org/2000/svg');\n // Inline computed styles for export fidelity\n const styleEl = document.createElement('style');\n styleEl.textContent = `text { font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif; }`;\n clone.insertBefore(styleEl, clone.firstChild);\n const xml = new XMLSerializer().serializeToString(clone);\n const blob = new Blob([xml], { type: 'image/svg+xml;charset=utf-8' });\n const url = URL.createObjectURL(blob);\n const img = new Image();\n img.onload = () => {\n const canvas = document.createElement('canvas');\n const scale = 2; // retina\n canvas.width = w * scale;\n canvas.height = h * scale;\n const ctx = canvas.getContext('2d');\n ctx.fillStyle = '#ffffff';\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n ctx.scale(scale, scale);\n ctx.drawImage(img, 0, 0, w, h);\n URL.revokeObjectURL(url);\n const link = document.createElement('a');\n link.download = `${(title || 'chart').replace(/[^a-z0-9]+/gi, '_')}.png`;\n link.href = canvas.toDataURL('image/png');\n link.click();\n };\n img.src = url;\n};\n\nconst copyAsCsv = (series, allXValues) => {\n const header = ['', ...series.map(s => s.name)].join(',');\n const rows = allXValues.map(x => {\n const vals = series.map(s => {\n const match = s.data.find(d => d.x === x);\n return match ? match.y : '';\n });\n return [x, ...vals].join(',');\n });\n const csv = [header, ...rows].join('\\n');\n navigator.clipboard.writeText(csv);\n};\n\nconst ActionBar = ({ onDownload, onCopy, copied }) => (\n <div style={{\n display: 'flex', gap: 6, justifyContent: 'flex-end',\n marginBottom: 8, opacity: 0.7, transition: 'opacity 0.15s',\n }}>\n <button onClick={onCopy} title=\"Copy data as CSV\" style={{\n background: 'none', border: '1px solid var(--border, #e0e0e0)',\n borderRadius: 'var(--radius-sm, 4px)', padding: '3px 8px',\n fontSize: 11, color: 'var(--text-muted, #666)', cursor: 'pointer',\n display: 'flex', alignItems: 'center', gap: 4,\n }}>\n {copied ? '✓ Copied' : '📋 CSV'}\n </button>\n <button onClick={onDownload} title=\"Download as PNG\" style={{\n background: 'none', border: '1px solid var(--border, #e0e0e0)',\n borderRadius: 'var(--radius-sm, 4px)', padding: '3px 8px',\n fontSize: 11, color: 'var(--text-muted, #666)', cursor: 'pointer',\n display: 'flex', alignItems: 'center', gap: 4,\n }}>\n 📥 PNG\n </button>\n </div>\n);\n\nconst ChartRenderer = ({ chartType, title, xLabel, yLabel, series }) => {\n const chartRef = useRef(null);\n const [copied, setCopied] = React.useState(false);\n\n if (!series || series.length === 0) return null;\n\n // Transform: merge all series into [{x, series1: val, series2: val}, ...]\n const allXValues = [...new Set(series.flatMap(s => s.data.map(d => d.x)))];\n const chartData = allXValues.map(x => {\n const point = { x };\n series.forEach(s => {\n const match = s.data.find(d => d.x === x);\n point[s.name] = match ? match.y : null;\n });\n return point;\n });\n\n const seriesNames = series.map(s => s.name);\n const isSingleSeries = seriesNames.length === 1;\n\n // Determine if axis labels are redundant\n const showXLabel = shouldShowAxisLabel(xLabel, allXValues);\n const bottomMargin = showXLabel ? 20 : 5;\n\n // Check if x-axis labels are long (rotate them)\n const maxTickLen = Math.max(...allXValues.map(v => String(v).length));\n const rotateXTicks = maxTickLen > 12 || allXValues.length > 8;\n\n const containerStyle = {\n background: 'var(--paper-elevated, #fff)',\n border: '1px solid var(--border, #e0e0e0)',\n borderRadius: 'var(--radius-md, 8px)',\n padding: '16px',\n marginBottom: '16px',\n };\n\n const titleStyle = {\n color: 'var(--text-strong, #1e2125)',\n fontSize: '14px',\n fontWeight: '600',\n marginBottom: '12px',\n };\n\n const xAxisProps = {\n dataKey: 'x',\n tick: rotateXTicks\n ? { fill: 'var(--text-muted, #666)', fontSize: 11, angle: -35, textAnchor: 'end' }\n : AXIS_TICK,\n axisLine: AXIS_LINE,\n tickLine: AXIS_LINE,\n ...(showXLabel ? {\n label: { value: xLabel, position: 'insideBottom', offset: -10, style: { textAnchor: 'middle', fill: 'var(--text-muted, #666)' } }\n } : {}),\n };\n\n const yAxisProps = {\n tick: AXIS_TICK,\n axisLine: AXIS_LINE,\n tickLine: AXIS_LINE,\n ...(yLabel ? {\n label: { value: yLabel, angle: -90, position: 'insideLeft', style: { textAnchor: 'middle', fill: 'var(--text-muted, #666)' } }\n } : {}),\n };\n\n const renderChart = () => {\n switch (chartType) {\n case 'bar':\n return (\n <ResponsiveContainer width=\"100%\" height={300}>\n <BarChart data={chartData} margin={{ top: 5, right: 30, left: 20, bottom: rotateXTicks ? 40 : bottomMargin }}>\n <CartesianGrid strokeDasharray=\"3 3\" stroke={GRID_STROKE} />\n <XAxis {...xAxisProps} />\n <YAxis {...yAxisProps} />\n <Tooltip {...TOOLTIP_STYLE} />\n {!isSingleSeries && <Legend wrapperStyle={LEGEND_STYLE} />}\n {seriesNames.map((name, i) => (\n <Bar key={name} dataKey={name} fill={COLORS[i % COLORS.length]} radius={[2, 2, 0, 0]}>\n {isSingleSeries && chartData.map((_, idx) => (\n <Cell key={idx} fill={COLORS[idx % COLORS.length]} />\n ))}\n </Bar>\n ))}\n </BarChart>\n </ResponsiveContainer>\n );\n\n case 'horizontal_bar': {\n // Horizontal bar: swap X/Y, use YAxis for categories\n return (\n <ResponsiveContainer width=\"100%\" height={Math.max(300, chartData.length * 40)}>\n <BarChart data={chartData} layout=\"vertical\" margin={{ top: 5, right: 30, left: 100, bottom: 5 }}>\n <CartesianGrid strokeDasharray=\"3 3\" stroke={GRID_STROKE} />\n <XAxis type=\"number\" tick={AXIS_TICK} axisLine={AXIS_LINE} tickLine={AXIS_LINE}\n {...(yLabel ? { label: { value: yLabel, position: 'insideBottom', offset: -5, style: { textAnchor: 'middle', fill: 'var(--text-muted, #666)' } } } : {})}\n />\n <YAxis type=\"category\" dataKey=\"x\" tick={{ fill: 'var(--text-muted, #666)', fontSize: 11 }} width={90} axisLine={AXIS_LINE} tickLine={AXIS_LINE} />\n <Tooltip {...TOOLTIP_STYLE} />\n {!isSingleSeries && <Legend wrapperStyle={LEGEND_STYLE} />}\n {seriesNames.map((name, i) => (\n <Bar key={name} dataKey={name} fill={COLORS[i % COLORS.length]} radius={[0, 2, 2, 0]}>\n {isSingleSeries && chartData.map((_, idx) => (\n <Cell key={idx} fill={COLORS[idx % COLORS.length]} />\n ))}\n </Bar>\n ))}\n </BarChart>\n </ResponsiveContainer>\n );\n }\n\n case 'line':\n return (\n <ResponsiveContainer width=\"100%\" height={300}>\n <LineChart data={chartData} margin={{ top: 5, right: 30, left: 20, bottom: rotateXTicks ? 40 : bottomMargin }}>\n <CartesianGrid strokeDasharray=\"3 3\" stroke={GRID_STROKE} />\n <XAxis {...xAxisProps} />\n <YAxis {...yAxisProps} />\n <Tooltip {...TOOLTIP_STYLE} />\n <Legend wrapperStyle={LEGEND_STYLE} />\n {seriesNames.map((name, i) => (\n <Line key={name} type=\"monotone\" dataKey={name}\n stroke={COLORS[i % COLORS.length]} strokeWidth={2}\n dot={{ r: 4, fill: COLORS[i % COLORS.length] }}\n activeDot={{ r: 6, fill: COLORS[i % COLORS.length] }}\n />\n ))}\n </LineChart>\n </ResponsiveContainer>\n );\n\n case 'area':\n return (\n <ResponsiveContainer width=\"100%\" height={300}>\n <AreaChart data={chartData} margin={{ top: 5, right: 30, left: 20, bottom: rotateXTicks ? 40 : bottomMargin }}>\n <CartesianGrid strokeDasharray=\"3 3\" stroke={GRID_STROKE} />\n <XAxis {...xAxisProps} />\n <YAxis {...yAxisProps} />\n <Tooltip {...TOOLTIP_STYLE} />\n <Legend wrapperStyle={LEGEND_STYLE} />\n {seriesNames.map((name, i) => (\n <Area key={name} type=\"monotone\" dataKey={name}\n stroke={COLORS[i % COLORS.length]} strokeWidth={2}\n fill={COLORS[i % COLORS.length]} fillOpacity={0.15}\n />\n ))}\n </AreaChart>\n </ResponsiveContainer>\n );\n\n case 'pie': {\n // Pie uses first series only\n const pieData = series[0].data.map((d, i) => ({\n name: d.x,\n value: d.y,\n fill: COLORS[i % COLORS.length],\n }));\n const RADIAN = Math.PI / 180;\n const renderLabel = ({ cx, cy, midAngle, innerRadius, outerRadius, percent, name }) => {\n const radius = outerRadius + 20;\n const x = cx + radius * Math.cos(-midAngle * RADIAN);\n const y = cy + radius * Math.sin(-midAngle * RADIAN);\n if (percent < 0.04) return null;\n return (\n <text x={x} y={y} fill=\"var(--text-ink, #1e2125)\" fontSize={11}\n textAnchor={x > cx ? 'start' : 'end'} dominantBaseline=\"central\">\n {name} ({(percent * 100).toFixed(0)}%)\n </text>\n );\n };\n return (\n <ResponsiveContainer width=\"100%\" height={320}>\n <PieChart>\n <Pie data={pieData} cx=\"50%\" cy=\"50%\" outerRadius={100}\n dataKey=\"value\" label={renderLabel} labelLine={{ stroke: 'var(--text-muted, #666)' }}>\n {pieData.map((entry, i) => (\n <Cell key={i} fill={entry.fill} />\n ))}\n </Pie>\n <Tooltip {...TOOLTIP_STYLE} />\n </PieChart>\n </ResponsiveContainer>\n );\n }\n\n case 'metric': {\n const s = series[0];\n const current = s.data[0];\n const previous = s.data.length > 1 ? s.data[1] : null;\n const value = current.y;\n const unit = current.x || '';\n const hasTrend = previous !== null;\n const change = hasTrend ? value - previous.y : 0;\n const pctChange = hasTrend && previous.y !== 0 ? ((change / Math.abs(previous.y)) * 100) : 0;\n const isPositive = change > 0;\n const isNegative = change < 0;\n const trendColor = isPositive ? '#7BA89D' : isNegative ? '#D17B6B' : 'var(--text-muted, #666)';\n const trendArrow = isPositive ? '↑' : isNegative ? '↓' : '→';\n\n // Format large numbers nicely\n const fmt = (n) => {\n if (Number.isInteger(n) && Math.abs(n) >= 1000) return n.toLocaleString();\n if (typeof n === 'number') return n % 1 === 0 ? n.toString() : n.toFixed(n < 10 ? 2 : 1);\n return String(n);\n };\n\n return (\n <div style={{ display: 'flex', alignItems: 'baseline', gap: 12, padding: '8px 0' }}>\n <div style={{\n fontSize: '36px', fontWeight: 700, lineHeight: 1,\n color: 'var(--text-strong, #1e2125)',\n fontVariantNumeric: 'tabular-nums',\n }}>\n {fmt(value)}\n </div>\n {unit && (\n <div style={{ fontSize: '14px', color: 'var(--text-muted, #666)', fontWeight: 500 }}>\n {unit}\n </div>\n )}\n {hasTrend && (\n <div style={{\n display: 'flex', alignItems: 'center', gap: 4,\n fontSize: '13px', fontWeight: 600, color: trendColor,\n background: isPositive ? 'rgba(123,168,157,0.12)' : isNegative ? 'rgba(209,123,107,0.12)' : 'rgba(128,128,128,0.08)',\n padding: '3px 8px', borderRadius: 'var(--radius-sm, 4px)',\n }}>\n <span>{trendArrow}</span>\n <span>{fmt(Math.abs(change))} ({Math.abs(pctChange).toFixed(1)}%)</span>\n </div>\n )}\n {hasTrend && (\n <div style={{ fontSize: '11px', color: 'var(--text-faint, #999)' }}>\n vs {previous.x || 'previous'}\n </div>\n )}\n </div>\n );\n }\n\n default:\n return <div style={{ color: 'var(--text-muted)', fontSize: 12, padding: 8 }}>Unsupported chart type: {chartType}</div>;\n }\n };\n\n const handleDownload = useCallback(() => {\n if (chartRef.current) downloadPng(chartRef.current, title);\n }, [title]);\n\n const handleCopy = useCallback(() => {\n copyAsCsv(series, allXValues);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n }, [series, allXValues]);\n\n const showActions = chartType !== 'metric';\n\n return (\n <div style={containerStyle}>\n {title && <div style={titleStyle}>{title}</div>}\n {showActions && <ActionBar onDownload={handleDownload} onCopy={handleCopy} copied={copied} />}\n <div ref={chartRef}>\n {renderChart()}\n </div>\n </div>\n );\n};\n\nexport default ChartRenderer;\n"],"names":["COLORS","AXIS_TICK","AXIS_LINE","GRID_STROKE","TOOLTIP_STYLE","LEGEND_STYLE","shouldShowAxisLabel","label","tickValues","lower","v","downloadPng","containerEl","title","svg","clone","w","styleEl","xml","blob","url","img","canvas","scale","ctx","link","copyAsCsv","series","allXValues","header","s","rows","x","vals","match","d","csv","ActionBar","onDownload","onCopy","copied","jsxs","jsx","ChartRenderer","chartType","xLabel","yLabel","chartRef","useRef","setCopied","React","chartData","point","seriesNames","isSingleSeries","showXLabel","bottomMargin","rotateXTicks","containerStyle","titleStyle","xAxisProps","yAxisProps","renderChart","ResponsiveContainer","BarChart","CartesianGrid","XAxis","YAxis","Tooltip","Legend","name","i","Bar","_","idx","Cell","LineChart","Line","AreaChart","Area","pieData","RADIAN","PieChart","Pie","cx","cy","midAngle","innerRadius","outerRadius","percent","radius","y","entry","current","previous","value","unit","hasTrend","change","pctChange","isPositive","isNegative","trendColor","trendArrow","fmt","n","handleDownload","useCallback","handleCopy"],"mappings":";;;AASA,MAAMA,IAAS;AAAA,EACb;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AACF,GAGMC,IAAY,EAAE,MAAM,2BAA2B,UAAU,GAAG,GAC5DC,IAAY,EAAE,QAAQ,4BACtBC,IAAc,0BACdC,IAAgB;AAAA,EACpB,cAAc;AAAA,IACZ,iBAAiB;AAAA,IACjB,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,WAAW;AAAA,IACX,OAAO;AAAA,EACT;AAAA,EACA,YAAY,EAAE,OAAO,8BAA8B;AACrD,GACMC,IAAe,EAAE,OAAO,4BAA4B,UAAU,OAAO,GAGrEC,KAAsB,CAACC,GAAOC,MAAe;AACjD,MAAI,CAACD;AAAc,WAAA;AACb,QAAAE,IAAQF,EAAM;AAGb,SADSC,EAAW,OAAO,CAAKE,MAAA,OAAOA,CAAC,EAAE,YAAY,EAAE,SAASD,CAAK,CAAC,EAC/D,SAASD,EAAW,SAAS;AAC9C,GAGMG,KAAc,OAAOC,GAAaC,MAAU;AAC1C,QAAAC,IAAMF,EAAY,cAAc,KAAK;AAC3C,MAAI,CAACE;AAAK;AACJ,QAAAC,IAAQD,EAAI,UAAU,EAAI,GAE1BE,IAAIF,EAAI,eAAe,KACvB,IAAIA,EAAI,gBAAgB;AACxB,EAAAC,EAAA,aAAa,SAASC,CAAC,GACvBD,EAAA,aAAa,UAAU,CAAC,GACxBA,EAAA,aAAa,SAAS,4BAA4B;AAElD,QAAAE,IAAU,SAAS,cAAc,OAAO;AAC9C,EAAAA,EAAQ,cAAc,4FAChBF,EAAA,aAAaE,GAASF,EAAM,UAAU;AAC5C,QAAMG,IAAM,IAAI,cAAc,EAAE,kBAAkBH,CAAK,GACjDI,IAAO,IAAI,KAAK,CAACD,CAAG,GAAG,EAAE,MAAM,8BAAA,CAA+B,GAC9DE,IAAM,IAAI,gBAAgBD,CAAI,GAC9BE,IAAM,IAAI;AAChB,EAAAA,EAAI,SAAS,MAAM;AACX,UAAAC,IAAS,SAAS,cAAc,QAAQ,GACxCC,IAAQ;AACd,IAAAD,EAAO,QAAQN,IAAIO,GACnBD,EAAO,SAAS,IAAIC;AACd,UAAAC,IAAMF,EAAO,WAAW,IAAI;AAClC,IAAAE,EAAI,YAAY,WAChBA,EAAI,SAAS,GAAG,GAAGF,EAAO,OAAOA,EAAO,MAAM,GAC1CE,EAAA,MAAMD,GAAOA,CAAK,GACtBC,EAAI,UAAUH,GAAK,GAAG,GAAGL,GAAG,CAAC,GAC7B,IAAI,gBAAgBI,CAAG;AACjB,UAAAK,IAAO,SAAS,cAAc,GAAG;AACvC,IAAAA,EAAK,WAAW,IAAIZ,KAAS,SAAS,QAAQ,gBAAgB,GAAG,CAAC,QAC7DY,EAAA,OAAOH,EAAO,UAAU,WAAW,GACxCG,EAAK,MAAM;AAAA,EAAA,GAEbJ,EAAI,MAAMD;AACZ,GAEMM,KAAY,CAACC,GAAQC,MAAe;AACxC,QAAMC,IAAS,CAAC,IAAI,GAAGF,EAAO,IAAI,CAAKG,MAAAA,EAAE,IAAI,CAAC,EAAE,KAAK,GAAG,GAClDC,IAAOH,EAAW,IAAI,CAAKI,MAAA;AACzB,UAAAC,IAAON,EAAO,IAAI,CAAKG,MAAA;AAC3B,YAAMI,IAAQJ,EAAE,KAAK,KAAK,CAAKK,MAAAA,EAAE,MAAMH,CAAC;AACjC,aAAAE,IAAQA,EAAM,IAAI;AAAA,IAAA,CAC1B;AACD,WAAO,CAACF,GAAG,GAAGC,CAAI,EAAE,KAAK,GAAG;AAAA,EAAA,CAC7B,GACKG,IAAM,CAACP,GAAQ,GAAGE,CAAI,EAAE,KAAK;AAAA,CAAI;AAC7B,YAAA,UAAU,UAAUK,CAAG;AACnC,GAEMC,KAAY,CAAC,EAAE,YAAAC,GAAY,QAAAC,GAAQ,QAAAC,EAAO,MAC7C,gBAAAC,EAAA,OAAA,EAAI,OAAO;AAAA,EACV,SAAS;AAAA,EAAQ,KAAK;AAAA,EAAG,gBAAgB;AAAA,EACzC,cAAc;AAAA,EAAG,SAAS;AAAA,EAAK,YAAY;AAC7C,GACE,UAAA;AAAA,EAAA,gBAAAC,EAAC,UAAO,EAAA,SAASH,GAAQ,OAAM,oBAAmB,OAAO;AAAA,IACvD,YAAY;AAAA,IAAQ,QAAQ;AAAA,IAC5B,cAAc;AAAA,IAAyB,SAAS;AAAA,IAChD,UAAU;AAAA,IAAI,OAAO;AAAA,IAA2B,QAAQ;AAAA,IACxD,SAAS;AAAA,IAAQ,YAAY;AAAA,IAAU,KAAK;AAAA,EAC9C,GACG,UAASC,IAAA,aAAa,SACzB,CAAA;AAAA,oBACC,UAAO,EAAA,SAASF,GAAY,OAAM,mBAAkB,OAAO;AAAA,IAC1D,YAAY;AAAA,IAAQ,QAAQ;AAAA,IAC5B,cAAc;AAAA,IAAyB,SAAS;AAAA,IAChD,UAAU;AAAA,IAAI,OAAO;AAAA,IAA2B,QAAQ;AAAA,IACxD,SAAS;AAAA,IAAQ,YAAY;AAAA,IAAU,KAAK;AAAA,EAAA,GAC3C,UAEH,UAAA;AAAA,EACF,CAAA,GAGIK,KAAgB,CAAC,EAAE,WAAAC,GAAW,OAAA/B,GAAO,QAAAgC,GAAQ,QAAAC,GAAQ,QAAAnB,QAAa;AAChE,QAAAoB,IAAWC,GAAO,IAAI,GACtB,CAACR,GAAQS,CAAS,IAAIC,GAAM,SAAS,EAAK;AAE5C,MAAA,CAACvB,KAAUA,EAAO,WAAW;AAAU,WAAA;AAG3C,QAAMC,IAAa,CAAC,GAAG,IAAI,IAAID,EAAO,QAAQ,CAAAG,MAAKA,EAAE,KAAK,IAAI,CAAKK,MAAAA,EAAE,CAAC,CAAC,CAAC,CAAC,GACnEgB,IAAYvB,EAAW,IAAI,CAAKI,MAAA;AAC9B,UAAAoB,IAAQ,EAAE,GAAApB;AAChB,WAAAL,EAAO,QAAQ,CAAKG,MAAA;AAClB,YAAMI,IAAQJ,EAAE,KAAK,KAAK,CAAKK,MAAAA,EAAE,MAAMH,CAAC;AACxC,MAAAoB,EAAMtB,EAAE,IAAI,IAAII,IAAQA,EAAM,IAAI;AAAA,IAAA,CACnC,GACMkB;AAAA,EAAA,CACR,GAEKC,IAAc1B,EAAO,IAAI,CAAAG,MAAKA,EAAE,IAAI,GACpCwB,IAAiBD,EAAY,WAAW,GAGxCE,IAAajD,GAAoBuC,GAAQjB,CAAU,GACnD4B,IAAeD,IAAa,KAAK,GAIjCE,IADa,KAAK,IAAI,GAAG7B,EAAW,IAAI,CAAAlB,MAAK,OAAOA,CAAC,EAAE,MAAM,CAAC,IAClC,MAAMkB,EAAW,SAAS,GAEtD8B,IAAiB;AAAA,IACrB,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,SAAS;AAAA,IACT,cAAc;AAAA,EAAA,GAGVC,IAAa;AAAA,IACjB,OAAO;AAAA,IACP,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,cAAc;AAAA,EAAA,GAGVC,IAAa;AAAA,IACjB,SAAS;AAAA,IACT,MAAMH,IACF,EAAE,MAAM,2BAA2B,UAAU,IAAI,OAAO,KAAK,YAAY,MACzE,IAAAxD;AAAA,IACJ,UAAUC;AAAA,IACV,UAAUA;AAAA,IACV,GAAIqD,IAAa;AAAA,MACf,OAAO,EAAE,OAAOV,GAAQ,UAAU,gBAAgB,QAAQ,KAAK,OAAO,EAAE,YAAY,UAAU,MAAM,4BAA4B;AAAA,IAAA,IAC9H,CAAC;AAAA,EAAA,GAGDgB,IAAa;AAAA,IACjB,MAAM5D;AAAA,IACN,UAAUC;AAAA,IACV,UAAUA;AAAA,IACV,GAAI4C,IAAS;AAAA,MACX,OAAO,EAAE,OAAOA,GAAQ,OAAO,KAAK,UAAU,cAAc,OAAO,EAAE,YAAY,UAAU,MAAM,4BAA4B;AAAA,IAAA,IAC3H,CAAC;AAAA,EAAA,GAGDgB,IAAc,MAAM;AACxB,YAAQlB,GAAW;AAAA,MACjB,KAAK;AAED,eAAA,gBAAAF,EAACqB,KAAoB,OAAM,QAAO,QAAQ,KACxC,UAAA,gBAAAtB,EAACuB,GAAS,EAAA,MAAMb,GAAW,QAAQ,EAAE,KAAK,GAAG,OAAO,IAAI,MAAM,IAAI,QAAQM,IAAe,KAAKD,EAAA,GAC5F,UAAA;AAAA,UAAA,gBAAAd,EAACuB,GAAc,EAAA,iBAAgB,OAAM,QAAQ9D,GAAa;AAAA,UAC1D,gBAAAuC,EAACwB,GAAO,EAAA,GAAGN,GAAY;AAAA,UACvB,gBAAAlB,EAACyB,GAAO,EAAA,GAAGN,GAAY;AAAA,UACvB,gBAAAnB,EAAC0B,GAAS,EAAA,GAAGhE,GAAe;AAAA,UAC3B,CAACkD,KAAmB,gBAAAZ,EAAA2B,GAAA,EAAO,cAAchE,EAAc,CAAA;AAAA,UACvDgD,EAAY,IAAI,CAACiB,GAAMC,MACtB,gBAAA7B,EAAC8B,KAAe,SAASF,GAAM,MAAMtE,EAAOuE,IAAIvE,EAAO,MAAM,GAAG,QAAQ,CAAC,GAAG,GAAG,GAAG,CAAC,GAChF,eAAkBmD,EAAU,IAAI,CAACsB,GAAGC,wBAClCC,GAAe,EAAA,MAAM3E,EAAO0E,IAAM1E,EAAO,MAAM,EAAA,GAArC0E,CAAwC,CACpD,KAHOJ,CAIV,CACD;AAAA,QAAA,EACH,CAAA,EACF,CAAA;AAAA,MAGJ,KAAK;AAEH,eACG,gBAAA5B,EAAAqB,GAAA,EAAoB,OAAM,QAAO,QAAQ,KAAK,IAAI,KAAKZ,EAAU,SAAS,EAAE,GAC3E,UAAC,gBAAAV,EAAAuB,GAAA,EAAS,MAAMb,GAAW,QAAO,YAAW,QAAQ,EAAE,KAAK,GAAG,OAAO,IAAI,MAAM,KAAK,QAAQ,EAC3F,GAAA,UAAA;AAAA,UAAA,gBAAAT,EAACuB,GAAc,EAAA,iBAAgB,OAAM,QAAQ9D,GAAa;AAAA,UAC1D,gBAAAuC;AAAA,YAACwB;AAAA,YAAA;AAAA,cAAM,MAAK;AAAA,cAAS,MAAMjE;AAAA,cAAW,UAAUC;AAAA,cAAW,UAAUA;AAAA,cAClE,GAAI4C,IAAS,EAAE,OAAO,EAAE,OAAOA,GAAQ,UAAU,gBAAgB,QAAQ,IAAI,OAAO,EAAE,YAAY,UAAU,MAAM,4BAA4B,EAAA,IAAM,CAAC;AAAA,YAAA;AAAA,UACxJ;AAAA,4BACCqB,GAAM,EAAA,MAAK,YAAW,SAAQ,KAAI,MAAM,EAAE,MAAM,2BAA2B,UAAU,GAAM,GAAA,OAAO,IAAI,UAAUjE,GAAW,UAAUA,GAAW;AAAA,UACjJ,gBAAAwC,EAAC0B,GAAS,EAAA,GAAGhE,GAAe;AAAA,UAC3B,CAACkD,KAAmB,gBAAAZ,EAAA2B,GAAA,EAAO,cAAchE,EAAc,CAAA;AAAA,UACvDgD,EAAY,IAAI,CAACiB,GAAMC,MACtB,gBAAA7B,EAAC8B,KAAe,SAASF,GAAM,MAAMtE,EAAOuE,IAAIvE,EAAO,MAAM,GAAG,QAAQ,CAAC,GAAG,GAAG,GAAG,CAAC,GAChF,eAAkBmD,EAAU,IAAI,CAACsB,GAAGC,wBAClCC,GAAe,EAAA,MAAM3E,EAAO0E,IAAM1E,EAAO,MAAM,EAAA,GAArC0E,CAAwC,CACpD,KAHOJ,CAIV,CACD;AAAA,QAAA,EACH,CAAA,EACF,CAAA;AAAA,MAIJ,KAAK;AAED,eAAA,gBAAA5B,EAACqB,KAAoB,OAAM,QAAO,QAAQ,KACxC,UAAA,gBAAAtB,EAACmC,IAAU,EAAA,MAAMzB,GAAW,QAAQ,EAAE,KAAK,GAAG,OAAO,IAAI,MAAM,IAAI,QAAQM,IAAe,KAAKD,EAAA,GAC7F,UAAA;AAAA,UAAA,gBAAAd,EAACuB,GAAc,EAAA,iBAAgB,OAAM,QAAQ9D,GAAa;AAAA,UAC1D,gBAAAuC,EAACwB,GAAO,EAAA,GAAGN,GAAY;AAAA,UACvB,gBAAAlB,EAACyB,GAAO,EAAA,GAAGN,GAAY;AAAA,UACvB,gBAAAnB,EAAC0B,GAAS,EAAA,GAAGhE,GAAe;AAAA,UAC5B,gBAAAsC,EAAC2B,GAAO,EAAA,cAAchE,EAAc,CAAA;AAAA,UACnCgD,EAAY,IAAI,CAACiB,GAAMC,MACtB,gBAAA7B;AAAA,YAACmC;AAAA,YAAA;AAAA,cAAgB,MAAK;AAAA,cAAW,SAASP;AAAA,cACxC,QAAQtE,EAAOuE,IAAIvE,EAAO,MAAM;AAAA,cAAG,aAAa;AAAA,cAChD,KAAK,EAAE,GAAG,GAAG,MAAMA,EAAOuE,IAAIvE,EAAO,MAAM,EAAE;AAAA,cAC7C,WAAW,EAAE,GAAG,GAAG,MAAMA,EAAOuE,IAAIvE,EAAO,MAAM,EAAE;AAAA,YAAA;AAAA,YAH1CsE;AAAA,UAAA,CAKZ;AAAA,QAAA,EACH,CAAA,EACF,CAAA;AAAA,MAGJ,KAAK;AAED,eAAA,gBAAA5B,EAACqB,KAAoB,OAAM,QAAO,QAAQ,KACxC,UAAA,gBAAAtB,EAACqC,IAAU,EAAA,MAAM3B,GAAW,QAAQ,EAAE,KAAK,GAAG,OAAO,IAAI,MAAM,IAAI,QAAQM,IAAe,KAAKD,EAAA,GAC7F,UAAA;AAAA,UAAA,gBAAAd,EAACuB,GAAc,EAAA,iBAAgB,OAAM,QAAQ9D,GAAa;AAAA,UAC1D,gBAAAuC,EAACwB,GAAO,EAAA,GAAGN,GAAY;AAAA,UACvB,gBAAAlB,EAACyB,GAAO,EAAA,GAAGN,GAAY;AAAA,UACvB,gBAAAnB,EAAC0B,GAAS,EAAA,GAAGhE,GAAe;AAAA,UAC5B,gBAAAsC,EAAC2B,GAAO,EAAA,cAAchE,EAAc,CAAA;AAAA,UACnCgD,EAAY,IAAI,CAACiB,GAAMC,MACtB,gBAAA7B;AAAA,YAACqC;AAAA,YAAA;AAAA,cAAgB,MAAK;AAAA,cAAW,SAAST;AAAA,cACxC,QAAQtE,EAAOuE,IAAIvE,EAAO,MAAM;AAAA,cAAG,aAAa;AAAA,cAChD,MAAMA,EAAOuE,IAAIvE,EAAO,MAAM;AAAA,cAAG,aAAa;AAAA,YAAA;AAAA,YAFrCsE;AAAA,UAAA,CAIZ;AAAA,QAAA,EACH,CAAA,EACF,CAAA;AAAA,MAGJ,KAAK,OAAO;AAEJ,cAAAU,IAAUrD,EAAO,CAAC,EAAE,KAAK,IAAI,CAACQ,GAAGoC,OAAO;AAAA,UAC5C,MAAMpC,EAAE;AAAA,UACR,OAAOA,EAAE;AAAA,UACT,MAAMnC,EAAOuE,IAAIvE,EAAO,MAAM;AAAA,QAC9B,EAAA,GACIiF,IAAS,KAAK,KAAK;AAazB,iCACGlB,GAAoB,EAAA,OAAM,QAAO,QAAQ,KACxC,4BAACmB,IACC,EAAA,UAAA;AAAA,UAAA,gBAAAxC;AAAA,YAACyC;AAAA,YAAA;AAAA,cAAI,MAAMH;AAAA,cAAS,IAAG;AAAA,cAAM,IAAG;AAAA,cAAM,aAAa;AAAA,cACjD,SAAQ;AAAA,cAAQ,OAhBJ,CAAC,EAAE,IAAAI,GAAI,IAAAC,GAAI,UAAAC,GAAU,aAAAC,GAAa,aAAAC,GAAa,SAAAC,GAAS,MAAAnB,QAAW;AACrF,sBAAMoB,IAASF,IAAc,IACvBxD,IAAIoD,IAAKM,IAAS,KAAK,IAAI,CAACJ,IAAWL,CAAM,GAC7CU,IAAIN,IAAKK,IAAS,KAAK,IAAI,CAACJ,IAAWL,CAAM;AACnD,uBAAIQ,IAAU,OAAa,OAEzB,gBAAAhD;AAAA,kBAAC;AAAA,kBAAA;AAAA,oBAAK,GAAAT;AAAA,oBAAM,GAAA2D;AAAA,oBAAM,MAAK;AAAA,oBAA2B,UAAU;AAAA,oBAC1D,YAAY3D,IAAIoD,IAAK,UAAU;AAAA,oBAAO,kBAAiB;AAAA,oBACtD,UAAA;AAAA,sBAAAd;AAAA,sBAAK;AAAA,uBAAImB,IAAU,KAAK,QAAQ,CAAC;AAAA,sBAAE;AAAA,oBAAA;AAAA,kBAAA;AAAA,gBAAA;AAAA,cACtC;AAAA,cAOwC,WAAW,EAAE,QAAQ,0BAA0B;AAAA,cAClF,UAAAT,EAAQ,IAAI,CAACY,GAAOrB,MAClB,gBAAA7B,EAAAiC,GAAA,EAAa,MAAMiB,EAAM,KAAf,GAAArB,CAAqB,CACjC;AAAA,YAAA;AAAA,UACH;AAAA,UACA,gBAAA7B,EAAC0B,GAAS,EAAA,GAAGhE,GAAe;AAAA,QAAA,EAC9B,CAAA,EACF,CAAA;AAAA,MAEJ;AAAA,MAEA,KAAK,UAAU;AACP,cAAA0B,IAAIH,EAAO,CAAC,GACZkE,IAAU/D,EAAE,KAAK,CAAC,GAClBgE,IAAWhE,EAAE,KAAK,SAAS,IAAIA,EAAE,KAAK,CAAC,IAAI,MAC3CiE,IAAQF,EAAQ,GAChBG,IAAOH,EAAQ,KAAK,IACpBI,IAAWH,MAAa,MACxBI,IAASD,IAAWF,IAAQD,EAAS,IAAI,GACzCK,IAAYF,KAAYH,EAAS,MAAM,IAAMI,IAAS,KAAK,IAAIJ,EAAS,CAAC,IAAK,MAAO,GACrFM,IAAaF,IAAS,GACtBG,IAAaH,IAAS,GACtBI,IAAaF,IAAa,YAAYC,IAAa,YAAY,2BAC/DE,IAAaH,IAAa,MAAMC,IAAa,MAAM,KAGnDG,IAAM,CAACC,MACP,OAAO,UAAUA,CAAC,KAAK,KAAK,IAAIA,CAAC,KAAK,MAAaA,EAAE,mBACrD,OAAOA,KAAM,WAAiBA,IAAI,MAAM,IAAIA,EAAE,SAAa,IAAAA,EAAE,QAAQA,IAAI,KAAK,IAAI,CAAC,IAChF,OAAOA,CAAC;AAGjB,eACG,gBAAAhE,EAAA,OAAA,EAAI,OAAO,EAAE,SAAS,QAAQ,YAAY,YAAY,KAAK,IAAI,SAAS,QAAA,GACvE,UAAA;AAAA,UAAA,gBAAAC,EAAC,SAAI,OAAO;AAAA,YACV,UAAU;AAAA,YAAQ,YAAY;AAAA,YAAK,YAAY;AAAA,YAC/C,OAAO;AAAA,YACP,oBAAoB;AAAA,UACtB,GACG,UAAI8D,EAAAT,CAAK,GACZ;AAAA,UACCC,KACC,gBAAAtD,EAAC,OAAI,EAAA,OAAO,EAAE,UAAU,QAAQ,OAAO,2BAA2B,YAAY,IAAI,GAC/E,UACHsD,EAAA,CAAA;AAAA,UAEDC,KACE,gBAAAxD,EAAA,OAAA,EAAI,OAAO;AAAA,YACV,SAAS;AAAA,YAAQ,YAAY;AAAA,YAAU,KAAK;AAAA,YAC5C,UAAU;AAAA,YAAQ,YAAY;AAAA,YAAK,OAAO6D;AAAA,YAC1C,YAAYF,IAAa,2BAA2BC,IAAa,2BAA2B;AAAA,YAC5F,SAAS;AAAA,YAAW,cAAc;AAAA,UAElC,GAAA,UAAA;AAAA,YAAA,gBAAA3D,EAAC,UAAM,UAAW6D,EAAA,CAAA;AAAA,8BACjB,QAAM,EAAA,UAAA;AAAA,cAAIC,EAAA,KAAK,IAAIN,CAAM,CAAC;AAAA,cAAE;AAAA,cAAG,KAAK,IAAIC,CAAS,EAAE,QAAQ,CAAC;AAAA,cAAE;AAAA,YAAA,GAAE;AAAA,UAAA,GACnE;AAAA,UAEDF,uBACE,OAAI,EAAA,OAAO,EAAE,UAAU,QAAQ,OAAO,0BAA6B,GAAA,UAAA;AAAA,YAAA;AAAA,YAC9DH,EAAS,KAAK;AAAA,UAAA,GACpB;AAAA,QAEJ,EAAA,CAAA;AAAA,MAEJ;AAAA,MAEA;AACS,eAAA,gBAAArD,EAAC,OAAI,EAAA,OAAO,EAAE,OAAO,qBAAqB,UAAU,IAAI,SAAS,EAAA,GAAK,UAAA;AAAA,UAAA;AAAA,UAAyBG;AAAA,QAAU,EAAA,CAAA;AAAA,IACpH;AAAA,EAAA,GAGI8D,IAAiBC,EAAY,MAAM;AACvC,IAAI5D,EAAS,WAAqBpC,GAAAoC,EAAS,SAASlC,CAAK;AAAA,EAAA,GACxD,CAACA,CAAK,CAAC,GAEJ+F,KAAaD,EAAY,MAAM;AACnC,IAAAjF,GAAUC,GAAQC,CAAU,GAC5BqB,EAAU,EAAI,GACd,WAAW,MAAMA,EAAU,EAAK,GAAG,GAAI;AAAA,EAAA,GACtC,CAACtB,GAAQC,CAAU,CAAC;AAKrB,SAAA,gBAAAa,EAAC,OAAI,EAAA,OAAOiB,GACT,UAAA;AAAA,IAAA7C,KAAU,gBAAA6B,EAAA,OAAA,EAAI,OAAOiB,GAAa,UAAM9C,GAAA;AAAA,IAJzB+B,MAAc,YAKb,gBAAAF,EAAAL,IAAA,EAAU,YAAYqE,GAAgB,QAAQE,IAAY,QAAApE,GAAgB;AAAA,IAC1F,gBAAAE,EAAA,OAAA,EAAI,KAAKK,GACP,eACH;AAAA,EACF,EAAA,CAAA;AAEJ;"}
|