chordia-ui 3.7.0 → 3.7.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.
Files changed (36) hide show
  1. package/dist/ChatMessage.cjs.js +15 -0
  2. package/dist/ChatMessage.cjs.js.map +1 -0
  3. package/dist/ChatMessage.es.js +915 -0
  4. package/dist/ChatMessage.es.js.map +1 -0
  5. package/dist/SideDrawer.cjs.js +2 -0
  6. package/dist/SideDrawer.cjs.js.map +1 -0
  7. package/dist/SideDrawer.es.js +358 -0
  8. package/dist/SideDrawer.es.js.map +1 -0
  9. package/dist/Toast.cjs.js +2 -2
  10. package/dist/Toast.cjs.js.map +1 -1
  11. package/dist/Toast.es.js +301 -671
  12. package/dist/Toast.es.js.map +1 -1
  13. package/dist/components/UpdatedInteractionDetails.cjs.js +4 -4
  14. package/dist/components/UpdatedInteractionDetails.cjs.js.map +1 -1
  15. package/dist/components/UpdatedInteractionDetails.es.js +652 -603
  16. package/dist/components/UpdatedInteractionDetails.es.js.map +1 -1
  17. package/dist/components/chat.cjs.js +5 -7
  18. package/dist/components/chat.cjs.js.map +1 -1
  19. package/dist/components/chat.es.js +393 -849
  20. package/dist/components/chat.es.js.map +1 -1
  21. package/dist/components/common.cjs.js +1 -1
  22. package/dist/components/common.es.js +28 -27
  23. package/dist/components/common.es.js.map +1 -1
  24. package/dist/index.cjs.js +1 -1
  25. package/dist/index.es.js +73 -72
  26. package/dist/index.es.js.map +1 -1
  27. package/package.json +1 -1
  28. package/src/components/UpdatedInteractionDetails/UpdatedInteractionContext.jsx +6 -2
  29. package/src/components/UpdatedInteractionDetails/UpdatedInteractionDetails.jsx +190 -139
  30. package/src/components/chat/ChartRenderer.jsx +300 -49
  31. package/src/components/common/AskCompass.jsx +91 -87
  32. package/src/components/common/SideDrawer.jsx +7 -3
  33. package/dist/ChartRenderer.cjs.js +0 -3
  34. package/dist/ChartRenderer.cjs.js.map +0 -1
  35. package/dist/ChartRenderer.es.js +0 -304
  36. package/dist/ChartRenderer.es.js.map +0 -1
@@ -4,6 +4,7 @@ import React, { useState, useRef, useEffect } from "react";
4
4
  import { motion, AnimatePresence } from "motion/react";
5
5
  import { History, MessageCircleQuestion } from "lucide-react";
6
6
  import ChartRenderer from "../chat/ChartRenderer.jsx";
7
+ import ChatMessage from "../chat/ChatMessage";
7
8
 
8
9
  /*
9
10
  * AskCompass — floating action button + AI chat panel
@@ -63,7 +64,7 @@ function CompassRingsIcon({ size = 48 }) {
63
64
  }
64
65
 
65
66
  /* ─── AI Panel ─── */
66
- function AskCompassPanel({ onSend, onHistoryClick, messages = [], loading = false, statusLabel }) {
67
+ function AskCompassPanel({ isOpen = true, onSend, onHistoryClick, messages = [], loading = false, statusLabel, onCodeBlockClick }) {
67
68
  const [query, setQuery] = useState("");
68
69
  const chatRef = useRef(null);
69
70
  const textareaRef = useRef(null);
@@ -103,16 +104,35 @@ function AskCompassPanel({ onSend, onHistoryClick, messages = [], loading = fals
103
104
 
104
105
  const hasMessages = messages.length > 0;
105
106
 
107
+ // Charts (especially pie with external labels) need more horizontal room than the 360px panel.
108
+ // Wrap each chart in a horizontally-scrollable container so labels render fully.
109
+ // Pie/donut labels extend on both sides of the chart, so they need extra width vs cartesian charts.
110
+ // flexShrink: 0 + explicit width prevents the flex chat-area from squishing the chart to nothing.
111
+ const chartScrollWrapperStyle = {
112
+ alignSelf: "stretch",
113
+ marginTop: 8,
114
+ overflowX: "auto",
115
+ overflowY: "hidden",
116
+ flexShrink: 0,
117
+ };
118
+ const getChartInnerStyle = (chartType) => ({
119
+ width: chartType === "pie" || chartType === "donut" ? 500 : 460,
120
+ flexShrink: 0,
121
+ });
122
+
106
123
  return (
107
124
  <motion.div
108
- initial={{ opacity: 0, y: 20, scale: 0.95 }}
109
- animate={{ opacity: 1, y: 0, scale: 1 }}
110
- exit={{ opacity: 0, y: 20, scale: 0.95 }}
125
+ initial={false}
126
+ animate={
127
+ isOpen
128
+ ? { opacity: 1, y: 0, scale: 1, pointerEvents: "auto" }
129
+ : { opacity: 0, y: 20, scale: 0.95, pointerEvents: "none" }
130
+ }
111
131
  transition={{ type: "spring", stiffness: 400, damping: 30 }}
112
132
  style={{
113
133
  display: "flex",
114
- width: 360,
115
- height: 709,
134
+ width: "min(360px, calc(100vw - 24px))",
135
+ height: "min(709px, calc(100dvh - 100px))",
116
136
  padding: 24,
117
137
  flexDirection: "column",
118
138
  justifyContent: "space-between",
@@ -213,61 +233,53 @@ function AskCompassPanel({ onSend, onHistoryClick, messages = [], loading = fals
213
233
  </span>
214
234
  </>
215
235
  ) : (
216
- messages.map((msg, i) => (
217
- <React.Fragment key={i}>
218
- <div
219
- style={{
220
- display: "flex",
221
- justifyContent: msg.role === "user" ? "flex-end" : "flex-start",
222
- }}
223
- >
224
- <div
225
- style={{
226
- maxWidth: "85%",
227
- padding: "10px 14px",
228
- borderRadius: msg.role === "user" ? "14px 14px 4px 14px" : "14px 14px 14px 4px",
229
- background: msg.role === "user" ? "var(--Rail-Surface-2, #E3E1D7)" : "#F3F7F7",
230
- fontSize: 14,
231
- fontWeight: 400,
232
- color: "var(--Grey-Strong, #2E3236)",
233
- lineHeight: "140%",
234
- whiteSpace: "pre-wrap",
235
- wordBreak: "break-word",
236
- }}
237
- >
238
- {msg.content}
239
- </div>
240
- </div>
241
- {msg.charts?.map((chart, ci) => (
242
- <div
243
- key={`chart-${ci}`}
244
- style={{
245
- width: "100%",
246
- marginTop: 8,
247
- overflowX: "auto",
248
- overflowY: "hidden",
249
- }}
250
- >
251
- <div
252
- style={{
253
- width: 520,
254
- transform: "scale(0.85)",
255
- transformOrigin: "top left",
256
- marginBottom: -40,
257
- }}
258
- >
236
+ messages.map((message, i) => {
237
+ const key = message.id ?? i;
238
+ // Chart-only message: render ChartRenderer instead of ChatMessage
239
+ if (message.chartType && message.series) {
240
+ return (
241
+ <div key={key} style={chartScrollWrapperStyle}>
242
+ <div style={getChartInnerStyle(message.chartType)}>
259
243
  <ChartRenderer
260
- chartType={chart.chartType}
261
- title={chart.title}
262
- xLabel={chart.xLabel}
263
- yLabel={chart.yLabel}
264
- series={chart.series}
244
+ chartType={message.chartType}
245
+ title={message.title}
246
+ xLabel={message.xLabel}
247
+ yLabel={message.yLabel}
248
+ series={message.series}
249
+ compact
265
250
  />
266
251
  </div>
267
252
  </div>
268
- ))}
269
- </React.Fragment>
270
- ))
253
+ );
254
+ }
255
+ return (
256
+ <React.Fragment key={key}>
257
+ <ChatMessage
258
+ role={message.role}
259
+ content={message.content}
260
+ html={message.html}
261
+ timestamp={message.timestamp}
262
+ toolBadges={message.toolBadges}
263
+ isStreaming={message.isStreaming}
264
+ onCodeBlockClick={onCodeBlockClick}
265
+ />
266
+ {message.charts?.map((chart, ci) => (
267
+ <div key={`chart-${ci}`} style={chartScrollWrapperStyle}>
268
+ <div style={getChartInnerStyle(chart.chartType)}>
269
+ <ChartRenderer
270
+ chartType={chart.chartType}
271
+ title={chart.title}
272
+ xLabel={chart.xLabel}
273
+ yLabel={chart.yLabel}
274
+ series={chart.series}
275
+ compact
276
+ />
277
+ </div>
278
+ </div>
279
+ ))}
280
+ </React.Fragment>
281
+ );
282
+ })
271
283
  )}
272
284
  {loading && (
273
285
  <div style={{ display: "flex", justifyContent: "flex-start" }}>
@@ -316,7 +328,7 @@ function AskCompassPanel({ onSend, onHistoryClick, messages = [], loading = fals
316
328
  fontSize: 15,
317
329
  fontWeight: 400,
318
330
  color: "var(--Base-Strong, #2E3236)",
319
- lineHeight: "1.4",
331
+ lineHeight: "1",
320
332
  resize: "none",
321
333
  fontFamily: "inherit",
322
334
  padding: 0,
@@ -361,54 +373,46 @@ export default function AskCompass({
361
373
  messages = [],
362
374
  loading = false,
363
375
  statusLabel,
376
+ onCodeBlockClick,
364
377
  className = "",
365
378
  }) {
366
379
  const [isHovered, setIsHovered] = useState(false);
367
380
  const [isOpen, setIsOpen] = useState(false);
368
- const wrapperRef = useRef(null);
369
-
370
- useEffect(() => {
371
- if (!isOpen) return;
372
- const handleClickOutside = (e) => {
373
- if (wrapperRef.current && !wrapperRef.current.contains(e.target)) {
374
- setIsOpen(false);
375
- }
376
- };
377
- document.addEventListener("mousedown", handleClickOutside);
378
- return () => document.removeEventListener("mousedown", handleClickOutside);
379
- }, [isOpen]);
380
381
 
381
382
  return (
382
383
  <div
383
- ref={wrapperRef}
384
384
  className={className}
385
385
  style={{
386
386
  position: "fixed",
387
- bottom: 24,
388
- right: 24,
387
+ bottom: "max(12px, env(safe-area-inset-bottom))",
388
+ right: "max(12px, env(safe-area-inset-right))",
389
389
  zIndex: 1000,
390
390
  display: "flex",
391
391
  flexDirection: "column",
392
392
  alignItems: "flex-end",
393
393
  gap: 12,
394
+ // Wrapper itself is transparent to clicks; only the FAB (and the panel when open)
395
+ // capture pointer events. This keeps page content underneath clickable when the
396
+ // panel is closed but still mounted.
397
+ pointerEvents: "none",
394
398
  }}
395
399
  >
396
- {/* Panel */}
397
- <AnimatePresence>
398
- {isOpen && (
399
- <AskCompassPanel
400
- onSend={onSend}
401
- onHistoryClick={onHistoryClick}
402
- messages={messages}
403
- loading={loading}
404
- statusLabel={statusLabel}
405
- />
406
- )}
407
- </AnimatePresence>
400
+ {/* Panel — always mounted so messages and UI state survive close/reopen.
401
+ Visibility is animated rather than via mount/unmount so chat history persists
402
+ for the lifetime of the page (cleared only on full page refresh). */}
403
+ <AskCompassPanel
404
+ isOpen={isOpen}
405
+ onSend={onSend}
406
+ onHistoryClick={onHistoryClick}
407
+ messages={messages}
408
+ loading={loading}
409
+ statusLabel={statusLabel}
410
+ onCodeBlockClick={onCodeBlockClick}
411
+ />
408
412
 
409
- {/* FAB */}
413
+ {/* FAB — re-enable pointer events since the wrapper is set to none */}
410
414
  <div
411
- style={{ width: 48, height: 48 }}
415
+ style={{ width: 48, height: 48, pointerEvents: "auto" }}
412
416
  onMouseEnter={() => setIsHovered(true)}
413
417
  onMouseLeave={() => setIsHovered(false)}
414
418
  >
@@ -18,6 +18,7 @@ import { X } from "lucide-react";
18
18
  * - toggleLabel string Optional toggle label (right side of subtitle row)
19
19
  * - toggleChecked boolean Toggle state
20
20
  * - onToggle function Toggle callback
21
+ * - topOffset number|string Optional top offset (e.g. below navbar)
21
22
  */
22
23
  export default function SideDrawer({
23
24
  open,
@@ -31,8 +32,11 @@ export default function SideDrawer({
31
32
  toggleLabel,
32
33
  toggleChecked,
33
34
  onToggle,
35
+ topOffset,
34
36
  }) {
35
37
  const drawerRef = useRef(null);
38
+ const hasTopOffset = topOffset !== undefined && topOffset !== null;
39
+ const normalizedTopOffset = typeof topOffset === "number" ? `${topOffset}px` : topOffset;
36
40
 
37
41
  // Close on Escape key
38
42
  useEffect(() => {
@@ -64,14 +68,14 @@ export default function SideDrawer({
64
68
  ref={drawerRef}
65
69
  style={{
66
70
  position: "fixed",
67
- top: "50%",
71
+ top: hasTopOffset ? normalizedTopOffset : "50%",
68
72
  right: 0,
69
- transform: "translateY(-50%)",
73
+ transform: hasTopOffset ? "none" : "translateY(-50%)",
70
74
  zIndex: 1201,
71
75
  display: "flex",
72
76
  width,
73
77
  height,
74
- maxHeight: "100vh",
78
+ maxHeight: hasTopOffset ? `calc(100vh - ${normalizedTopOffset})` : "100vh",
75
79
  padding: "20px",
76
80
  flexDirection: "column",
77
81
  alignItems: "flex-start",
@@ -1,3 +0,0 @@
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(o=>String(o).toLowerCase().includes(d)).length<c.length*.5},V=async(l,c)=>{const d=l.querySelector("svg");if(!d)return;const i=d.cloneNode(!0),o=d.clientWidth||600,x=d.clientHeight||300;i.setAttribute("width",o),i.setAttribute("height",x),i.setAttribute("xmlns","http://www.w3.org/2000/svg");const C=document.createElement("style");C.textContent='text { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; }',i.insertBefore(C,i.firstChild);const S=new XMLSerializer().serializeToString(i),u=new Blob([S],{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=o*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,o,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 C=l.map(S=>{const u=S.data.find(h=>h.x===x);return u?u.y:""});return[x,...C].join(",")}),o=[d,...i].join(`
2
- `);navigator.clipboard.writeText(o)},$=({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:o})=>{const x=E.useRef(null),[C,S]=E.useState(!1);if(!o||o.length===0)return null;const u=[...new Set(o.flatMap(n=>n.data.map(r=>r.x)))],h=u.map(n=>{const r={x:n};return o.forEach(p=>{const s=p.data.find(f=>f.x===n);r[p.name]=s?s.y:null}),r}),m=o.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],isAnimationActive:!1,children:g&&h.map((p,s)=>t.jsx(e.Cell,{fill:a[s%a.length]},s))},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],isAnimationActive:!1,children:g&&h.map((p,s)=>t.jsx(e.Cell,{fill:a[s%a.length]},s))},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]},isAnimationActive:!1},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,isAnimationActive:!1},n))]})});case"pie":{const n=o[0].data.map((s,f)=>({name:s.x,value:s.y,fill:a[f%a.length]})),r=Math.PI/180,p=({cx:s,cy:f,midAngle:A,innerRadius:w,outerRadius:K,percent:k,name:L})=>{const z=K+20,I=s+z*Math.cos(-A*r),T=f+z*Math.sin(-A*r);return k<.04?null:t.jsxs("text",{x:I,y:T,fill:"var(--text-ink, #1e2125)",fontSize:11,textAnchor:I>s?"start":"end",dominantBaseline:"central",children:[L," (",(k*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)"},isAnimationActive:!1,children:n.map((s,f)=>t.jsx(e.Cell,{fill:s.fill},f))}),t.jsx(e.Tooltip,{...R})]})})}case"metric":{const n=o[0],r=n.data[0],p=n.data.length>1?n.data[1]:null,s=r.y,f=r.x||"",A=p!==null,w=A?s-p.y:0,K=A&&p.y!==0?w/Math.abs(p.y)*100:0,k=w>0,L=w<0,z=k?"#7BA89D":L?"#D17B6B":"var(--text-muted, #666)",I=k?"↑":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(s)}),f&&t.jsx("div",{style:{fontSize:"14px",color:"var(--text-muted, #666)",fontWeight:500},children:f}),A&&t.jsxs("div",{style:{display:"flex",alignItems:"center",gap:4,fontSize:"13px",fontWeight:600,color:z,background:k?"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(w))," (",Math.abs(K).toFixed(1),"%)"]})]}),A&&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(o,u),S(!0),setTimeout(()=>S(!1),2e3)},[o,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:C}),t.jsx("div",{ref:x,children:U()})]})};exports.ChartRenderer=J;
3
- //# sourceMappingURL=ChartRenderer.cjs.js.map
@@ -1 +0,0 @@
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]} isAnimationActive={false}>\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]} isAnimationActive={false}>\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 isAnimationActive={false}\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 isAnimationActive={false}\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 isAnimationActive={false}>\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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"}