@retrivora-ai/rag-engine 1.5.4 → 1.5.6

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.js CHANGED
@@ -174,7 +174,7 @@ function ProductCarousel({ products, primaryColor = "#6366f1", onAddToCart }) {
174
174
  };
175
175
  if (!products || products.length === 0) return null;
176
176
  if (products.length === 1) {
177
- return /* @__PURE__ */ import_react3.default.createElement("div", { className: "my-4 w-[85%] sm:w-[48%] md:w-[31%] min-w-[200px] max-w-[300px] animate-fade-in-up" }, /* @__PURE__ */ import_react3.default.createElement(ProductCard, { product: products[0], primaryColor, onAddToCart }));
177
+ return /* @__PURE__ */ import_react3.default.createElement("div", { className: "my-4 w-[min(88%,18rem)] min-w-0 max-w-full animate-fade-in-up" }, /* @__PURE__ */ import_react3.default.createElement(ProductCard, { product: products[0], primaryColor, onAddToCart }));
178
178
  }
179
179
  return /* @__PURE__ */ import_react3.default.createElement("div", { className: "relative w-full my-4 group/carousel animate-fade-in-up" }, canScroll && /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, /* @__PURE__ */ import_react3.default.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__ */ import_react3.default.createElement(
180
180
  "button",
@@ -209,7 +209,7 @@ function ProductCarousel({ products, primaryColor = "#6366f1", onAddToCart }) {
209
209
  "div",
210
210
  {
211
211
  key: product.id,
212
- className: "snap-start flex-shrink-0 w-[85%] sm:w-[48%] md:w-[31%] min-w-[200px] max-w-[300px]"
212
+ className: "snap-start flex-shrink-0 w-[min(88%,18rem)] min-w-[11rem] max-w-full"
213
213
  },
214
214
  /* @__PURE__ */ import_react3.default.createElement(ProductCard, { product, primaryColor, onAddToCart })
215
215
  ))
@@ -220,9 +220,20 @@ function ProductCarousel({ products, primaryColor = "#6366f1", onAddToCart }) {
220
220
  var import_react4 = __toESM(require("react"));
221
221
  var import_recharts = require("recharts");
222
222
  var DEFAULT_COLORS = ["#6366f1", "#10b981", "#f59e0b", "#ef4444", "#8b5cf6", "#ec4899"];
223
- function DynamicChart({ config, primaryColor = "#6366f1", accentColor = "#8b5cf6" }) {
223
+ function DynamicChart({
224
+ config,
225
+ primaryColor = "#6366f1",
226
+ accentColor = "#8b5cf6",
227
+ viewportSize = "large"
228
+ }) {
224
229
  const { type, data } = config;
225
230
  const colors = config.colors || [primaryColor, accentColor, ...DEFAULT_COLORS];
231
+ const isCompact = viewportSize === "compact";
232
+ const isMedium = viewportSize === "medium";
233
+ const chartHeightClass = isCompact ? "h-56 min-h-[220px]" : isMedium ? "h-64 min-h-[250px]" : "h-72 min-h-[280px]";
234
+ const pieOuterRadius = isCompact ? 56 : isMedium ? 68 : 80;
235
+ const pieLabel = ({ name, percent }) => isCompact ? `${name}` : `${name} ${((percent != null ? percent : 0) * 100).toFixed(0)}%`;
236
+ const axisTick = { fontSize: isCompact ? 10 : 12, fill: "#64748b" };
226
237
  const sanitizedData = import_react4.default.useMemo(() => {
227
238
  if (!data) return [];
228
239
  return data.map((item) => {
@@ -270,9 +281,59 @@ function DynamicChart({ config, primaryColor = "#6366f1", accentColor = "#8b5cf6
270
281
  }).slice(0, 5);
271
282
  const finalXKey = String(resolvedXKey);
272
283
  const finalDataKeys = resolvedDataKeys.map(String).filter((k) => k !== "undefined");
284
+ const pieDataKey = finalDataKeys[0] || "value";
285
+ const stockAwareColor = (entry, index) => {
286
+ var _a, _b, _c;
287
+ const stockStatus = String(
288
+ (_c = (_b = (_a = entry.stockStatus) != null ? _a : entry.status) != null ? _b : entry.availability) != null ? _c : ""
289
+ ).toLowerCase();
290
+ const inStockCount = typeof entry.inStockCount === "number" ? entry.inStockCount : void 0;
291
+ const outOfStockCount = typeof entry.outOfStockCount === "number" ? entry.outOfStockCount : void 0;
292
+ const inStockFlag = entry.inStock;
293
+ if (stockStatus.includes("in stock")) return "#10b981";
294
+ if (stockStatus.includes("out of stock")) return "#f97316";
295
+ if (typeof inStockFlag === "string" && inStockFlag.toLowerCase() === "true") return "#10b981";
296
+ if (inStockFlag === 1) return "#10b981";
297
+ if (inStockFlag === 0) return "#f97316";
298
+ if (typeof inStockCount === "number" || typeof outOfStockCount === "number") {
299
+ const inCount = inStockCount != null ? inStockCount : 0;
300
+ const outCount = outOfStockCount != null ? outOfStockCount : 0;
301
+ if (inCount > outCount) return "#10b981";
302
+ if (outCount > inCount) return "#f97316";
303
+ }
304
+ return colors[index % colors.length];
305
+ };
306
+ const tooltipLabelMap = {
307
+ value: "Value",
308
+ count: "Count",
309
+ inStock: "In stock",
310
+ inStockCount: "In stock",
311
+ outOfStockCount: "Out of stock",
312
+ stockStatus: "Stock status",
313
+ category: "Category",
314
+ label: "Label",
315
+ name: "Name"
316
+ };
317
+ const renderTooltip = (row, label) => {
318
+ var _a, _b;
319
+ if (!row) return null;
320
+ return /* @__PURE__ */ import_react4.default.createElement("div", { className: "rounded-xl border border-slate-200 bg-white px-3 py-2 text-xs shadow-xl dark:border-white/10 dark:bg-slate-950" }, /* @__PURE__ */ import_react4.default.createElement("p", { className: "mb-2 font-semibold text-slate-800 dark:text-white/90" }, String((_b = (_a = row[finalXKey]) != null ? _a : label) != null ? _b : "Details")), Object.entries(row).map(([key, value]) => {
321
+ var _a2;
322
+ if (value === null || value === void 0 || key === finalXKey) return null;
323
+ if (typeof value === "object") return null;
324
+ return /* @__PURE__ */ import_react4.default.createElement("div", { key, className: "flex items-center justify-between gap-3 text-slate-600 dark:text-white/70" }, /* @__PURE__ */ import_react4.default.createElement("span", null, (_a2 = tooltipLabelMap[key]) != null ? _a2 : key), /* @__PURE__ */ import_react4.default.createElement("span", { className: "font-medium text-slate-900 dark:text-white/90" }, String(value)));
325
+ }));
326
+ };
327
+ const getTooltipRow = (payload) => {
328
+ if (!Array.isArray(payload) || payload.length === 0) return null;
329
+ const first = payload[0];
330
+ if (!first || typeof first !== "object" || !("payload" in first)) return null;
331
+ const row = first.payload;
332
+ if (!row || typeof row !== "object" || Array.isArray(row)) return null;
333
+ return row;
334
+ };
273
335
  if (type === "pie") {
274
- const pieDataKey = finalDataKeys[0] || "value";
275
- return /* @__PURE__ */ import_react4.default.createElement("div", { className: "w-full h-72 min-h-[280px] mt-4 mb-2 select-none overflow-hidden" }, /* @__PURE__ */ import_react4.default.createElement(import_recharts.ResponsiveContainer, { width: "99%", height: "100%" }, /* @__PURE__ */ import_react4.default.createElement(import_recharts.PieChart, null, /* @__PURE__ */ import_react4.default.createElement(
336
+ return /* @__PURE__ */ import_react4.default.createElement("div", { className: `w-full ${chartHeightClass} mt-4 mb-2 select-none overflow-hidden` }, /* @__PURE__ */ import_react4.default.createElement(import_recharts.ResponsiveContainer, { width: "99%", height: "100%" }, /* @__PURE__ */ import_react4.default.createElement(import_recharts.PieChart, null, /* @__PURE__ */ import_react4.default.createElement(
276
337
  import_recharts.Pie,
277
338
  {
278
339
  data: sanitizedData,
@@ -280,47 +341,31 @@ function DynamicChart({ config, primaryColor = "#6366f1", accentColor = "#8b5cf6
280
341
  nameKey: finalXKey,
281
342
  cx: "50%",
282
343
  cy: "50%",
283
- outerRadius: 80,
284
- label: ({ name, percent }) => `${name} ${((percent != null ? percent : 0) * 100).toFixed(0)}%`
344
+ outerRadius: pieOuterRadius,
345
+ label: pieLabel
285
346
  },
286
- data.map((entry, index) => /* @__PURE__ */ import_react4.default.createElement(import_recharts.Cell, { key: `cell-${index}`, fill: colors[index % colors.length] }))
287
- ), /* @__PURE__ */ import_react4.default.createElement(
288
- import_recharts.Tooltip,
289
- {
290
- contentStyle: { borderRadius: "8px", border: "none", boxShadow: "0 4px 6px -1px rgb(0 0 0 / 0.1)" }
291
- }
292
- ), /* @__PURE__ */ import_react4.default.createElement(import_recharts.Legend, null))));
347
+ sanitizedData.map((entry, index) => /* @__PURE__ */ import_react4.default.createElement(import_recharts.Cell, { key: `cell-${index}`, fill: stockAwareColor(entry, index) }))
348
+ ), /* @__PURE__ */ import_react4.default.createElement(import_recharts.Tooltip, { content: (props) => renderTooltip(getTooltipRow(props.payload), typeof props.label === "string" ? props.label : void 0) }), /* @__PURE__ */ import_react4.default.createElement(import_recharts.Legend, { wrapperStyle: { fontSize: isCompact ? 10 : 12 } }))));
293
349
  }
294
- return /* @__PURE__ */ import_react4.default.createElement("div", { className: "w-full h-72 min-h-[280px] mt-4 mb-2 select-none overflow-hidden" }, /* @__PURE__ */ import_react4.default.createElement(import_recharts.ResponsiveContainer, { width: "99%", height: "100%" }, type === "bar" ? /* @__PURE__ */ import_react4.default.createElement(import_recharts.BarChart, { data: sanitizedData, margin: { top: 10, right: 10, left: -20, bottom: 0 } }, /* @__PURE__ */ import_react4.default.createElement(import_recharts.CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }), /* @__PURE__ */ import_react4.default.createElement(import_recharts.XAxis, { dataKey: finalXKey, tick: { fontSize: 12, fill: "#64748b" }, tickLine: false, axisLine: { stroke: "#cbd5e1" } }), /* @__PURE__ */ import_react4.default.createElement(import_recharts.YAxis, { tick: { fontSize: 12, fill: "#64748b" }, tickLine: false, axisLine: false }), /* @__PURE__ */ import_react4.default.createElement(
295
- import_recharts.Tooltip,
296
- {
297
- contentStyle: { borderRadius: "8px", border: "none", boxShadow: "0 4px 6px -1px rgb(0 0 0 / 0.1)" },
298
- cursor: { fill: "#f1f5f9" }
299
- }
300
- ), /* @__PURE__ */ import_react4.default.createElement(import_recharts.Legend, { wrapperStyle: { fontSize: 12 } }), finalDataKeys.map((key, index) => /* @__PURE__ */ import_react4.default.createElement(
350
+ return /* @__PURE__ */ import_react4.default.createElement("div", { className: `w-full ${chartHeightClass} mt-4 mb-2 select-none overflow-hidden` }, /* @__PURE__ */ import_react4.default.createElement(import_recharts.ResponsiveContainer, { width: "99%", height: "100%" }, type === "bar" ? /* @__PURE__ */ import_react4.default.createElement(import_recharts.BarChart, { data: sanitizedData, margin: { top: 10, right: 10, left: -20, bottom: 0 } }, /* @__PURE__ */ import_react4.default.createElement(import_recharts.CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }), /* @__PURE__ */ import_react4.default.createElement(import_recharts.XAxis, { dataKey: finalXKey, tick: axisTick, tickLine: false, axisLine: { stroke: "#cbd5e1" } }), /* @__PURE__ */ import_react4.default.createElement(import_recharts.YAxis, { tick: axisTick, tickLine: false, axisLine: false }), /* @__PURE__ */ import_react4.default.createElement(import_recharts.Tooltip, { content: (props) => renderTooltip(getTooltipRow(props.payload), typeof props.label === "string" ? props.label : void 0), cursor: { fill: "#f1f5f9" } }), /* @__PURE__ */ import_react4.default.createElement(import_recharts.Legend, { wrapperStyle: { fontSize: isCompact ? 10 : 12 } }), finalDataKeys.map((key, index) => /* @__PURE__ */ import_react4.default.createElement(
301
351
  import_recharts.Bar,
302
352
  {
303
353
  key,
304
354
  dataKey: key,
305
355
  fill: colors[index % colors.length],
306
356
  radius: [4, 4, 0, 0],
307
- barSize: Math.max(20, 60 / data.length)
357
+ barSize: isCompact ? Math.max(14, 42 / data.length) : Math.max(20, 60 / data.length)
308
358
  }
309
- ))) : /* @__PURE__ */ import_react4.default.createElement(import_recharts.LineChart, { data: sanitizedData, margin: { top: 10, right: 10, left: -20, bottom: 0 } }, /* @__PURE__ */ import_react4.default.createElement(import_recharts.CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }), /* @__PURE__ */ import_react4.default.createElement(import_recharts.XAxis, { dataKey: finalXKey, tick: { fontSize: 12, fill: "#64748b" }, tickLine: false, axisLine: { stroke: "#cbd5e1" } }), /* @__PURE__ */ import_react4.default.createElement(import_recharts.YAxis, { tick: { fontSize: 12, fill: "#64748b" }, tickLine: false, axisLine: false }), /* @__PURE__ */ import_react4.default.createElement(
310
- import_recharts.Tooltip,
311
- {
312
- contentStyle: { borderRadius: "8px", border: "none", boxShadow: "0 4px 6px -1px rgb(0 0 0 / 0.1)" }
313
- }
314
- ), /* @__PURE__ */ import_react4.default.createElement(import_recharts.Legend, { wrapperStyle: { fontSize: 12 } }), finalDataKeys.map((key, index) => /* @__PURE__ */ import_react4.default.createElement(
359
+ ))) : /* @__PURE__ */ import_react4.default.createElement(import_recharts.LineChart, { data: sanitizedData, margin: { top: 10, right: 10, left: -20, bottom: 0 } }, /* @__PURE__ */ import_react4.default.createElement(import_recharts.CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }), /* @__PURE__ */ import_react4.default.createElement(import_recharts.XAxis, { dataKey: finalXKey, tick: axisTick, tickLine: false, axisLine: { stroke: "#cbd5e1" } }), /* @__PURE__ */ import_react4.default.createElement(import_recharts.YAxis, { tick: axisTick, tickLine: false, axisLine: false }), /* @__PURE__ */ import_react4.default.createElement(import_recharts.Tooltip, { content: (props) => renderTooltip(getTooltipRow(props.payload), typeof props.label === "string" ? props.label : void 0) }), /* @__PURE__ */ import_react4.default.createElement(import_recharts.Legend, { wrapperStyle: { fontSize: isCompact ? 10 : 12 } }), finalDataKeys.map((key, index) => /* @__PURE__ */ import_react4.default.createElement(
315
360
  import_recharts.Line,
316
361
  {
317
362
  key,
318
363
  type: "monotone",
319
364
  dataKey: key,
320
365
  stroke: colors[index % colors.length],
321
- strokeWidth: 3,
322
- dot: { r: 4, strokeWidth: 2 },
323
- activeDot: { r: 6 }
366
+ strokeWidth: isCompact ? 2 : 3,
367
+ dot: { r: isCompact ? 3 : 4, strokeWidth: 2 },
368
+ activeDot: { r: isCompact ? 5 : 6 }
324
369
  }
325
370
  )))));
326
371
  }
@@ -379,6 +424,14 @@ function sanitizeJson(raw) {
379
424
  }
380
425
  return s;
381
426
  }
427
+ function extractLikelyJsonBlock(raw) {
428
+ const trimmed = raw.trim();
429
+ const objectStart = trimmed.indexOf("{");
430
+ const arrayStart = trimmed.indexOf("[");
431
+ const starts = [objectStart, arrayStart].filter((index) => index >= 0);
432
+ if (starts.length === 0) return trimmed;
433
+ return trimmed.slice(Math.min(...starts));
434
+ }
382
435
  function resolveImage(data) {
383
436
  for (const key of ["image", "img", "thumbnail"]) {
384
437
  const v = data[key];
@@ -395,7 +448,9 @@ function normaliseChild(children) {
395
448
  }
396
449
  return children;
397
450
  }
398
- function DataTable({ config }) {
451
+ function DataTable({ config, viewportSize = "large" }) {
452
+ const isCompact = viewportSize === "compact";
453
+ const isMedium = viewportSize === "medium";
399
454
  const keys = import_react5.default.useMemo(() => {
400
455
  if (Array.isArray(config.columns) && config.columns.length) {
401
456
  return config.columns;
@@ -417,11 +472,11 @@ function DataTable({ config }) {
417
472
  if (typeof val === "boolean") return val ? "\u2713" : "\u2717";
418
473
  return String(val);
419
474
  };
420
- return /* @__PURE__ */ import_react5.default.createElement("div", { className: "my-4 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm overflow-hidden" }, config.title && /* @__PURE__ */ import_react5.default.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__ */ import_react5.default.createElement("p", { className: "text-xs font-semibold text-slate-600 dark:text-white/70 uppercase tracking-wide" }, config.title)), /* @__PURE__ */ import_react5.default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ import_react5.default.createElement("table", { className: "w-full text-left border-collapse min-w-[320px] text-sm" }, /* @__PURE__ */ import_react5.default.createElement("thead", { className: "bg-slate-50 dark:bg-white/5 border-b border-slate-200 dark:border-white/10" }, /* @__PURE__ */ import_react5.default.createElement("tr", null, keys.map((k) => /* @__PURE__ */ import_react5.default.createElement(
475
+ return /* @__PURE__ */ import_react5.default.createElement("div", { className: "my-4 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm overflow-hidden" }, config.title && /* @__PURE__ */ import_react5.default.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__ */ import_react5.default.createElement("p", { className: "text-xs font-semibold text-slate-600 dark:text-white/70 uppercase tracking-wide" }, config.title)), /* @__PURE__ */ import_react5.default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ import_react5.default.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__ */ import_react5.default.createElement("thead", { className: "bg-slate-50 dark:bg-white/5 border-b border-slate-200 dark:border-white/10" }, /* @__PURE__ */ import_react5.default.createElement("tr", null, keys.map((k) => /* @__PURE__ */ import_react5.default.createElement(
421
476
  "th",
422
477
  {
423
478
  key: k,
424
- className: "px-4 py-3 font-semibold text-slate-700 dark:text-white/90 whitespace-nowrap"
479
+ className: `${isCompact ? "px-2.5 py-2" : "px-4 py-3"} font-semibold text-slate-700 dark:text-white/90 whitespace-nowrap`
425
480
  },
426
481
  k
427
482
  )))), /* @__PURE__ */ import_react5.default.createElement("tbody", null, config.data.map((row, ri) => /* @__PURE__ */ import_react5.default.createElement(
@@ -434,33 +489,54 @@ function DataTable({ config }) {
434
489
  "td",
435
490
  {
436
491
  key: k,
437
- className: "px-4 py-3 text-slate-600 dark:text-white/70 whitespace-nowrap"
492
+ className: `${isCompact ? "px-2.5 py-2" : "px-4 py-3"} text-slate-600 dark:text-white/70 whitespace-nowrap`
438
493
  },
439
494
  formatCell(row[k])
440
495
  ))
441
496
  ))))), /* @__PURE__ */ import_react5.default.createElement("div", { className: "px-4 py-2 bg-slate-50 dark:bg-white/5 border-t border-slate-100 dark:border-white/5" }, /* @__PURE__ */ import_react5.default.createElement("p", { className: "text-[11px] text-slate-400 dark:text-white/30" }, config.data.length, " row", config.data.length !== 1 ? "s" : "")));
442
497
  }
443
- function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming }) {
498
+ function normalizeTabularRows(rows, columns) {
499
+ if (!Array.isArray(rows)) return [];
500
+ return rows.map((row) => {
501
+ if (Array.isArray(row)) {
502
+ const keys = Array.isArray(columns) && columns.length > 0 ? columns : row.map((_, index) => `column_${index + 1}`);
503
+ return keys.reduce((acc, key, index) => {
504
+ acc[key] = row[index];
505
+ return acc;
506
+ }, {});
507
+ }
508
+ if (row && typeof row === "object") {
509
+ return row;
510
+ }
511
+ return { value: row };
512
+ }).filter((row) => Object.keys(row).length > 0);
513
+ }
514
+ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAddToCart, viewportSize = "large" }) {
515
+ var _a;
444
516
  const result = import_react5.default.useMemo(() => {
445
517
  if (isStreaming) return { loading: true };
446
518
  try {
447
519
  const clean = rawContent.replace(/^```[a-z]*\s*/i, "").replace(/```\s*$/, "").trim();
448
- const parsed = JSON.parse(sanitizeJson(clean));
520
+ const parsed = JSON.parse(sanitizeJson(extractLikelyJsonBlock(clean)));
449
521
  const config2 = __spreadValues({}, parsed);
450
522
  if (!config2.view) {
451
523
  if (config2.type === "products" || Array.isArray(config2.items)) {
452
524
  config2.view = "carousel";
453
525
  config2.data = config2.data || config2.items || [];
454
- } else if (["pie", "bar", "line"].includes(config2.type) || ["pie", "bar", "line"].includes(config2.chartType)) {
526
+ } else if (typeof config2.type === "string" && ["pie", "bar", "line"].includes(config2.type) || typeof config2.chartType === "string" && ["pie", "bar", "line"].includes(config2.chartType)) {
527
+ 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";
455
528
  config2.view = "chart";
456
- config2.chartType = config2.chartType || config2.type || "bar";
529
+ config2.chartType = resolvedChartType;
457
530
  config2.data = config2.data || [];
458
531
  } else {
459
532
  config2.view = "table";
460
533
  config2.data = Array.isArray(config2.data) ? config2.data : Array.isArray(config2) ? config2 : [];
461
534
  }
462
535
  }
463
- return { config: config2 };
536
+ const normalizedConfig = __spreadProps(__spreadValues({}, config2), {
537
+ data: normalizeTabularRows(config2.data, config2.columns)
538
+ });
539
+ return { config: normalizedConfig };
464
540
  } catch (err) {
465
541
  return { error: String(err) };
466
542
  }
@@ -472,28 +548,50 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming }) {
472
548
  return /* @__PURE__ */ import_react5.default.createElement("pre", { className: "p-4 my-2 bg-slate-900 text-slate-100 rounded-lg text-[10px] overflow-auto max-h-40" }, /* @__PURE__ */ import_react5.default.createElement("code", null, rawContent));
473
549
  }
474
550
  const { config } = result;
551
+ const isCompact = viewportSize === "compact";
552
+ const hasInsights = Array.isArray(config.insights) && config.insights.length > 0;
553
+ const hasDescription = typeof config.description === "string" && config.description.trim().length > 0;
475
554
  switch (config.view) {
476
555
  case "chart":
477
- return /* @__PURE__ */ import_react5.default.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__ */ import_react5.default.createElement("h4", { className: "text-xs font-semibold text-slate-500 mb-4 px-2" }, config.title), /* @__PURE__ */ import_react5.default.createElement(
556
+ return /* @__PURE__ */ import_react5.default.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__ */ import_react5.default.createElement("h4", { className: `${isCompact ? "text-[11px] mb-3" : "text-xs mb-4"} font-semibold text-slate-500 px-2` }, config.title), hasDescription && /* @__PURE__ */ import_react5.default.createElement("p", { className: `px-2 ${isCompact ? "text-xs" : "text-sm"} text-slate-500 dark:text-white/60` }, config.description), /* @__PURE__ */ import_react5.default.createElement(
478
557
  DynamicChart,
479
558
  {
480
559
  config: {
481
560
  type: config.chartType || "bar",
482
- data: config.data
561
+ data: config.data,
562
+ xAxisKey: config.xAxisKey,
563
+ dataKeys: config.dataKeys,
564
+ colors: config.colors
483
565
  },
484
566
  primaryColor,
485
- accentColor
567
+ accentColor,
568
+ viewportSize
486
569
  }
487
- ));
570
+ ), hasInsights && /* @__PURE__ */ import_react5.default.createElement("div", { className: "mt-4 flex flex-wrap gap-2 px-2" }, (_a = config.insights) == null ? void 0 : _a.map((insight) => /* @__PURE__ */ import_react5.default.createElement(
571
+ "span",
572
+ {
573
+ key: insight,
574
+ 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`
575
+ },
576
+ insight
577
+ ))));
488
578
  case "carousel":
489
- return /* @__PURE__ */ import_react5.default.createElement("div", { className: "my-4" }, /* @__PURE__ */ import_react5.default.createElement(ProductCarousel, { products: config.data.map((item) => {
490
- var _a;
579
+ return /* @__PURE__ */ import_react5.default.createElement("div", { className: "my-4" }, config.title && /* @__PURE__ */ import_react5.default.createElement("h4", { className: `${isCompact ? "mb-1.5 text-[11px]" : "mb-2 text-xs"} font-semibold text-slate-500` }, config.title), hasDescription && /* @__PURE__ */ import_react5.default.createElement("p", { className: `mb-3 ${isCompact ? "text-xs" : "text-sm"} text-slate-500 dark:text-white/60` }, config.description), /* @__PURE__ */ import_react5.default.createElement(ProductCarousel, { products: config.data.map((item) => {
580
+ var _a2;
491
581
  return __spreadProps(__spreadValues({}, item), {
492
- image: (_a = item.image) != null ? _a : typeof resolveImage === "function" ? resolveImage(item) : void 0
582
+ image: (_a2 = item.image) != null ? _a2 : typeof resolveImage === "function" ? resolveImage(item) : void 0
493
583
  });
494
- }) }));
584
+ }), primaryColor, onAddToCart }));
495
585
  case "table":
496
- return /* @__PURE__ */ import_react5.default.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__ */ import_react5.default.createElement("h4", { className: "text-xs font-semibold text-slate-500 mb-2" }, config.title), /* @__PURE__ */ import_react5.default.createElement(DataTable, { config: { type: "table", data: config.data } }));
586
+ return /* @__PURE__ */ import_react5.default.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__ */ import_react5.default.createElement("h4", { className: `${isCompact ? "text-[11px]" : "text-xs"} font-semibold text-slate-500 mb-2` }, config.title), hasDescription && /* @__PURE__ */ import_react5.default.createElement("p", { className: `mb-3 ${isCompact ? "text-xs" : "text-sm"} text-slate-500 dark:text-white/60` }, config.description), /* @__PURE__ */ import_react5.default.createElement(DataTable, { config: {
587
+ type: "table",
588
+ title: config.title,
589
+ description: config.description,
590
+ columns: config.columns,
591
+ dataKeys: config.dataKeys,
592
+ xAxisKey: config.xAxisKey,
593
+ data: config.data
594
+ }, viewportSize }));
497
595
  default:
498
596
  return null;
499
597
  }
@@ -504,10 +602,17 @@ function MessageBubble({
504
602
  isStreaming = false,
505
603
  primaryColor = "#6366f1",
506
604
  accentColor = "#8b5cf6",
507
- onAddToCart
605
+ onAddToCart,
606
+ viewportSize = "large"
508
607
  }) {
509
608
  const isUser = message.role === "user";
609
+ const isCompact = viewportSize === "compact";
610
+ const isMedium = viewportSize === "medium";
510
611
  const [showSources, setShowSources] = import_react5.default.useState(false);
612
+ const hasStructuredProductBlock = import_react5.default.useMemo(
613
+ () => /```(?:ui|json|chart)\s*[\s\S]*?"(?:view|type)"\s*:\s*"(?:carousel|products)"/i.test(message.content),
614
+ [message.content]
615
+ );
511
616
  const productsFromSources = import_react5.default.useMemo(() => {
512
617
  if (isUser || !sources) return [];
513
618
  return sources.filter((s) => {
@@ -678,7 +783,9 @@ ${match.trim()}
678
783
  rawContent: String(children != null ? children : "").trim(),
679
784
  primaryColor,
680
785
  accentColor,
681
- isStreaming
786
+ isStreaming,
787
+ onAddToCart,
788
+ viewportSize
682
789
  }
683
790
  );
684
791
  }
@@ -691,7 +798,9 @@ ${match.trim()}
691
798
  rawContent: content,
692
799
  primaryColor,
693
800
  accentColor,
694
- isStreaming
801
+ isStreaming,
802
+ onAddToCart,
803
+ viewportSize
695
804
  }
696
805
  );
697
806
  }
@@ -702,23 +811,23 @@ ${match.trim()}
702
811
  return /* @__PURE__ */ import_react5.default.createElement("code", __spreadValues({ className }, props), typeof children === "string" || typeof children === "number" ? children : JSON.stringify(children));
703
812
  }
704
813
  }),
705
- [primaryColor, accentColor, isStreaming]
814
+ [primaryColor, accentColor, isStreaming, onAddToCart, viewportSize]
706
815
  );
707
- return /* @__PURE__ */ import_react5.default.createElement("div", { className: `flex gap-3 ${isUser ? "flex-row-reverse" : "flex-row"} items-start` }, /* @__PURE__ */ import_react5.default.createElement(
816
+ return /* @__PURE__ */ import_react5.default.createElement("div", { className: `flex ${isCompact ? "gap-2" : "gap-3"} ${isUser ? "flex-row-reverse" : "flex-row"} items-start` }, /* @__PURE__ */ import_react5.default.createElement(
708
817
  "div",
709
818
  {
710
- 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"}`,
819
+ 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"}`,
711
820
  style: isUser ? { background: `linear-gradient(135deg, ${primaryColor}, ${accentColor})` } : {}
712
821
  },
713
- isUser ? /* @__PURE__ */ import_react5.default.createElement(import_lucide_react4.User, { className: "w-4 h-4 text-white" }) : /* @__PURE__ */ import_react5.default.createElement(import_lucide_react4.Bot, { className: "w-4 h-4" })
714
- ), /* @__PURE__ */ import_react5.default.createElement("div", { className: `flex flex-col gap-1 max-w-[90%] ${isUser ? "items-end" : "items-start"}` }, /* @__PURE__ */ import_react5.default.createElement(
822
+ isUser ? /* @__PURE__ */ import_react5.default.createElement(import_lucide_react4.User, { className: `${isCompact ? "w-3.5 h-3.5" : "w-4 h-4"} text-white` }) : /* @__PURE__ */ import_react5.default.createElement(import_lucide_react4.Bot, { className: `${isCompact ? "w-3.5 h-3.5" : "w-4 h-4"}` })
823
+ ), /* @__PURE__ */ import_react5.default.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__ */ import_react5.default.createElement(
715
824
  "div",
716
825
  {
717
- 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"}`,
826
+ 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"}`,
718
827
  style: isUser ? { background: `linear-gradient(135deg, ${primaryColor}, ${accentColor})` } : {}
719
828
  },
720
- isStreaming && !message.content ? /* @__PURE__ */ import_react5.default.createElement("span", { className: "flex items-center gap-1 py-1" }, /* @__PURE__ */ import_react5.default.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:0ms]" }), /* @__PURE__ */ import_react5.default.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:150ms]" }), /* @__PURE__ */ import_react5.default.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:300ms]" })) : /* @__PURE__ */ import_react5.default.createElement("div", { className: `prose prose-sm max-w-none ${isUser ? "prose-invert" : "dark:prose-invert"}` }, /* @__PURE__ */ import_react5.default.createElement(import_react_markdown.default, { remarkPlugins: [import_remark_gfm.default], components: markdownComponents }, processedMarkdown), isStreaming && message.content && /* @__PURE__ */ import_react5.default.createElement("span", { className: "inline-block w-1.5 h-3.5 ml-1 bg-emerald-500 animate-pulse align-middle" }))
721
- ), !isUser && allProducts.length > 0 && /* @__PURE__ */ import_react5.default.createElement("div", { className: "w-full mt-1" }, /* @__PURE__ */ import_react5.default.createElement(
829
+ isStreaming && !message.content ? /* @__PURE__ */ import_react5.default.createElement("span", { className: "flex items-center gap-1 py-1" }, /* @__PURE__ */ import_react5.default.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:0ms]" }), /* @__PURE__ */ import_react5.default.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:150ms]" }), /* @__PURE__ */ import_react5.default.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:300ms]" })) : /* @__PURE__ */ import_react5.default.createElement("div", { className: `prose ${isCompact ? "prose-xs" : "prose-sm"} max-w-none break-words ${isUser ? "prose-invert" : "dark:prose-invert"}` }, /* @__PURE__ */ import_react5.default.createElement(import_react_markdown.default, { remarkPlugins: [import_remark_gfm.default], components: markdownComponents }, processedMarkdown), isStreaming && message.content && /* @__PURE__ */ import_react5.default.createElement("span", { className: "inline-block w-1.5 h-3.5 ml-1 bg-emerald-500 animate-pulse align-middle" }))
830
+ ), !isUser && !hasStructuredProductBlock && allProducts.length > 0 && /* @__PURE__ */ import_react5.default.createElement("div", { className: "w-full mt-1" }, /* @__PURE__ */ import_react5.default.createElement(
722
831
  ProductCarousel,
723
832
  {
724
833
  products: allProducts,
@@ -1014,6 +1123,8 @@ function ChatWindow({
1014
1123
  const { ui, projectId } = useConfig();
1015
1124
  const [input, setInput] = (0, import_react8.useState)("");
1016
1125
  const [mounted, setMounted] = (0, import_react8.useState)(false);
1126
+ const [viewportSize, setViewportSize] = (0, import_react8.useState)("large");
1127
+ const windowRef = (0, import_react8.useRef)(null);
1017
1128
  const bottomRef = (0, import_react8.useRef)(null);
1018
1129
  const inputRef = (0, import_react8.useRef)(null);
1019
1130
  const { messages, send, clear, isLoading, error } = useRagChat(projectId, {
@@ -1072,6 +1183,22 @@ function ChatWindow({
1072
1183
  (0, import_react8.useEffect)(() => {
1073
1184
  setMounted(true);
1074
1185
  }, []);
1186
+ (0, import_react8.useEffect)(() => {
1187
+ const element = windowRef.current;
1188
+ if (!element || typeof ResizeObserver === "undefined") return;
1189
+ const resolveViewportSize = (width) => {
1190
+ if (width < 420) return "compact";
1191
+ if (width < 640) return "medium";
1192
+ return "large";
1193
+ };
1194
+ const observer = new ResizeObserver(([entry]) => {
1195
+ if (!entry) return;
1196
+ setViewportSize(resolveViewportSize(entry.contentRect.width));
1197
+ });
1198
+ setViewportSize(resolveViewportSize(element.getBoundingClientRect().width));
1199
+ observer.observe(element);
1200
+ return () => observer.disconnect();
1201
+ }, []);
1075
1202
  (0, import_react8.useEffect)(() => {
1076
1203
  var _a2;
1077
1204
  if (messages.length > 0 || isLoading) {
@@ -1135,6 +1262,7 @@ function ChatWindow({
1135
1262
  return /* @__PURE__ */ import_react8.default.createElement(
1136
1263
  "div",
1137
1264
  {
1265
+ ref: windowRef,
1138
1266
  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}`,
1139
1267
  style: __spreadValues({ "--primary": ui.primaryColor, "--accent": ui.accentColor }, style)
1140
1268
  },
@@ -1231,7 +1359,8 @@ function ChatWindow({
1231
1359
  isStreaming: isLoading && index === messages.length - 1 && msg.role === "assistant",
1232
1360
  primaryColor: ui.primaryColor,
1233
1361
  accentColor: ui.accentColor,
1234
- onAddToCart
1362
+ onAddToCart,
1363
+ viewportSize
1235
1364
  }
1236
1365
  )), isLoading && ((_a = messages[messages.length - 1]) == null ? void 0 : _a.role) !== "assistant" && /* @__PURE__ */ import_react8.default.createElement(
1237
1366
  MessageBubble,
@@ -1240,7 +1369,8 @@ function ChatWindow({
1240
1369
  isStreaming: true,
1241
1370
  primaryColor: ui.primaryColor,
1242
1371
  accentColor: ui.accentColor,
1243
- onAddToCart
1372
+ onAddToCart,
1373
+ viewportSize
1244
1374
  }
1245
1375
  ), error && /* @__PURE__ */ import_react8.default.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__ */ import_react8.default.createElement(import_lucide_react5.TriangleAlert, { className: "w-4 h-4 flex-shrink-0" }), /* @__PURE__ */ import_react8.default.createElement("span", null, error)), /* @__PURE__ */ import_react8.default.createElement("div", { ref: bottomRef })),
1246
1376
  /* @__PURE__ */ import_react8.default.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__ */ import_react8.default.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__ */ import_react8.default.createElement(