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.
- package/dist/ChatMessage.cjs.js +15 -0
- package/dist/ChatMessage.cjs.js.map +1 -0
- package/dist/ChatMessage.es.js +915 -0
- package/dist/ChatMessage.es.js.map +1 -0
- package/dist/SideDrawer.cjs.js +2 -0
- package/dist/SideDrawer.cjs.js.map +1 -0
- package/dist/SideDrawer.es.js +358 -0
- package/dist/SideDrawer.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 +301 -671
- 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 +652 -603
- package/dist/components/UpdatedInteractionDetails.es.js.map +1 -1
- package/dist/components/chat.cjs.js +5 -7
- package/dist/components/chat.cjs.js.map +1 -1
- package/dist/components/chat.es.js +393 -849
- package/dist/components/chat.es.js.map +1 -1
- package/dist/components/common.cjs.js +1 -1
- package/dist/components/common.es.js +28 -27
- package/dist/components/common.es.js.map +1 -1
- package/dist/index.cjs.js +1 -1
- package/dist/index.es.js +73 -72
- package/dist/index.es.js.map +1 -1
- package/package.json +1 -1
- package/src/components/UpdatedInteractionDetails/UpdatedInteractionContext.jsx +6 -2
- package/src/components/UpdatedInteractionDetails/UpdatedInteractionDetails.jsx +190 -139
- package/src/components/chat/ChartRenderer.jsx +300 -49
- package/src/components/common/AskCompass.jsx +91 -87
- package/src/components/common/SideDrawer.jsx +7 -3
- package/dist/ChartRenderer.cjs.js +0 -3
- package/dist/ChartRenderer.cjs.js.map +0 -1
- package/dist/ChartRenderer.es.js +0 -304
- 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={
|
|
109
|
-
animate={
|
|
110
|
-
|
|
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:
|
|
115
|
-
height:
|
|
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((
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
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={
|
|
261
|
-
title={
|
|
262
|
-
xLabel={
|
|
263
|
-
yLabel={
|
|
264
|
-
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
|
-
|
|
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
|
|
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:
|
|
388
|
-
right:
|
|
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
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
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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"}
|