@retrivora-ai/rag-engine 1.5.5 → 1.5.7

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/index.mjs CHANGED
@@ -123,7 +123,7 @@ function ProductCarousel({ products, primaryColor = "#6366f1", onAddToCart }) {
123
123
  };
124
124
  if (!products || products.length === 0) return null;
125
125
  if (products.length === 1) {
126
- return /* @__PURE__ */ React3.createElement("div", { className: "my-4 w-[85%] sm:w-[48%] md:w-[31%] min-w-[200px] max-w-[300px] animate-fade-in-up" }, /* @__PURE__ */ React3.createElement(ProductCard, { product: products[0], primaryColor, onAddToCart }));
126
+ return /* @__PURE__ */ React3.createElement("div", { className: "my-4 w-[min(88%,18rem)] min-w-0 max-w-full animate-fade-in-up" }, /* @__PURE__ */ React3.createElement(ProductCard, { product: products[0], primaryColor, onAddToCart }));
127
127
  }
128
128
  return /* @__PURE__ */ React3.createElement("div", { className: "relative w-full my-4 group/carousel animate-fade-in-up" }, canScroll && /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement("div", { className: "absolute -left-4 top-1/2 -translate-y-1/2 z-20 opacity-100 md:opacity-0 md:group-hover/carousel:opacity-100 transition-opacity" }, /* @__PURE__ */ React3.createElement(
129
129
  "button",
@@ -158,7 +158,7 @@ function ProductCarousel({ products, primaryColor = "#6366f1", onAddToCart }) {
158
158
  "div",
159
159
  {
160
160
  key: product.id,
161
- className: "snap-start flex-shrink-0 w-[85%] sm:w-[48%] md:w-[31%] min-w-[200px] max-w-[300px]"
161
+ className: "snap-start flex-shrink-0 w-[min(88%,18rem)] min-w-[11rem] max-w-full"
162
162
  },
163
163
  /* @__PURE__ */ React3.createElement(ProductCard, { product, primaryColor, onAddToCart })
164
164
  ))
@@ -183,9 +183,20 @@ import {
183
183
  ResponsiveContainer
184
184
  } from "recharts";
185
185
  var DEFAULT_COLORS = ["#6366f1", "#10b981", "#f59e0b", "#ef4444", "#8b5cf6", "#ec4899"];
186
- function DynamicChart({ config, primaryColor = "#6366f1", accentColor = "#8b5cf6" }) {
186
+ function DynamicChart({
187
+ config,
188
+ primaryColor = "#6366f1",
189
+ accentColor = "#8b5cf6",
190
+ viewportSize = "large"
191
+ }) {
187
192
  const { type, data } = config;
188
193
  const colors = config.colors || [primaryColor, accentColor, ...DEFAULT_COLORS];
194
+ const isCompact = viewportSize === "compact";
195
+ const isMedium = viewportSize === "medium";
196
+ const chartHeightClass = isCompact ? "h-56 min-h-[220px]" : isMedium ? "h-64 min-h-[250px]" : "h-72 min-h-[280px]";
197
+ const pieOuterRadius = isCompact ? 56 : isMedium ? 68 : 80;
198
+ const pieLabel = ({ name, percent }) => isCompact ? `${name}` : `${name} ${((percent != null ? percent : 0) * 100).toFixed(0)}%`;
199
+ const axisTick = { fontSize: isCompact ? 10 : 12, fill: "#64748b" };
189
200
  const sanitizedData = React4.useMemo(() => {
190
201
  if (!data) return [];
191
202
  return data.map((item) => {
@@ -285,7 +296,7 @@ function DynamicChart({ config, primaryColor = "#6366f1", accentColor = "#8b5cf6
285
296
  return row;
286
297
  };
287
298
  if (type === "pie") {
288
- return /* @__PURE__ */ React4.createElement("div", { className: "w-full h-72 min-h-[280px] mt-4 mb-2 select-none overflow-hidden" }, /* @__PURE__ */ React4.createElement(ResponsiveContainer, { width: "99%", height: "100%" }, /* @__PURE__ */ React4.createElement(PieChart, null, /* @__PURE__ */ React4.createElement(
299
+ return /* @__PURE__ */ React4.createElement("div", { className: `w-full ${chartHeightClass} mt-4 mb-2 select-none overflow-hidden` }, /* @__PURE__ */ React4.createElement(ResponsiveContainer, { width: "99%", height: "100%" }, /* @__PURE__ */ React4.createElement(PieChart, null, /* @__PURE__ */ React4.createElement(
289
300
  Pie,
290
301
  {
291
302
  data: sanitizedData,
@@ -293,31 +304,31 @@ function DynamicChart({ config, primaryColor = "#6366f1", accentColor = "#8b5cf6
293
304
  nameKey: finalXKey,
294
305
  cx: "50%",
295
306
  cy: "50%",
296
- outerRadius: 80,
297
- label: ({ name, percent }) => `${name} ${((percent != null ? percent : 0) * 100).toFixed(0)}%`
307
+ outerRadius: pieOuterRadius,
308
+ label: pieLabel
298
309
  },
299
310
  sanitizedData.map((entry, index) => /* @__PURE__ */ React4.createElement(Cell, { key: `cell-${index}`, fill: stockAwareColor(entry, index) }))
300
- ), /* @__PURE__ */ React4.createElement(Tooltip, { content: (props) => renderTooltip(getTooltipRow(props.payload), typeof props.label === "string" ? props.label : void 0) }), /* @__PURE__ */ React4.createElement(Legend, null))));
311
+ ), /* @__PURE__ */ React4.createElement(Tooltip, { content: (props) => renderTooltip(getTooltipRow(props.payload), typeof props.label === "string" ? props.label : void 0) }), /* @__PURE__ */ React4.createElement(Legend, { wrapperStyle: { fontSize: isCompact ? 10 : 12 } }))));
301
312
  }
302
- return /* @__PURE__ */ React4.createElement("div", { className: "w-full h-72 min-h-[280px] mt-4 mb-2 select-none overflow-hidden" }, /* @__PURE__ */ React4.createElement(ResponsiveContainer, { width: "99%", height: "100%" }, type === "bar" ? /* @__PURE__ */ React4.createElement(BarChart, { data: sanitizedData, margin: { top: 10, right: 10, left: -20, bottom: 0 } }, /* @__PURE__ */ React4.createElement(CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }), /* @__PURE__ */ React4.createElement(XAxis, { dataKey: finalXKey, tick: { fontSize: 12, fill: "#64748b" }, tickLine: false, axisLine: { stroke: "#cbd5e1" } }), /* @__PURE__ */ React4.createElement(YAxis, { tick: { fontSize: 12, fill: "#64748b" }, tickLine: false, axisLine: false }), /* @__PURE__ */ React4.createElement(Tooltip, { content: (props) => renderTooltip(getTooltipRow(props.payload), typeof props.label === "string" ? props.label : void 0), cursor: { fill: "#f1f5f9" } }), /* @__PURE__ */ React4.createElement(Legend, { wrapperStyle: { fontSize: 12 } }), finalDataKeys.map((key, index) => /* @__PURE__ */ React4.createElement(
313
+ return /* @__PURE__ */ React4.createElement("div", { className: `w-full ${chartHeightClass} mt-4 mb-2 select-none overflow-hidden` }, /* @__PURE__ */ React4.createElement(ResponsiveContainer, { width: "99%", height: "100%" }, type === "bar" ? /* @__PURE__ */ React4.createElement(BarChart, { data: sanitizedData, margin: { top: 10, right: 10, left: -20, bottom: 0 } }, /* @__PURE__ */ React4.createElement(CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }), /* @__PURE__ */ React4.createElement(XAxis, { dataKey: finalXKey, tick: axisTick, tickLine: false, axisLine: { stroke: "#cbd5e1" } }), /* @__PURE__ */ React4.createElement(YAxis, { tick: axisTick, tickLine: false, axisLine: false }), /* @__PURE__ */ React4.createElement(Tooltip, { content: (props) => renderTooltip(getTooltipRow(props.payload), typeof props.label === "string" ? props.label : void 0), cursor: { fill: "#f1f5f9" } }), /* @__PURE__ */ React4.createElement(Legend, { wrapperStyle: { fontSize: isCompact ? 10 : 12 } }), finalDataKeys.map((key, index) => /* @__PURE__ */ React4.createElement(
303
314
  Bar,
304
315
  {
305
316
  key,
306
317
  dataKey: key,
307
318
  fill: colors[index % colors.length],
308
319
  radius: [4, 4, 0, 0],
309
- barSize: Math.max(20, 60 / data.length)
320
+ barSize: isCompact ? Math.max(14, 42 / data.length) : Math.max(20, 60 / data.length)
310
321
  }
311
- ))) : /* @__PURE__ */ React4.createElement(LineChart, { data: sanitizedData, margin: { top: 10, right: 10, left: -20, bottom: 0 } }, /* @__PURE__ */ React4.createElement(CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }), /* @__PURE__ */ React4.createElement(XAxis, { dataKey: finalXKey, tick: { fontSize: 12, fill: "#64748b" }, tickLine: false, axisLine: { stroke: "#cbd5e1" } }), /* @__PURE__ */ React4.createElement(YAxis, { tick: { fontSize: 12, fill: "#64748b" }, tickLine: false, axisLine: false }), /* @__PURE__ */ React4.createElement(Tooltip, { content: (props) => renderTooltip(getTooltipRow(props.payload), typeof props.label === "string" ? props.label : void 0) }), /* @__PURE__ */ React4.createElement(Legend, { wrapperStyle: { fontSize: 12 } }), finalDataKeys.map((key, index) => /* @__PURE__ */ React4.createElement(
322
+ ))) : /* @__PURE__ */ React4.createElement(LineChart, { data: sanitizedData, margin: { top: 10, right: 10, left: -20, bottom: 0 } }, /* @__PURE__ */ React4.createElement(CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }), /* @__PURE__ */ React4.createElement(XAxis, { dataKey: finalXKey, tick: axisTick, tickLine: false, axisLine: { stroke: "#cbd5e1" } }), /* @__PURE__ */ React4.createElement(YAxis, { tick: axisTick, tickLine: false, axisLine: false }), /* @__PURE__ */ React4.createElement(Tooltip, { content: (props) => renderTooltip(getTooltipRow(props.payload), typeof props.label === "string" ? props.label : void 0) }), /* @__PURE__ */ React4.createElement(Legend, { wrapperStyle: { fontSize: isCompact ? 10 : 12 } }), finalDataKeys.map((key, index) => /* @__PURE__ */ React4.createElement(
312
323
  Line,
313
324
  {
314
325
  key,
315
326
  type: "monotone",
316
327
  dataKey: key,
317
328
  stroke: colors[index % colors.length],
318
- strokeWidth: 3,
319
- dot: { r: 4, strokeWidth: 2 },
320
- activeDot: { r: 6 }
329
+ strokeWidth: isCompact ? 2 : 3,
330
+ dot: { r: isCompact ? 3 : 4, strokeWidth: 2 },
331
+ activeDot: { r: isCompact ? 5 : 6 }
321
332
  }
322
333
  )))));
323
334
  }
@@ -376,6 +387,14 @@ function sanitizeJson(raw) {
376
387
  }
377
388
  return s;
378
389
  }
390
+ function extractLikelyJsonBlock(raw) {
391
+ const trimmed = raw.trim();
392
+ const objectStart = trimmed.indexOf("{");
393
+ const arrayStart = trimmed.indexOf("[");
394
+ const starts = [objectStart, arrayStart].filter((index) => index >= 0);
395
+ if (starts.length === 0) return trimmed;
396
+ return trimmed.slice(Math.min(...starts));
397
+ }
379
398
  function resolveImage(data) {
380
399
  for (const key of ["image", "img", "thumbnail"]) {
381
400
  const v = data[key];
@@ -392,7 +411,9 @@ function normaliseChild(children) {
392
411
  }
393
412
  return children;
394
413
  }
395
- function DataTable({ config }) {
414
+ function DataTable({ config, viewportSize = "large" }) {
415
+ const isCompact = viewportSize === "compact";
416
+ const isMedium = viewportSize === "medium";
396
417
  const keys = React5.useMemo(() => {
397
418
  if (Array.isArray(config.columns) && config.columns.length) {
398
419
  return config.columns;
@@ -414,11 +435,11 @@ function DataTable({ config }) {
414
435
  if (typeof val === "boolean") return val ? "\u2713" : "\u2717";
415
436
  return String(val);
416
437
  };
417
- return /* @__PURE__ */ React5.createElement("div", { className: "my-4 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm overflow-hidden" }, config.title && /* @__PURE__ */ React5.createElement("div", { className: "px-4 py-2.5 bg-slate-50 dark:bg-white/5 border-b border-slate-200 dark:border-white/10" }, /* @__PURE__ */ React5.createElement("p", { className: "text-xs font-semibold text-slate-600 dark:text-white/70 uppercase tracking-wide" }, config.title)), /* @__PURE__ */ React5.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React5.createElement("table", { className: "w-full text-left border-collapse min-w-[320px] text-sm" }, /* @__PURE__ */ React5.createElement("thead", { className: "bg-slate-50 dark:bg-white/5 border-b border-slate-200 dark:border-white/10" }, /* @__PURE__ */ React5.createElement("tr", null, keys.map((k) => /* @__PURE__ */ React5.createElement(
438
+ return /* @__PURE__ */ React5.createElement("div", { className: "my-4 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm overflow-hidden" }, config.title && /* @__PURE__ */ React5.createElement("div", { className: "px-4 py-2.5 bg-slate-50 dark:bg-white/5 border-b border-slate-200 dark:border-white/10" }, /* @__PURE__ */ React5.createElement("p", { className: "text-xs font-semibold text-slate-600 dark:text-white/70 uppercase tracking-wide" }, config.title)), /* @__PURE__ */ React5.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React5.createElement("table", { className: `w-full text-left border-collapse ${isCompact ? "min-w-[240px] text-xs" : isMedium ? "min-w-[280px] text-[13px]" : "min-w-[320px] text-sm"}` }, /* @__PURE__ */ React5.createElement("thead", { className: "bg-slate-50 dark:bg-white/5 border-b border-slate-200 dark:border-white/10" }, /* @__PURE__ */ React5.createElement("tr", null, keys.map((k) => /* @__PURE__ */ React5.createElement(
418
439
  "th",
419
440
  {
420
441
  key: k,
421
- className: "px-4 py-3 font-semibold text-slate-700 dark:text-white/90 whitespace-nowrap"
442
+ className: `${isCompact ? "px-2.5 py-2" : "px-4 py-3"} font-semibold text-slate-700 dark:text-white/90 whitespace-nowrap`
422
443
  },
423
444
  k
424
445
  )))), /* @__PURE__ */ React5.createElement("tbody", null, config.data.map((row, ri) => /* @__PURE__ */ React5.createElement(
@@ -431,34 +452,63 @@ function DataTable({ config }) {
431
452
  "td",
432
453
  {
433
454
  key: k,
434
- className: "px-4 py-3 text-slate-600 dark:text-white/70 whitespace-nowrap"
455
+ className: `${isCompact ? "px-2.5 py-2" : "px-4 py-3"} text-slate-600 dark:text-white/70 whitespace-nowrap`
435
456
  },
436
457
  formatCell(row[k])
437
458
  ))
438
459
  ))))), /* @__PURE__ */ React5.createElement("div", { className: "px-4 py-2 bg-slate-50 dark:bg-white/5 border-t border-slate-100 dark:border-white/5" }, /* @__PURE__ */ React5.createElement("p", { className: "text-[11px] text-slate-400 dark:text-white/30" }, config.data.length, " row", config.data.length !== 1 ? "s" : "")));
439
460
  }
440
- function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAddToCart }) {
461
+ function normalizeTabularRows(rows, columns) {
462
+ if (!Array.isArray(rows)) return [];
463
+ return rows.map((row) => {
464
+ if (Array.isArray(row)) {
465
+ const keys = Array.isArray(columns) && columns.length > 0 ? columns : row.map((_, index) => `column_${index + 1}`);
466
+ return keys.reduce((acc, key, index) => {
467
+ acc[key] = row[index];
468
+ return acc;
469
+ }, {});
470
+ }
471
+ if (row && typeof row === "object") {
472
+ return row;
473
+ }
474
+ return { value: row };
475
+ }).filter((row) => Object.keys(row).length > 0);
476
+ }
477
+ function resolveStructuredRows(config) {
478
+ if (Array.isArray(config.data) && config.data.length > 0) return config.data;
479
+ if (Array.isArray(config.rows) && config.rows.length > 0) return config.rows;
480
+ if (Array.isArray(config.items) && config.items.length > 0) return config.items;
481
+ if (Array.isArray(config.products) && config.products.length > 0) return config.products;
482
+ if (Array.isArray(config.results) && config.results.length > 0) return config.results;
483
+ return [];
484
+ }
485
+ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAddToCart, viewportSize = "large" }) {
441
486
  var _a;
442
487
  const result = React5.useMemo(() => {
443
488
  if (isStreaming) return { loading: true };
444
489
  try {
445
490
  const clean = rawContent.replace(/^```[a-z]*\s*/i, "").replace(/```\s*$/, "").trim();
446
- const parsed = JSON.parse(sanitizeJson(clean));
491
+ const parsed = JSON.parse(sanitizeJson(extractLikelyJsonBlock(clean)));
447
492
  const config2 = __spreadValues({}, parsed);
448
493
  if (!config2.view) {
449
494
  if (config2.type === "products" || Array.isArray(config2.items)) {
450
495
  config2.view = "carousel";
451
496
  config2.data = config2.data || config2.items || [];
452
- } else if (["pie", "bar", "line"].includes(config2.type) || ["pie", "bar", "line"].includes(config2.chartType)) {
497
+ } else if (typeof config2.type === "string" && ["pie", "bar", "line"].includes(config2.type) || typeof config2.chartType === "string" && ["pie", "bar", "line"].includes(config2.chartType)) {
498
+ const resolvedChartType = config2.chartType === "pie" || config2.chartType === "bar" || config2.chartType === "line" ? config2.chartType : config2.type === "pie" || config2.type === "bar" || config2.type === "line" ? config2.type : "bar";
453
499
  config2.view = "chart";
454
- config2.chartType = config2.chartType || config2.type || "bar";
500
+ config2.chartType = resolvedChartType;
455
501
  config2.data = config2.data || [];
456
502
  } else {
457
503
  config2.view = "table";
458
504
  config2.data = Array.isArray(config2.data) ? config2.data : Array.isArray(config2) ? config2 : [];
459
505
  }
460
506
  }
461
- return { config: config2 };
507
+ const resolvedRows = resolveStructuredRows(config2);
508
+ const normalizedConfig = __spreadProps(__spreadValues({}, config2), {
509
+ data: normalizeTabularRows(resolvedRows, config2.columns)
510
+ });
511
+ return { config: normalizedConfig };
462
512
  } catch (err) {
463
513
  return { error: String(err) };
464
514
  }
@@ -470,11 +520,12 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
470
520
  return /* @__PURE__ */ React5.createElement("pre", { className: "p-4 my-2 bg-slate-900 text-slate-100 rounded-lg text-[10px] overflow-auto max-h-40" }, /* @__PURE__ */ React5.createElement("code", null, rawContent));
471
521
  }
472
522
  const { config } = result;
523
+ const isCompact = viewportSize === "compact";
473
524
  const hasInsights = Array.isArray(config.insights) && config.insights.length > 0;
474
525
  const hasDescription = typeof config.description === "string" && config.description.trim().length > 0;
475
526
  switch (config.view) {
476
527
  case "chart":
477
- return /* @__PURE__ */ React5.createElement("div", { className: "my-6 p-4 bg-white dark:bg-slate-900 rounded-2xl border border-slate-200 dark:border-white/10 shadow-sm overflow-hidden" }, config.title && /* @__PURE__ */ React5.createElement("h4", { className: "text-xs font-semibold text-slate-500 mb-4 px-2" }, config.title), hasDescription && /* @__PURE__ */ React5.createElement("p", { className: "px-2 text-sm text-slate-500 dark:text-white/60" }, config.description), /* @__PURE__ */ React5.createElement(
528
+ return /* @__PURE__ */ React5.createElement("div", { className: `${isCompact ? "my-4 p-3" : "my-6 p-4"} bg-white dark:bg-slate-900 rounded-2xl border border-slate-200 dark:border-white/10 shadow-sm overflow-hidden` }, config.title && /* @__PURE__ */ React5.createElement("h4", { className: `${isCompact ? "text-[11px] mb-3" : "text-xs mb-4"} font-semibold text-slate-500 px-2` }, config.title), hasDescription && /* @__PURE__ */ React5.createElement("p", { className: `px-2 ${isCompact ? "text-xs" : "text-sm"} text-slate-500 dark:text-white/60` }, config.description), /* @__PURE__ */ React5.createElement(
478
529
  DynamicChart,
479
530
  {
480
531
  config: {
@@ -485,25 +536,26 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
485
536
  colors: config.colors
486
537
  },
487
538
  primaryColor,
488
- accentColor
539
+ accentColor,
540
+ viewportSize
489
541
  }
490
542
  ), hasInsights && /* @__PURE__ */ React5.createElement("div", { className: "mt-4 flex flex-wrap gap-2 px-2" }, (_a = config.insights) == null ? void 0 : _a.map((insight) => /* @__PURE__ */ React5.createElement(
491
543
  "span",
492
544
  {
493
545
  key: insight,
494
- className: "rounded-full border border-emerald-200 bg-emerald-50 px-3 py-1 text-[11px] font-medium text-emerald-700 dark:border-emerald-500/20 dark:bg-emerald-500/10 dark:text-emerald-300"
546
+ className: `rounded-full border border-emerald-200 bg-emerald-50 ${isCompact ? "px-2.5 py-1 text-[10px]" : "px-3 py-1 text-[11px]"} font-medium text-emerald-700 dark:border-emerald-500/20 dark:bg-emerald-500/10 dark:text-emerald-300`
495
547
  },
496
548
  insight
497
549
  ))));
498
550
  case "carousel":
499
- return /* @__PURE__ */ React5.createElement("div", { className: "my-4" }, config.title && /* @__PURE__ */ React5.createElement("h4", { className: "mb-2 text-xs font-semibold text-slate-500" }, config.title), hasDescription && /* @__PURE__ */ React5.createElement("p", { className: "mb-3 text-sm text-slate-500 dark:text-white/60" }, config.description), /* @__PURE__ */ React5.createElement(ProductCarousel, { products: config.data.map((item) => {
551
+ return /* @__PURE__ */ React5.createElement("div", { className: "my-4" }, config.title && /* @__PURE__ */ React5.createElement("h4", { className: `${isCompact ? "mb-1.5 text-[11px]" : "mb-2 text-xs"} font-semibold text-slate-500` }, config.title), hasDescription && /* @__PURE__ */ React5.createElement("p", { className: `mb-3 ${isCompact ? "text-xs" : "text-sm"} text-slate-500 dark:text-white/60` }, config.description), /* @__PURE__ */ React5.createElement(ProductCarousel, { products: config.data.map((item) => {
500
552
  var _a2;
501
553
  return __spreadProps(__spreadValues({}, item), {
502
554
  image: (_a2 = item.image) != null ? _a2 : typeof resolveImage === "function" ? resolveImage(item) : void 0
503
555
  });
504
556
  }), primaryColor, onAddToCart }));
505
557
  case "table":
506
- return /* @__PURE__ */ React5.createElement("div", { className: "my-4 p-4 bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm overflow-auto max-h-[400px]" }, config.title && /* @__PURE__ */ React5.createElement("h4", { className: "text-xs font-semibold text-slate-500 mb-2" }, config.title), hasDescription && /* @__PURE__ */ React5.createElement("p", { className: "mb-3 text-sm text-slate-500 dark:text-white/60" }, config.description), /* @__PURE__ */ React5.createElement(DataTable, { config: {
558
+ return /* @__PURE__ */ React5.createElement("div", { className: `${isCompact ? "my-3 p-3 max-h-[320px]" : "my-4 p-4 max-h-[400px]"} bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm overflow-auto` }, config.title && /* @__PURE__ */ React5.createElement("h4", { className: `${isCompact ? "text-[11px]" : "text-xs"} font-semibold text-slate-500 mb-2` }, config.title), hasDescription && /* @__PURE__ */ React5.createElement("p", { className: `mb-3 ${isCompact ? "text-xs" : "text-sm"} text-slate-500 dark:text-white/60` }, config.description), /* @__PURE__ */ React5.createElement(DataTable, { config: {
507
559
  type: "table",
508
560
  title: config.title,
509
561
  description: config.description,
@@ -511,7 +563,7 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
511
563
  dataKeys: config.dataKeys,
512
564
  xAxisKey: config.xAxisKey,
513
565
  data: config.data
514
- } }));
566
+ }, viewportSize }));
515
567
  default:
516
568
  return null;
517
569
  }
@@ -522,9 +574,12 @@ function MessageBubble({
522
574
  isStreaming = false,
523
575
  primaryColor = "#6366f1",
524
576
  accentColor = "#8b5cf6",
525
- onAddToCart
577
+ onAddToCart,
578
+ viewportSize = "large"
526
579
  }) {
527
580
  const isUser = message.role === "user";
581
+ const isCompact = viewportSize === "compact";
582
+ const isMedium = viewportSize === "medium";
528
583
  const [showSources, setShowSources] = React5.useState(false);
529
584
  const hasStructuredProductBlock = React5.useMemo(
530
585
  () => /```(?:ui|json|chart)\s*[\s\S]*?"(?:view|type)"\s*:\s*"(?:carousel|products)"/i.test(message.content),
@@ -701,7 +756,8 @@ ${match.trim()}
701
756
  primaryColor,
702
757
  accentColor,
703
758
  isStreaming,
704
- onAddToCart
759
+ onAddToCart,
760
+ viewportSize
705
761
  }
706
762
  );
707
763
  }
@@ -715,7 +771,8 @@ ${match.trim()}
715
771
  primaryColor,
716
772
  accentColor,
717
773
  isStreaming,
718
- onAddToCart
774
+ onAddToCart,
775
+ viewportSize
719
776
  }
720
777
  );
721
778
  }
@@ -726,22 +783,22 @@ ${match.trim()}
726
783
  return /* @__PURE__ */ React5.createElement("code", __spreadValues({ className }, props), typeof children === "string" || typeof children === "number" ? children : JSON.stringify(children));
727
784
  }
728
785
  }),
729
- [primaryColor, accentColor, isStreaming, onAddToCart]
786
+ [primaryColor, accentColor, isStreaming, onAddToCart, viewportSize]
730
787
  );
731
- return /* @__PURE__ */ React5.createElement("div", { className: `flex gap-3 ${isUser ? "flex-row-reverse" : "flex-row"} items-start` }, /* @__PURE__ */ React5.createElement(
788
+ return /* @__PURE__ */ React5.createElement("div", { className: `flex ${isCompact ? "gap-2" : "gap-3"} ${isUser ? "flex-row-reverse" : "flex-row"} items-start` }, /* @__PURE__ */ React5.createElement(
732
789
  "div",
733
790
  {
734
- className: `flex-shrink-0 w-8 h-8 rounded-full flex items-center justify-center shadow-lg ${isUser ? "text-white" : "bg-slate-100 dark:bg-white/10 text-slate-700 dark:text-white/80"}`,
791
+ className: `flex-shrink-0 ${isCompact ? "w-7 h-7" : "w-8 h-8"} rounded-full flex items-center justify-center shadow-lg ${isUser ? "text-white" : "bg-slate-100 dark:bg-white/10 text-slate-700 dark:text-white/80"}`,
735
792
  style: isUser ? { background: `linear-gradient(135deg, ${primaryColor}, ${accentColor})` } : {}
736
793
  },
737
- isUser ? /* @__PURE__ */ React5.createElement(User, { className: "w-4 h-4 text-white" }) : /* @__PURE__ */ React5.createElement(Bot, { className: "w-4 h-4" })
738
- ), /* @__PURE__ */ React5.createElement("div", { className: `flex flex-col gap-1 max-w-[90%] ${isUser ? "items-end" : "items-start"}` }, /* @__PURE__ */ React5.createElement(
794
+ isUser ? /* @__PURE__ */ React5.createElement(User, { className: `${isCompact ? "w-3.5 h-3.5" : "w-4 h-4"} text-white` }) : /* @__PURE__ */ React5.createElement(Bot, { className: `${isCompact ? "w-3.5 h-3.5" : "w-4 h-4"}` })
795
+ ), /* @__PURE__ */ React5.createElement("div", { className: `flex flex-col gap-1 ${isCompact ? "max-w-[94%]" : isMedium ? "max-w-[92%]" : "max-w-[90%]"} ${isUser ? "items-end" : "items-start"}` }, /* @__PURE__ */ React5.createElement(
739
796
  "div",
740
797
  {
741
- className: `relative px-4 py-3 rounded-2xl text-sm leading-relaxed shadow-sm dark:shadow-lg ${isUser ? "text-white rounded-tr-sm" : "bg-white dark:bg-white/5 border border-slate-200 dark:border-white/10 text-slate-800 dark:text-white/90 rounded-tl-sm"}`,
798
+ className: `relative ${isCompact ? "px-3 py-2.5 text-[13px]" : "px-4 py-3 text-sm"} rounded-2xl leading-relaxed shadow-sm dark:shadow-lg ${isUser ? "text-white rounded-tr-sm" : "bg-white dark:bg-white/5 border border-slate-200 dark:border-white/10 text-slate-800 dark:text-white/90 rounded-tl-sm"}`,
742
799
  style: isUser ? { background: `linear-gradient(135deg, ${primaryColor}, ${accentColor})` } : {}
743
800
  },
744
- isStreaming && !message.content ? /* @__PURE__ */ React5.createElement("span", { className: "flex items-center gap-1 py-1" }, /* @__PURE__ */ React5.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:0ms]" }), /* @__PURE__ */ React5.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:150ms]" }), /* @__PURE__ */ React5.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:300ms]" })) : /* @__PURE__ */ React5.createElement("div", { className: `prose prose-sm max-w-none ${isUser ? "prose-invert" : "dark:prose-invert"}` }, /* @__PURE__ */ React5.createElement(ReactMarkdown, { remarkPlugins: [remarkGfm], components: markdownComponents }, processedMarkdown), isStreaming && message.content && /* @__PURE__ */ React5.createElement("span", { className: "inline-block w-1.5 h-3.5 ml-1 bg-emerald-500 animate-pulse align-middle" }))
801
+ isStreaming && !message.content ? /* @__PURE__ */ React5.createElement("span", { className: "flex items-center gap-1 py-1" }, /* @__PURE__ */ React5.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:0ms]" }), /* @__PURE__ */ React5.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:150ms]" }), /* @__PURE__ */ React5.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:300ms]" })) : /* @__PURE__ */ React5.createElement("div", { className: `prose ${isCompact ? "prose-xs" : "prose-sm"} max-w-none break-words ${isUser ? "prose-invert" : "dark:prose-invert"}` }, /* @__PURE__ */ React5.createElement(ReactMarkdown, { remarkPlugins: [remarkGfm], components: markdownComponents }, processedMarkdown), isStreaming && message.content && /* @__PURE__ */ React5.createElement("span", { className: "inline-block w-1.5 h-3.5 ml-1 bg-emerald-500 animate-pulse align-middle" }))
745
802
  ), !isUser && !hasStructuredProductBlock && allProducts.length > 0 && /* @__PURE__ */ React5.createElement("div", { className: "w-full mt-1" }, /* @__PURE__ */ React5.createElement(
746
803
  ProductCarousel,
747
804
  {
@@ -1024,6 +1081,8 @@ function ChatWindow({
1024
1081
  const { ui, projectId } = useConfig();
1025
1082
  const [input, setInput] = useState4("");
1026
1083
  const [mounted, setMounted] = useState4(false);
1084
+ const [viewportSize, setViewportSize] = useState4("large");
1085
+ const windowRef = useRef3(null);
1027
1086
  const bottomRef = useRef3(null);
1028
1087
  const inputRef = useRef3(null);
1029
1088
  const { messages, send, clear, isLoading, error } = useRagChat(projectId, {
@@ -1082,6 +1141,22 @@ function ChatWindow({
1082
1141
  useEffect4(() => {
1083
1142
  setMounted(true);
1084
1143
  }, []);
1144
+ useEffect4(() => {
1145
+ const element = windowRef.current;
1146
+ if (!element || typeof ResizeObserver === "undefined") return;
1147
+ const resolveViewportSize = (width) => {
1148
+ if (width < 420) return "compact";
1149
+ if (width < 640) return "medium";
1150
+ return "large";
1151
+ };
1152
+ const observer = new ResizeObserver(([entry]) => {
1153
+ if (!entry) return;
1154
+ setViewportSize(resolveViewportSize(entry.contentRect.width));
1155
+ });
1156
+ setViewportSize(resolveViewportSize(element.getBoundingClientRect().width));
1157
+ observer.observe(element);
1158
+ return () => observer.disconnect();
1159
+ }, []);
1085
1160
  useEffect4(() => {
1086
1161
  var _a2;
1087
1162
  if (messages.length > 0 || isLoading) {
@@ -1145,6 +1220,7 @@ function ChatWindow({
1145
1220
  return /* @__PURE__ */ React8.createElement(
1146
1221
  "div",
1147
1222
  {
1223
+ ref: windowRef,
1148
1224
  className: `relative flex flex-col border border-slate-200 dark:border-white/10 shadow-2xl transition-all duration-300 ${currentRadius} ${isGlass ? "bg-white/90 dark:bg-[#0f0f1a]/90 backdrop-blur-xl" : "bg-white dark:bg-[#0f0f1a]"} ${className}`,
1149
1225
  style: __spreadValues({ "--primary": ui.primaryColor, "--accent": ui.accentColor }, style)
1150
1226
  },
@@ -1241,7 +1317,8 @@ function ChatWindow({
1241
1317
  isStreaming: isLoading && index === messages.length - 1 && msg.role === "assistant",
1242
1318
  primaryColor: ui.primaryColor,
1243
1319
  accentColor: ui.accentColor,
1244
- onAddToCart
1320
+ onAddToCart,
1321
+ viewportSize
1245
1322
  }
1246
1323
  )), isLoading && ((_a = messages[messages.length - 1]) == null ? void 0 : _a.role) !== "assistant" && /* @__PURE__ */ React8.createElement(
1247
1324
  MessageBubble,
@@ -1250,7 +1327,8 @@ function ChatWindow({
1250
1327
  isStreaming: true,
1251
1328
  primaryColor: ui.primaryColor,
1252
1329
  accentColor: ui.accentColor,
1253
- onAddToCart
1330
+ onAddToCart,
1331
+ viewportSize
1254
1332
  }
1255
1333
  ), error && /* @__PURE__ */ React8.createElement("div", { className: "flex items-center gap-2 text-rose-500 dark:text-rose-400 text-sm bg-rose-50 dark:bg-rose-400/10 border border-rose-200 dark:border-rose-400/20 rounded-xl px-4 py-3" }, /* @__PURE__ */ React8.createElement(TriangleAlert, { className: "w-4 h-4 flex-shrink-0" }), /* @__PURE__ */ React8.createElement("span", null, error)), /* @__PURE__ */ React8.createElement("div", { ref: bottomRef })),
1256
1334
  /* @__PURE__ */ React8.createElement("div", { className: `px-4 pb-4 pt-2 border-t border-slate-200 dark:border-white/10 ${isGlass ? "bg-transparent" : "bg-white dark:bg-[#0f0f1a]"}` }, (suggestions.length > 0 || isSuggesting) && !isLoading && /* @__PURE__ */ React8.createElement("div", { className: "mb-3 flex flex-wrap gap-2 animate-in fade-in slide-in-from-bottom-2 duration-300" }, suggestions.map((suggestion) => /* @__PURE__ */ React8.createElement(
package/dist/server.js CHANGED
@@ -3952,6 +3952,8 @@ When the user asks for a visual representation, comparison, distribution, breakd
3952
3952
  - Never use ASCII art, markdown tables as the primary answer, or text-only fake charts when a UI block is requested.
3953
3953
  - Put any short natural-language explanation before or after the \`\`\`ui\`\`\` block, but keep it concise.
3954
3954
  - Return valid JSON inside the \`\`\`ui\`\`\` block.
3955
+ - If the user explicitly asks for a pie chart, return "view": "chart" with "chartType": "pie", not a table fallback.
3956
+ - Do not prefix the JSON with labels like "Table View", "Alternative", or explanatory text inside the code block.
3955
3957
 
3956
3958
  5. EXAMPLE
3957
3959
  User: "provide me the distribution of products across categories and highlight which ones are in stock in a pie chart"
package/dist/server.mjs CHANGED
@@ -39,7 +39,7 @@ import {
39
39
  sseFrame,
40
40
  sseMetaFrame,
41
41
  sseTextFrame
42
- } from "./chunk-Q4MDH6C4.mjs";
42
+ } from "./chunk-ID2Q4CF7.mjs";
43
43
  import "./chunk-YLTMFW4M.mjs";
44
44
  import {
45
45
  PineconeProvider
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@retrivora-ai/rag-engine",
3
- "version": "1.5.5",
3
+ "version": "1.5.7",
4
4
  "description": "Retrivora AI is a plug-and-play AI engine for RAG chat experiences — generic vector DB + LLM provider, embeddable or standalone.",
5
5
  "author": "Abhinav Alkuchi",
6
6
  "license": "MIT",
@@ -65,6 +65,8 @@ export function ChatWindow({
65
65
  const { ui, projectId } = useConfig();
66
66
  const [input, setInput] = useState('');
67
67
  const [mounted, setMounted] = useState(false);
68
+ const [viewportSize, setViewportSize] = useState<'compact' | 'medium' | 'large'>('large');
69
+ const windowRef = useRef<HTMLDivElement>(null);
68
70
  const bottomRef = useRef<HTMLDivElement>(null);
69
71
  const inputRef = useRef<HTMLTextAreaElement>(null);
70
72
  const { messages, send, clear, isLoading, error } = useRagChat(projectId, {
@@ -136,6 +138,27 @@ export function ChatWindow({
136
138
  setMounted(true);
137
139
  }, []);
138
140
 
141
+ useEffect(() => {
142
+ const element = windowRef.current;
143
+ if (!element || typeof ResizeObserver === 'undefined') return;
144
+
145
+ const resolveViewportSize = (width: number) => {
146
+ if (width < 420) return 'compact';
147
+ if (width < 640) return 'medium';
148
+ return 'large';
149
+ };
150
+
151
+ const observer = new ResizeObserver(([entry]) => {
152
+ if (!entry) return;
153
+ setViewportSize(resolveViewportSize(entry.contentRect.width));
154
+ });
155
+
156
+ setViewportSize(resolveViewportSize(element.getBoundingClientRect().width));
157
+ observer.observe(element);
158
+
159
+ return () => observer.disconnect();
160
+ }, []);
161
+
139
162
  // Scroll to bottom on new message (but not on initial mount with empty messages)
140
163
  useEffect(() => {
141
164
  if (messages.length > 0 || isLoading) {
@@ -206,6 +229,7 @@ export function ChatWindow({
206
229
 
207
230
  return (
208
231
  <div
232
+ ref={windowRef}
209
233
  className={`relative flex flex-col border border-slate-200 dark:border-white/10 shadow-2xl transition-all duration-300 ${currentRadius} ${
210
234
  isGlass
211
235
  ? 'bg-white/90 dark:bg-[#0f0f1a]/90 backdrop-blur-xl'
@@ -344,6 +368,7 @@ export function ChatWindow({
344
368
  primaryColor={ui.primaryColor}
345
369
  accentColor={ui.accentColor}
346
370
  onAddToCart={onAddToCart}
371
+ viewportSize={viewportSize}
347
372
  />
348
373
  ))
349
374
  )}
@@ -356,6 +381,7 @@ export function ChatWindow({
356
381
  primaryColor={ui.primaryColor}
357
382
  accentColor={ui.accentColor}
358
383
  onAddToCart={onAddToCart}
384
+ viewportSize={viewportSize}
359
385
  />
360
386
  )}
361
387
 
@@ -5,6 +5,7 @@ import {
5
5
  BarChart, Bar, LineChart, Line, PieChart, Pie, Cell,
6
6
  XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer
7
7
  } from 'recharts';
8
+ import { ChatViewportSize } from '../types/props';
8
9
 
9
10
  export interface ChartConfig {
10
11
  type: 'bar' | 'line' | 'pie';
@@ -18,13 +19,28 @@ interface DynamicChartProps {
18
19
  config: ChartConfig;
19
20
  primaryColor?: string;
20
21
  accentColor?: string;
22
+ viewportSize?: ChatViewportSize;
21
23
  }
22
24
 
23
25
  const DEFAULT_COLORS = ['#6366f1', '#10b981', '#f59e0b', '#ef4444', '#8b5cf6', '#ec4899'];
24
26
 
25
- export function DynamicChart({ config, primaryColor = '#6366f1', accentColor = '#8b5cf6' }: DynamicChartProps) {
27
+ export function DynamicChart({
28
+ config,
29
+ primaryColor = '#6366f1',
30
+ accentColor = '#8b5cf6',
31
+ viewportSize = 'large',
32
+ }: DynamicChartProps) {
26
33
  const { type, data } = config;
27
34
  const colors = config.colors || [primaryColor, accentColor, ...DEFAULT_COLORS];
35
+ const isCompact = viewportSize === 'compact';
36
+ const isMedium = viewportSize === 'medium';
37
+ const chartHeightClass = isCompact ? 'h-56 min-h-[220px]' : isMedium ? 'h-64 min-h-[250px]' : 'h-72 min-h-[280px]';
38
+ const pieOuterRadius = isCompact ? 56 : isMedium ? 68 : 80;
39
+ const pieLabel = ({ name, percent }: { name?: string; percent?: number }) =>
40
+ isCompact
41
+ ? `${name}`
42
+ : `${name} ${((percent ?? 0) * 100).toFixed(0)}%`;
43
+ const axisTick = { fontSize: isCompact ? 10 : 12, fill: '#64748b' };
28
44
 
29
45
  // CRITICAL: Sanitize the data array to remove any non-primitive values (objects/arrays)
30
46
  // This prevents the "Objects are not valid as a React child" error in Tooltips/Legends
@@ -176,7 +192,7 @@ export function DynamicChart({ config, primaryColor = '#6366f1', accentColor = '
176
192
  // Handle Pie Chart separately as it has a different structure
177
193
  if (type === 'pie') {
178
194
  return (
179
- <div className="w-full h-72 min-h-[280px] mt-4 mb-2 select-none overflow-hidden">
195
+ <div className={`w-full ${chartHeightClass} mt-4 mb-2 select-none overflow-hidden`}>
180
196
  <ResponsiveContainer width="99%" height="100%">
181
197
  <PieChart>
182
198
  <Pie
@@ -185,15 +201,15 @@ export function DynamicChart({ config, primaryColor = '#6366f1', accentColor = '
185
201
  nameKey={finalXKey}
186
202
  cx="50%"
187
203
  cy="50%"
188
- outerRadius={80}
189
- label={({ name, percent }) => `${name} ${((percent ?? 0) * 100).toFixed(0)}%`}
204
+ outerRadius={pieOuterRadius}
205
+ label={pieLabel}
190
206
  >
191
207
  {sanitizedData.map((entry, index) => (
192
208
  <Cell key={`cell-${index}`} fill={stockAwareColor(entry, index)} />
193
209
  ))}
194
210
  </Pie>
195
211
  <Tooltip content={(props) => renderTooltip(getTooltipRow(props.payload), typeof props.label === 'string' ? props.label : undefined)} />
196
- <Legend />
212
+ <Legend wrapperStyle={{ fontSize: isCompact ? 10 : 12 }} />
197
213
  </PieChart>
198
214
  </ResponsiveContainer>
199
215
  </div>
@@ -202,41 +218,41 @@ export function DynamicChart({ config, primaryColor = '#6366f1', accentColor = '
202
218
 
203
219
  // Bar and Line charts
204
220
  return (
205
- <div className="w-full h-72 min-h-[280px] mt-4 mb-2 select-none overflow-hidden">
221
+ <div className={`w-full ${chartHeightClass} mt-4 mb-2 select-none overflow-hidden`}>
206
222
  <ResponsiveContainer width="99%" height="100%">
207
223
  {type === 'bar' ? (
208
224
  <BarChart data={sanitizedData} margin={{ top: 10, right: 10, left: -20, bottom: 0 }}>
209
225
  <CartesianGrid strokeDasharray="3 3" vertical={false} stroke="#e2e8f0" />
210
- <XAxis dataKey={finalXKey} tick={{ fontSize: 12, fill: '#64748b' }} tickLine={false} axisLine={{ stroke: '#cbd5e1' }} />
211
- <YAxis tick={{ fontSize: 12, fill: '#64748b' }} tickLine={false} axisLine={false} />
226
+ <XAxis dataKey={finalXKey} tick={axisTick} tickLine={false} axisLine={{ stroke: '#cbd5e1' }} />
227
+ <YAxis tick={axisTick} tickLine={false} axisLine={false} />
212
228
  <Tooltip content={(props) => renderTooltip(getTooltipRow(props.payload), typeof props.label === 'string' ? props.label : undefined)} cursor={{ fill: '#f1f5f9' }} />
213
- <Legend wrapperStyle={{ fontSize: 12 }} />
229
+ <Legend wrapperStyle={{ fontSize: isCompact ? 10 : 12 }} />
214
230
  {finalDataKeys.map((key, index) => (
215
231
  <Bar
216
232
  key={key}
217
233
  dataKey={key}
218
234
  fill={colors[index % colors.length]}
219
235
  radius={[4, 4, 0, 0]}
220
- barSize={Math.max(20, 60 / data.length)}
236
+ barSize={isCompact ? Math.max(14, 42 / data.length) : Math.max(20, 60 / data.length)}
221
237
  />
222
238
  ))}
223
239
  </BarChart>
224
240
  ) : (
225
241
  <LineChart data={sanitizedData} margin={{ top: 10, right: 10, left: -20, bottom: 0 }}>
226
242
  <CartesianGrid strokeDasharray="3 3" vertical={false} stroke="#e2e8f0" />
227
- <XAxis dataKey={finalXKey} tick={{ fontSize: 12, fill: '#64748b' }} tickLine={false} axisLine={{ stroke: '#cbd5e1' }} />
228
- <YAxis tick={{ fontSize: 12, fill: '#64748b' }} tickLine={false} axisLine={false} />
243
+ <XAxis dataKey={finalXKey} tick={axisTick} tickLine={false} axisLine={{ stroke: '#cbd5e1' }} />
244
+ <YAxis tick={axisTick} tickLine={false} axisLine={false} />
229
245
  <Tooltip content={(props) => renderTooltip(getTooltipRow(props.payload), typeof props.label === 'string' ? props.label : undefined)} />
230
- <Legend wrapperStyle={{ fontSize: 12 }} />
246
+ <Legend wrapperStyle={{ fontSize: isCompact ? 10 : 12 }} />
231
247
  {finalDataKeys.map((key, index) => (
232
248
  <Line
233
249
  key={key}
234
250
  type="monotone"
235
251
  dataKey={key}
236
252
  stroke={colors[index % colors.length]}
237
- strokeWidth={3}
238
- dot={{ r: 4, strokeWidth: 2 }}
239
- activeDot={{ r: 6 }}
253
+ strokeWidth={isCompact ? 2 : 3}
254
+ dot={{ r: isCompact ? 3 : 4, strokeWidth: 2 }}
255
+ activeDot={{ r: isCompact ? 5 : 6 }}
240
256
  />
241
257
  ))}
242
258
  </LineChart>