orchid-ai 2.1.5 → 2.2.0

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/orchid-ai.css CHANGED
@@ -860,6 +860,39 @@
860
860
  color: #1f2937;
861
861
  }
862
862
 
863
+ .ai-chart-card-header {
864
+ display: flex;
865
+ align-items: center;
866
+ justify-content: space-between;
867
+ gap: 12px;
868
+ margin-bottom: 10px;
869
+ }
870
+
871
+ .ai-chart-card-header .ai-chart-title {
872
+ margin: 0;
873
+ }
874
+
875
+ .ai-chart-csv-btn {
876
+ display: inline-flex;
877
+ align-items: center;
878
+ gap: 4px;
879
+ flex-shrink: 0;
880
+ padding: 4px 10px;
881
+ font-size: 12px;
882
+ font-weight: 500;
883
+ color: #1eaaf1;
884
+ background: #ffffff;
885
+ border: 1px solid #d1d5db;
886
+ border-radius: 6px;
887
+ cursor: pointer;
888
+ transition: background 0.15s, border-color 0.15s;
889
+ }
890
+
891
+ .ai-chart-csv-btn:hover {
892
+ background: #f0f9ff;
893
+ border-color: #1eaaf1;
894
+ }
895
+
863
896
  .ai-chart-error {
864
897
  color: #b91c1c;
865
898
  background: #fef2f2;
@@ -1877,8 +1910,9 @@
1877
1910
  font-size: 22px;
1878
1911
  font-weight: 700;
1879
1912
  color: #1f2937;
1880
- line-height: 1;
1913
+ line-height: 1.15;
1881
1914
  margin-bottom: 5px;
1915
+ overflow-wrap: break-word;
1882
1916
  }
1883
1917
 
1884
1918
  .ai-stat-unit {
@@ -2762,6 +2796,20 @@
2762
2796
  color: #1f2937 !important;
2763
2797
  box-shadow: none !important;
2764
2798
  }
2799
+
2800
+ body.ai-chat-printing #ai-cortex-print-section .ai-stat-card {
2801
+ padding: 8px 10px !important;
2802
+ min-width: 80px !important;
2803
+ }
2804
+
2805
+ body.ai-chat-printing #ai-cortex-print-section .ai-stat-value {
2806
+ font-size: 17px !important;
2807
+ line-height: 1.2 !important;
2808
+ }
2809
+
2810
+ body.ai-chat-printing #ai-cortex-print-section .ai-stat-label {
2811
+ font-size: 9px !important;
2812
+ }
2765
2813
  }
2766
2814
 
2767
2815
  /* ── Responsive ── */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orchid-ai",
3
- "version": "2.1.5",
3
+ "version": "2.2.0",
4
4
  "description": "Shared Orchid AI chat UI and visualization components",
5
5
  "main": "src/index.js",
6
6
  "types": "src/index.d.ts",
@@ -1,11 +1,58 @@
1
1
  import React from "react";
2
2
 
3
+ function csvEscape(value) {
4
+ const s = (value ?? "").toString();
5
+ return /[",\n\r]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
6
+ }
7
+
8
+ function buildCsv(columns, rows) {
9
+ const header = columns.map((c) => csvEscape(c.label)).join(",");
10
+ const body = rows.map((row) => columns.map((c) => csvEscape(row[c.key])).join(",")).join("\r\n");
11
+ return `${header}\r\n${body}`;
12
+ }
13
+
14
+ function downloadCsv(filename, csv) {
15
+ // Prepend a BOM so Excel reads UTF-8 correctly.
16
+ const blob = new Blob([`${csv}`], { type: "text/csv;charset=utf-8;" });
17
+ const url = URL.createObjectURL(blob);
18
+ const a = document.createElement("a");
19
+ a.href = url;
20
+ a.download = filename;
21
+ document.body.appendChild(a);
22
+ a.click();
23
+ document.body.removeChild(a);
24
+ setTimeout(() => URL.revokeObjectURL(url), 0);
25
+ }
26
+
27
+ function safeFilename(title) {
28
+ const base = (title || "table").replace(/[\\/:*?"<>|]+/g, "").trim().slice(0, 80);
29
+ return `${base || "table"}.csv`;
30
+ }
31
+
3
32
  export default function DataTable({ chart }) {
4
33
  const { title, columns, rows } = chart;
5
34
 
35
+ const handleDownload = () => downloadCsv(safeFilename(title), buildCsv(columns, rows));
36
+
6
37
  return (
7
38
  <div className="ai-chart-card">
8
- {title ? <h4 className="ai-chart-title">{title}</h4> : null}
39
+ <div className="ai-chart-card-header">
40
+ {title ? <h4 className="ai-chart-title">{title}</h4> : <span />}
41
+ <button
42
+ type="button"
43
+ className="ai-chart-csv-btn"
44
+ onClick={handleDownload}
45
+ title="Download as CSV"
46
+ aria-label="Download table as CSV"
47
+ >
48
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
49
+ <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
50
+ <polyline points="7 10 12 15 17 10" />
51
+ <line x1="12" y1="15" x2="12" y2="3" />
52
+ </svg>
53
+ CSV
54
+ </button>
55
+ </div>
9
56
  <div className="ai-data-table-wrap">
10
57
  <table className="ai-data-table">
11
58
  <thead>