bolt-table 0.1.36 → 0.1.37
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.d.mts +84 -2
- package/dist/index.d.ts +84 -2
- package/dist/index.js +840 -138
- package/dist/index.mjs +838 -137
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -102,6 +102,18 @@ var XIcon = ({ style, className }) => /* @__PURE__ */ jsxs("svg", { ...svgBase,
|
|
|
102
102
|
/* @__PURE__ */ jsx("path", { d: "M18 6 6 18" }),
|
|
103
103
|
/* @__PURE__ */ jsx("path", { d: "m6 6 12 12" })
|
|
104
104
|
] });
|
|
105
|
+
var SparklesIcon = ({ style, className }) => /* @__PURE__ */ jsxs("svg", { ...svgBase, style, className, children: [
|
|
106
|
+
/* @__PURE__ */ jsx("path", { d: "m12 3-1.912 5.813a2 2 0 0 1-1.275 1.275L3 12l5.813 1.912a2 2 0 0 1 1.275 1.275L12 21l1.912-5.813a2 2 0 0 1 1.275-1.275L21 12l-5.813-1.912a2 2 0 0 1-1.275-1.275L12 3Z" }),
|
|
107
|
+
/* @__PURE__ */ jsx("path", { d: "M5 3v4" }),
|
|
108
|
+
/* @__PURE__ */ jsx("path", { d: "M19 17v4" }),
|
|
109
|
+
/* @__PURE__ */ jsx("path", { d: "M3 5h4" }),
|
|
110
|
+
/* @__PURE__ */ jsx("path", { d: "M17 19h4" })
|
|
111
|
+
] });
|
|
112
|
+
var SendIcon = ({ style, className }) => /* @__PURE__ */ jsxs("svg", { ...svgBase, style, className, children: [
|
|
113
|
+
/* @__PURE__ */ jsx("path", { d: "m22 2-7 20-4-9-9-4Z" }),
|
|
114
|
+
/* @__PURE__ */ jsx("path", { d: "M22 2 11 13" })
|
|
115
|
+
] });
|
|
116
|
+
var LoaderIcon = ({ style, className }) => /* @__PURE__ */ jsx("svg", { ...svgBase, style, className, children: /* @__PURE__ */ jsx("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }) });
|
|
105
117
|
|
|
106
118
|
// src/DraggableHeader.tsx
|
|
107
119
|
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
@@ -643,6 +655,280 @@ var DraggableHeader = React.memo(
|
|
|
643
655
|
DraggableHeader.displayName = "DraggableHeader";
|
|
644
656
|
var DraggableHeader_default = DraggableHeader;
|
|
645
657
|
|
|
658
|
+
// src/ai.ts
|
|
659
|
+
function detectColumnType(key, data) {
|
|
660
|
+
const values = [];
|
|
661
|
+
for (let i = 0; i < Math.min(data.length, 20); i++) {
|
|
662
|
+
const v = data[i]?.[key];
|
|
663
|
+
if (v != null) values.push(v);
|
|
664
|
+
}
|
|
665
|
+
if (values.length === 0) return { type: "unknown", sample: "" };
|
|
666
|
+
const allNumbers = values.every((v) => typeof v === "number");
|
|
667
|
+
const allBooleans = values.every((v) => typeof v === "boolean");
|
|
668
|
+
const uniqueVals = [...new Set(values.map(String))];
|
|
669
|
+
const sampleStr = uniqueVals.length <= 8 ? uniqueVals.join(", ") : uniqueVals.slice(0, 6).join(", ") + "...";
|
|
670
|
+
if (allBooleans) return { type: "boolean", sample: sampleStr };
|
|
671
|
+
if (allNumbers) {
|
|
672
|
+
const nums = values;
|
|
673
|
+
const min = Math.min(...nums);
|
|
674
|
+
const max = Math.max(...nums);
|
|
675
|
+
return { type: "number", sample: `range ${min}\u2013${max}` };
|
|
676
|
+
}
|
|
677
|
+
return { type: "string", sample: sampleStr };
|
|
678
|
+
}
|
|
679
|
+
function buildSystemPrompt(columns, data) {
|
|
680
|
+
const schemaLines = columns.filter((c) => c.key !== "__select__" && c.key !== "__expand__").map((c) => {
|
|
681
|
+
const key = c.dataIndex ?? c.key;
|
|
682
|
+
const title = typeof c.title === "string" ? c.title : c.key;
|
|
683
|
+
const info = detectColumnType(key, data);
|
|
684
|
+
return ` - key: "${c.key}", title: "${title}", dataIndex: "${key}", type: ${info.type}${info.sample ? ` (values: ${info.sample})` : ""}`;
|
|
685
|
+
}).join("\n");
|
|
686
|
+
const sample = data.slice(0, 5).map((row) => {
|
|
687
|
+
const obj = {};
|
|
688
|
+
for (const col of columns) {
|
|
689
|
+
if (col.key === "__select__" || col.key === "__expand__") continue;
|
|
690
|
+
const di = col.dataIndex ?? col.key;
|
|
691
|
+
obj[di] = row[di];
|
|
692
|
+
}
|
|
693
|
+
return obj;
|
|
694
|
+
});
|
|
695
|
+
return `You are a data table assistant. You help users query, filter, sort, and style tabular data.
|
|
696
|
+
You MUST respond with ONLY a valid JSON object \u2014 no markdown fences, no explanation, no extra text.
|
|
697
|
+
|
|
698
|
+
## Table Schema
|
|
699
|
+
${schemaLines}
|
|
700
|
+
|
|
701
|
+
## Sample Data (first ${sample.length} of ${data.length} rows)
|
|
702
|
+
${JSON.stringify(sample, null, 2)}
|
|
703
|
+
|
|
704
|
+
## Available Operations
|
|
705
|
+
Combine any of these in a single response:
|
|
706
|
+
|
|
707
|
+
1. **filter** \u2014 show only rows matching conditions
|
|
708
|
+
{ "type": "filter", "conditions": [{ "column": "<dataIndex>", "op": "<op>", "value": <val> }], "logic": "and" | "or" }
|
|
709
|
+
|
|
710
|
+
2. **rowStyle** \u2014 apply CSS styles to entire rows matching conditions
|
|
711
|
+
{ "type": "rowStyle", "conditions": [...], "logic": "and"|"or", "style": { "<cssProp>": "<value>" } }
|
|
712
|
+
|
|
713
|
+
3. **cellStyle** \u2014 apply CSS styles to a specific column's cells matching conditions
|
|
714
|
+
{ "type": "cellStyle", "column": "<dataIndex>", "conditions": [...], "logic": "and"|"or", "style": { "<cssProp>": "<value>" } }
|
|
715
|
+
|
|
716
|
+
4. **sort** \u2014 sort data by a column
|
|
717
|
+
{ "type": "sort", "column": "<dataIndex>", "direction": "asc" | "desc" }
|
|
718
|
+
|
|
719
|
+
5. **hideColumns** / **showColumns** \u2014 toggle column visibility
|
|
720
|
+
{ "type": "hideColumns" | "showColumns", "columns": ["<key>", ...] }
|
|
721
|
+
|
|
722
|
+
## Operators
|
|
723
|
+
eq, neq, gt, gte, lt, lte, contains, notContains, startsWith, endsWith, in, notIn
|
|
724
|
+
|
|
725
|
+
## Response format
|
|
726
|
+
{
|
|
727
|
+
"operations": [ ... ],
|
|
728
|
+
"message": "Brief user-friendly description of what was applied"
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
## Rules
|
|
732
|
+
- Use the dataIndex values from the schema, not display titles.
|
|
733
|
+
- For colors use semi-transparent values like "rgba(255,0,0,0.15)" so text stays readable.
|
|
734
|
+
- CSS property names must be camelCase (e.g. "backgroundColor", "color", "fontWeight").
|
|
735
|
+
- If the user asks to highlight / color / mark specific rows, use rowStyle or cellStyle.
|
|
736
|
+
- If the user asks to show only certain rows, use filter.
|
|
737
|
+
- You can combine filter + rowStyle + sort etc. in one response.
|
|
738
|
+
- The "message" should be concise: what was done, in plain English.`;
|
|
739
|
+
}
|
|
740
|
+
async function callAI(config, systemPrompt, userQuery) {
|
|
741
|
+
const { provider, apiKey, model, baseUrl, maxTokens = 1024, temperature = 0.1 } = config;
|
|
742
|
+
if (provider === "openai" || provider === "custom") {
|
|
743
|
+
const url = baseUrl ? `${baseUrl.replace(/\/$/, "")}/chat/completions` : "https://api.openai.com/v1/chat/completions";
|
|
744
|
+
const res = await fetch(url, {
|
|
745
|
+
method: "POST",
|
|
746
|
+
headers: {
|
|
747
|
+
"Content-Type": "application/json",
|
|
748
|
+
Authorization: `Bearer ${apiKey}`
|
|
749
|
+
},
|
|
750
|
+
body: JSON.stringify({
|
|
751
|
+
model: model ?? "gpt-4o-mini",
|
|
752
|
+
messages: [
|
|
753
|
+
{ role: "system", content: systemPrompt },
|
|
754
|
+
{ role: "user", content: userQuery }
|
|
755
|
+
],
|
|
756
|
+
max_tokens: maxTokens,
|
|
757
|
+
temperature
|
|
758
|
+
})
|
|
759
|
+
});
|
|
760
|
+
if (!res.ok) {
|
|
761
|
+
const body = await res.text().catch(() => "");
|
|
762
|
+
throw new Error(`AI request failed (${res.status}): ${body}`);
|
|
763
|
+
}
|
|
764
|
+
const json = await res.json();
|
|
765
|
+
return json.choices?.[0]?.message?.content ?? "";
|
|
766
|
+
}
|
|
767
|
+
if (provider === "anthropic") {
|
|
768
|
+
const url = baseUrl ? `${baseUrl.replace(/\/$/, "")}/messages` : "https://api.anthropic.com/v1/messages";
|
|
769
|
+
const res = await fetch(url, {
|
|
770
|
+
method: "POST",
|
|
771
|
+
headers: {
|
|
772
|
+
"Content-Type": "application/json",
|
|
773
|
+
"x-api-key": apiKey,
|
|
774
|
+
"anthropic-version": "2023-06-01",
|
|
775
|
+
"anthropic-dangerous-direct-browser-access": "true"
|
|
776
|
+
},
|
|
777
|
+
body: JSON.stringify({
|
|
778
|
+
model: model ?? "claude-sonnet-4-20250514",
|
|
779
|
+
system: systemPrompt,
|
|
780
|
+
messages: [{ role: "user", content: userQuery }],
|
|
781
|
+
max_tokens: maxTokens,
|
|
782
|
+
temperature
|
|
783
|
+
})
|
|
784
|
+
});
|
|
785
|
+
if (!res.ok) {
|
|
786
|
+
const body = await res.text().catch(() => "");
|
|
787
|
+
throw new Error(`AI request failed (${res.status}): ${body}`);
|
|
788
|
+
}
|
|
789
|
+
const json = await res.json();
|
|
790
|
+
const textBlock = json.content?.find(
|
|
791
|
+
(b) => b.type === "text"
|
|
792
|
+
);
|
|
793
|
+
return textBlock?.text ?? "";
|
|
794
|
+
}
|
|
795
|
+
throw new Error(`Unsupported AI provider: ${provider}`);
|
|
796
|
+
}
|
|
797
|
+
function parseAIResponse(raw) {
|
|
798
|
+
let text = raw.trim();
|
|
799
|
+
const fenceMatch = text.match(/```(?:json)?\s*([\s\S]*?)```/);
|
|
800
|
+
if (fenceMatch) text = fenceMatch[1].trim();
|
|
801
|
+
const start = text.indexOf("{");
|
|
802
|
+
const end = text.lastIndexOf("}");
|
|
803
|
+
if (start !== -1 && end > start) {
|
|
804
|
+
text = text.slice(start, end + 1);
|
|
805
|
+
}
|
|
806
|
+
const parsed = JSON.parse(text);
|
|
807
|
+
if (!parsed.operations || !Array.isArray(parsed.operations)) {
|
|
808
|
+
throw new Error("Invalid AI response: missing operations array");
|
|
809
|
+
}
|
|
810
|
+
return {
|
|
811
|
+
operations: parsed.operations,
|
|
812
|
+
message: parsed.message ?? "AI operations applied."
|
|
813
|
+
};
|
|
814
|
+
}
|
|
815
|
+
function evaluateCondition(condition, row) {
|
|
816
|
+
const rawVal = row[condition.column];
|
|
817
|
+
const target = condition.value;
|
|
818
|
+
switch (condition.op) {
|
|
819
|
+
case "eq":
|
|
820
|
+
return rawVal == target;
|
|
821
|
+
case "neq":
|
|
822
|
+
return rawVal != target;
|
|
823
|
+
case "gt":
|
|
824
|
+
return Number(rawVal) > Number(target);
|
|
825
|
+
case "gte":
|
|
826
|
+
return Number(rawVal) >= Number(target);
|
|
827
|
+
case "lt":
|
|
828
|
+
return Number(rawVal) < Number(target);
|
|
829
|
+
case "lte":
|
|
830
|
+
return Number(rawVal) <= Number(target);
|
|
831
|
+
case "contains":
|
|
832
|
+
return String(rawVal ?? "").toLowerCase().includes(String(target).toLowerCase());
|
|
833
|
+
case "notContains":
|
|
834
|
+
return !String(rawVal ?? "").toLowerCase().includes(String(target).toLowerCase());
|
|
835
|
+
case "startsWith":
|
|
836
|
+
return String(rawVal ?? "").toLowerCase().startsWith(String(target).toLowerCase());
|
|
837
|
+
case "endsWith":
|
|
838
|
+
return String(rawVal ?? "").toLowerCase().endsWith(String(target).toLowerCase());
|
|
839
|
+
case "in":
|
|
840
|
+
if (Array.isArray(target)) {
|
|
841
|
+
return target.some((t) => rawVal == t);
|
|
842
|
+
}
|
|
843
|
+
return false;
|
|
844
|
+
case "notIn":
|
|
845
|
+
if (Array.isArray(target)) {
|
|
846
|
+
return !target.some((t) => rawVal == t);
|
|
847
|
+
}
|
|
848
|
+
return true;
|
|
849
|
+
default:
|
|
850
|
+
return true;
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
function matchesConditions(conditions, logic, row) {
|
|
854
|
+
if (!conditions || conditions.length === 0) return true;
|
|
855
|
+
if (logic === "or") {
|
|
856
|
+
return conditions.some((c) => evaluateCondition(c, row));
|
|
857
|
+
}
|
|
858
|
+
return conditions.every((c) => evaluateCondition(c, row));
|
|
859
|
+
}
|
|
860
|
+
function applyAIFilter(data, op) {
|
|
861
|
+
return data.filter((row) => matchesConditions(op.conditions, op.logic, row));
|
|
862
|
+
}
|
|
863
|
+
function applyAISort(data, op) {
|
|
864
|
+
const dir = op.direction === "asc" ? 1 : -1;
|
|
865
|
+
const col = op.column;
|
|
866
|
+
return [...data].sort((a, b) => {
|
|
867
|
+
const aVal = a[col];
|
|
868
|
+
const bVal = b[col];
|
|
869
|
+
if (aVal == null && bVal == null) return 0;
|
|
870
|
+
if (aVal == null) return 1;
|
|
871
|
+
if (bVal == null) return -1;
|
|
872
|
+
if (typeof aVal === "number" && typeof bVal === "number")
|
|
873
|
+
return (aVal - bVal) * dir;
|
|
874
|
+
return String(aVal).localeCompare(String(bVal)) * dir;
|
|
875
|
+
});
|
|
876
|
+
}
|
|
877
|
+
function getAIRowStyle(row, ops) {
|
|
878
|
+
let merged;
|
|
879
|
+
for (const op of ops) {
|
|
880
|
+
if (matchesConditions(op.conditions, op.logic, row)) {
|
|
881
|
+
if (!merged) merged = {};
|
|
882
|
+
Object.assign(merged, op.style);
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
return merged;
|
|
886
|
+
}
|
|
887
|
+
function getAICellStyle(row, columnKey, ops) {
|
|
888
|
+
let merged;
|
|
889
|
+
for (const op of ops) {
|
|
890
|
+
if (op.column === columnKey && matchesConditions(op.conditions, op.logic, row)) {
|
|
891
|
+
if (!merged) merged = {};
|
|
892
|
+
Object.assign(merged, op.style);
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
return merged;
|
|
896
|
+
}
|
|
897
|
+
function applyAIOperations(data, operations) {
|
|
898
|
+
let filteredData = data;
|
|
899
|
+
let sortOp = null;
|
|
900
|
+
const styleOps = [];
|
|
901
|
+
const cellStyleOps = [];
|
|
902
|
+
const hideColumns = [];
|
|
903
|
+
const showColumns = [];
|
|
904
|
+
for (const op of operations) {
|
|
905
|
+
switch (op.type) {
|
|
906
|
+
case "filter":
|
|
907
|
+
filteredData = applyAIFilter(filteredData, op);
|
|
908
|
+
break;
|
|
909
|
+
case "sort":
|
|
910
|
+
sortOp = op;
|
|
911
|
+
break;
|
|
912
|
+
case "rowStyle":
|
|
913
|
+
styleOps.push(op);
|
|
914
|
+
break;
|
|
915
|
+
case "cellStyle":
|
|
916
|
+
cellStyleOps.push(op);
|
|
917
|
+
break;
|
|
918
|
+
case "hideColumns":
|
|
919
|
+
hideColumns.push(...op.columns);
|
|
920
|
+
break;
|
|
921
|
+
case "showColumns":
|
|
922
|
+
showColumns.push(...op.columns);
|
|
923
|
+
break;
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
if (sortOp) {
|
|
927
|
+
filteredData = applyAISort(filteredData, sortOp);
|
|
928
|
+
}
|
|
929
|
+
return { filteredData, sortOp, styleOps, cellStyleOps, hideColumns, showColumns };
|
|
930
|
+
}
|
|
931
|
+
|
|
646
932
|
// src/ResizeOverlay.tsx
|
|
647
933
|
import { forwardRef, useImperativeHandle, useRef as useRef2 } from "react";
|
|
648
934
|
import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
@@ -870,9 +1156,11 @@ var Cell = React3.memo(
|
|
|
870
1156
|
isLoading,
|
|
871
1157
|
onEdit,
|
|
872
1158
|
isEditing,
|
|
873
|
-
onEditComplete
|
|
1159
|
+
onEditComplete,
|
|
1160
|
+
cellStyleFn
|
|
874
1161
|
}) => {
|
|
875
1162
|
const isPinned = Boolean(column.pinned);
|
|
1163
|
+
const extraCellStyle = cellStyleFn?.(record, column.dataIndex ?? column.key);
|
|
876
1164
|
if (isLoading && column.key !== "__select__" && column.key !== "__expand__") {
|
|
877
1165
|
const shimmerContent = column.shimmerRender ? column.shimmerRender() : /* @__PURE__ */ jsx4(
|
|
878
1166
|
"div",
|
|
@@ -1024,7 +1312,8 @@ var Cell = React3.memo(
|
|
|
1024
1312
|
minWidth: 0,
|
|
1025
1313
|
...column.style,
|
|
1026
1314
|
...isPinned ? styles?.pinnedCell : void 0,
|
|
1027
|
-
...styles?.cell
|
|
1315
|
+
...styles?.cell,
|
|
1316
|
+
...extraCellStyle
|
|
1028
1317
|
},
|
|
1029
1318
|
children: isSystem ? content : showEditor ? content : /* @__PURE__ */ jsx4(
|
|
1030
1319
|
"div",
|
|
@@ -1051,6 +1340,7 @@ var Cell = React3.memo(
|
|
|
1051
1340
|
if (prev.onEdit !== next.onEdit) return false;
|
|
1052
1341
|
if (prev.isEditing !== next.isEditing) return false;
|
|
1053
1342
|
if (prev.onEditComplete !== next.onEditComplete) return false;
|
|
1343
|
+
if (prev.cellStyleFn !== next.cellStyleFn) return false;
|
|
1054
1344
|
if (prev.column.key === "__select__") {
|
|
1055
1345
|
return prev.isSelected === next.isSelected && prev.normalizedSelectedKeys === next.normalizedSelectedKeys;
|
|
1056
1346
|
}
|
|
@@ -1152,7 +1442,8 @@ var TableBody = ({
|
|
|
1152
1442
|
onEditComplete,
|
|
1153
1443
|
enableDynamicRowHeight = false,
|
|
1154
1444
|
onRowHeightChange,
|
|
1155
|
-
columnGridIndexMap
|
|
1445
|
+
columnGridIndexMap,
|
|
1446
|
+
cellStyleFn
|
|
1156
1447
|
}) => {
|
|
1157
1448
|
const virtualItems = rowVirtualizer.getVirtualItems();
|
|
1158
1449
|
const totalSize = rowVirtualizer.getTotalSize();
|
|
@@ -1281,7 +1572,8 @@ var TableBody = ({
|
|
|
1281
1572
|
recordFingerprint,
|
|
1282
1573
|
onEdit,
|
|
1283
1574
|
isEditing: editingCell?.rowKey === rowKey && editingCell?.columnKey === col.key,
|
|
1284
|
-
onEditComplete
|
|
1575
|
+
onEditComplete,
|
|
1576
|
+
cellStyleFn
|
|
1285
1577
|
}
|
|
1286
1578
|
)
|
|
1287
1579
|
}
|
|
@@ -1318,7 +1610,8 @@ var TableBody = ({
|
|
|
1318
1610
|
recordFingerprint,
|
|
1319
1611
|
onEdit,
|
|
1320
1612
|
isEditing: editingCell?.rowKey === rowKey && editingCell?.columnKey === col.key,
|
|
1321
|
-
onEditComplete
|
|
1613
|
+
onEditComplete,
|
|
1614
|
+
cellStyleFn
|
|
1322
1615
|
}
|
|
1323
1616
|
)
|
|
1324
1617
|
}
|
|
@@ -1508,7 +1801,8 @@ var TableBody = ({
|
|
|
1508
1801
|
recordFingerprint,
|
|
1509
1802
|
onEdit,
|
|
1510
1803
|
isEditing: editingCell?.rowKey === rk && editingCell?.columnKey === col.key,
|
|
1511
|
-
onEditComplete
|
|
1804
|
+
onEditComplete,
|
|
1805
|
+
cellStyleFn
|
|
1512
1806
|
}
|
|
1513
1807
|
)
|
|
1514
1808
|
}
|
|
@@ -1636,7 +1930,8 @@ var TableBody = ({
|
|
|
1636
1930
|
recordFingerprint,
|
|
1637
1931
|
onEdit,
|
|
1638
1932
|
isEditing: editingCell?.rowKey === rk && editingCell?.columnKey === col.key,
|
|
1639
|
-
onEditComplete
|
|
1933
|
+
onEditComplete,
|
|
1934
|
+
cellStyleFn
|
|
1640
1935
|
}
|
|
1641
1936
|
)
|
|
1642
1937
|
}
|
|
@@ -1731,7 +2026,13 @@ function BoltTable({
|
|
|
1731
2026
|
globalSearchValue,
|
|
1732
2027
|
onGlobalSearchChange,
|
|
1733
2028
|
toolbarContent,
|
|
1734
|
-
columnSettingsLabel
|
|
2029
|
+
columnSettingsLabel,
|
|
2030
|
+
aiMode = false,
|
|
2031
|
+
aiConfig,
|
|
2032
|
+
onAIQuery,
|
|
2033
|
+
onAIResponse,
|
|
2034
|
+
aiPlaceholder = "Ask AI anything about your data...",
|
|
2035
|
+
aiButtonLabel
|
|
1735
2036
|
}) {
|
|
1736
2037
|
const data = useMemo2(() => {
|
|
1737
2038
|
if (!Array.isArray(rawData)) return STABLE_EMPTY_DATA;
|
|
@@ -1905,6 +2206,96 @@ function BoltTable({
|
|
|
1905
2206
|
document.removeEventListener("keydown", onKey);
|
|
1906
2207
|
};
|
|
1907
2208
|
}, [showColumnPicker]);
|
|
2209
|
+
const [aiBarOpen, setAiBarOpen] = useState3(false);
|
|
2210
|
+
const [aiQuery, setAiQuery] = useState3("");
|
|
2211
|
+
const [aiLoading, setAiLoading] = useState3(false);
|
|
2212
|
+
const [aiResult, setAiResult] = useState3(null);
|
|
2213
|
+
const [aiError, setAiError] = useState3(null);
|
|
2214
|
+
const aiInputRef = useRef4(null);
|
|
2215
|
+
const [aiStyleOps, setAiStyleOps] = useState3([]);
|
|
2216
|
+
const [aiCellStyleOps, setAiCellStyleOps] = useState3(
|
|
2217
|
+
[]
|
|
2218
|
+
);
|
|
2219
|
+
const [aiFilteredDataKeys, setAiFilteredDataKeys] = useState3(null);
|
|
2220
|
+
const [aiSortKey, setAiSortKey] = useState3(null);
|
|
2221
|
+
const [aiSortDir, setAiSortDir] = useState3(null);
|
|
2222
|
+
const onAIResponseRef = useRef4(onAIResponse);
|
|
2223
|
+
onAIResponseRef.current = onAIResponse;
|
|
2224
|
+
const handleAISubmit = useCallback2(async () => {
|
|
2225
|
+
const query = aiQuery.trim();
|
|
2226
|
+
if (!query) return;
|
|
2227
|
+
setAiLoading(true);
|
|
2228
|
+
setAiError(null);
|
|
2229
|
+
try {
|
|
2230
|
+
let response;
|
|
2231
|
+
if (onAIQuery) {
|
|
2232
|
+
response = await onAIQuery(query, {
|
|
2233
|
+
data,
|
|
2234
|
+
columns: initialColumns
|
|
2235
|
+
});
|
|
2236
|
+
} else if (aiConfig) {
|
|
2237
|
+
const sysPrompt = buildSystemPrompt(initialColumns, data);
|
|
2238
|
+
const raw = await callAI(aiConfig, sysPrompt, query);
|
|
2239
|
+
response = parseAIResponse(raw);
|
|
2240
|
+
} else {
|
|
2241
|
+
throw new Error("AI mode requires either aiConfig or onAIQuery prop");
|
|
2242
|
+
}
|
|
2243
|
+
const { filteredData, sortOp, styleOps: sOps, cellStyleOps: csOps, hideColumns, showColumns } = applyAIOperations(data, response.operations);
|
|
2244
|
+
setAiStyleOps(sOps);
|
|
2245
|
+
setAiCellStyleOps(csOps);
|
|
2246
|
+
if (response.operations.some((op) => op.type === "filter")) {
|
|
2247
|
+
const keySet = /* @__PURE__ */ new Set();
|
|
2248
|
+
filteredData.forEach((row, idx) => {
|
|
2249
|
+
const k = typeof rowKey === "function" ? rowKey(row) : String(row[typeof rowKey === "string" ? rowKey : "id"] ?? idx);
|
|
2250
|
+
keySet.add(k);
|
|
2251
|
+
});
|
|
2252
|
+
setAiFilteredDataKeys(keySet);
|
|
2253
|
+
} else {
|
|
2254
|
+
setAiFilteredDataKeys(null);
|
|
2255
|
+
}
|
|
2256
|
+
if (sortOp) {
|
|
2257
|
+
setAiSortKey(sortOp.column);
|
|
2258
|
+
setAiSortDir(sortOp.direction);
|
|
2259
|
+
} else {
|
|
2260
|
+
setAiSortKey(null);
|
|
2261
|
+
setAiSortDir(null);
|
|
2262
|
+
}
|
|
2263
|
+
if (hideColumns.length > 0 || showColumns.length > 0) {
|
|
2264
|
+
setColumns(
|
|
2265
|
+
(prev) => prev.map((col) => {
|
|
2266
|
+
if (hideColumns.includes(col.key)) return { ...col, hidden: true };
|
|
2267
|
+
if (showColumns.includes(col.key)) return { ...col, hidden: false };
|
|
2268
|
+
return col;
|
|
2269
|
+
})
|
|
2270
|
+
);
|
|
2271
|
+
}
|
|
2272
|
+
setAiResult(response);
|
|
2273
|
+
onAIResponseRef.current?.(response);
|
|
2274
|
+
} catch (err) {
|
|
2275
|
+
setAiError(err instanceof Error ? err.message : "AI query failed");
|
|
2276
|
+
} finally {
|
|
2277
|
+
setAiLoading(false);
|
|
2278
|
+
}
|
|
2279
|
+
}, [aiQuery, aiConfig, onAIQuery, data, initialColumns, rowKey]);
|
|
2280
|
+
const handleAIClear = useCallback2(() => {
|
|
2281
|
+
setAiResult(null);
|
|
2282
|
+
setAiError(null);
|
|
2283
|
+
setAiStyleOps([]);
|
|
2284
|
+
setAiCellStyleOps([]);
|
|
2285
|
+
setAiFilteredDataKeys(null);
|
|
2286
|
+
setAiSortKey(null);
|
|
2287
|
+
setAiSortDir(null);
|
|
2288
|
+
setAiQuery("");
|
|
2289
|
+
}, []);
|
|
2290
|
+
const handleAIBarClose = useCallback2(() => {
|
|
2291
|
+
setAiBarOpen(false);
|
|
2292
|
+
handleAIClear();
|
|
2293
|
+
}, [handleAIClear]);
|
|
2294
|
+
React4.useEffect(() => {
|
|
2295
|
+
if (aiBarOpen && aiInputRef.current) {
|
|
2296
|
+
setTimeout(() => aiInputRef.current?.focus(), 300);
|
|
2297
|
+
}
|
|
2298
|
+
}, [aiBarOpen]);
|
|
1908
2299
|
const columnsWithPersistedWidths = useMemo2(
|
|
1909
2300
|
() => columns.map((col) => ({
|
|
1910
2301
|
...col,
|
|
@@ -2546,6 +2937,47 @@ function BoltTable({
|
|
|
2546
2937
|
}
|
|
2547
2938
|
return result;
|
|
2548
2939
|
}, [data, sortState, columnFilters, globalSearchValue, internalGlobalSearch]);
|
|
2940
|
+
const aiProcessedData = useMemo2(() => {
|
|
2941
|
+
let result = processedData;
|
|
2942
|
+
if (aiFilteredDataKeys) {
|
|
2943
|
+
result = result.filter((row, idx) => {
|
|
2944
|
+
if (row == null) return false;
|
|
2945
|
+
const k = typeof rowKey === "function" ? rowKey(row) : String(
|
|
2946
|
+
row[typeof rowKey === "string" ? rowKey : "id"] ?? idx
|
|
2947
|
+
);
|
|
2948
|
+
return aiFilteredDataKeys.has(k);
|
|
2949
|
+
});
|
|
2950
|
+
}
|
|
2951
|
+
if (aiSortKey && aiSortDir) {
|
|
2952
|
+
const dir = aiSortDir === "asc" ? 1 : -1;
|
|
2953
|
+
const col = aiSortKey;
|
|
2954
|
+
result = [...result].sort((a, b) => {
|
|
2955
|
+
const aVal = a[col];
|
|
2956
|
+
const bVal = b[col];
|
|
2957
|
+
if (aVal == null && bVal == null) return 0;
|
|
2958
|
+
if (aVal == null) return 1;
|
|
2959
|
+
if (bVal == null) return -1;
|
|
2960
|
+
if (typeof aVal === "number" && typeof bVal === "number")
|
|
2961
|
+
return (aVal - bVal) * dir;
|
|
2962
|
+
return String(aVal).localeCompare(String(bVal)) * dir;
|
|
2963
|
+
});
|
|
2964
|
+
}
|
|
2965
|
+
return result;
|
|
2966
|
+
}, [processedData, aiFilteredDataKeys, aiSortKey, aiSortDir, rowKey]);
|
|
2967
|
+
const getAIRowStyleForRecord = useCallback2(
|
|
2968
|
+
(record) => {
|
|
2969
|
+
if (aiStyleOps.length === 0) return void 0;
|
|
2970
|
+
return getAIRowStyle(record, aiStyleOps);
|
|
2971
|
+
},
|
|
2972
|
+
[aiStyleOps]
|
|
2973
|
+
);
|
|
2974
|
+
const getAICellStyleForRecord = useCallback2(
|
|
2975
|
+
(record, columnKey) => {
|
|
2976
|
+
if (aiCellStyleOps.length === 0) return void 0;
|
|
2977
|
+
return getAICellStyle(record, columnKey, aiCellStyleOps);
|
|
2978
|
+
},
|
|
2979
|
+
[aiCellStyleOps]
|
|
2980
|
+
);
|
|
2549
2981
|
const pinnedRowCacheRef = useRef4(/* @__PURE__ */ new Map());
|
|
2550
2982
|
const { pinnedTopRows, pinnedBottomRows, unpinnedProcessedData } = useMemo2(() => {
|
|
2551
2983
|
if (!resolvedRowPinning || !resolvedRowPinning.top?.length && !resolvedRowPinning.bottom?.length) {
|
|
@@ -2553,7 +2985,7 @@ function BoltTable({
|
|
|
2553
2985
|
return {
|
|
2554
2986
|
pinnedTopRows: [],
|
|
2555
2987
|
pinnedBottomRows: [],
|
|
2556
|
-
unpinnedProcessedData:
|
|
2988
|
+
unpinnedProcessedData: aiProcessedData
|
|
2557
2989
|
};
|
|
2558
2990
|
}
|
|
2559
2991
|
const topKeySet = new Set((resolvedRowPinning.top ?? []).map(String));
|
|
@@ -2563,7 +2995,7 @@ function BoltTable({
|
|
|
2563
2995
|
const topMap = /* @__PURE__ */ new Map();
|
|
2564
2996
|
const bottomMap = /* @__PURE__ */ new Map();
|
|
2565
2997
|
const rest = [];
|
|
2566
|
-
|
|
2998
|
+
aiProcessedData.forEach((row, idx) => {
|
|
2567
2999
|
if (row == null) return;
|
|
2568
3000
|
const key = getSafeRowKey(row, idx);
|
|
2569
3001
|
if (topKeySet.has(key)) {
|
|
@@ -2603,7 +3035,7 @@ function BoltTable({
|
|
|
2603
3035
|
unpinnedProcessedData: rest
|
|
2604
3036
|
};
|
|
2605
3037
|
}, [
|
|
2606
|
-
|
|
3038
|
+
aiProcessedData,
|
|
2607
3039
|
resolvedRowPinning,
|
|
2608
3040
|
getSafeRowKey,
|
|
2609
3041
|
keepPinnedRowsAcrossPages
|
|
@@ -2672,7 +3104,7 @@ function BoltTable({
|
|
|
2672
3104
|
return unpinnedProcessedData.slice(start, start + pgSize);
|
|
2673
3105
|
}, [unpinnedProcessedData, needsClientPagination, pgCurrent, pgSize]);
|
|
2674
3106
|
const shimmerCount = pgEnabled ? pgSize : 15;
|
|
2675
|
-
const showShimmer = isLoading &&
|
|
3107
|
+
const showShimmer = isLoading && aiProcessedData.length === 0;
|
|
2676
3108
|
const shimmerRowKeyField = typeof rowKey === "string" ? rowKey : "id";
|
|
2677
3109
|
const shimmerData = useMemo2(() => {
|
|
2678
3110
|
if (!showShimmer) return null;
|
|
@@ -2956,49 +3388,291 @@ function BoltTable({
|
|
|
2956
3388
|
border: 1px dashed ${accentColor} !important;
|
|
2957
3389
|
}
|
|
2958
3390
|
${onRowClick ? "[data-bt-cell] { cursor: pointer; }" : ""}
|
|
3391
|
+
@keyframes bt-spin { to { transform: rotate(360deg); } }
|
|
3392
|
+
@keyframes bt-ai-shimmer {
|
|
3393
|
+
0% { background-position: -200% 0; }
|
|
3394
|
+
100% { background-position: 200% 0; }
|
|
3395
|
+
}
|
|
2959
3396
|
` }),
|
|
2960
|
-
(!hideGlobalSearch || showColumnSettings) && /* @__PURE__ */ jsxs5(
|
|
3397
|
+
(!hideGlobalSearch || showColumnSettings || aiMode) && /* @__PURE__ */ jsxs5(
|
|
2961
3398
|
"div",
|
|
2962
3399
|
{
|
|
2963
3400
|
style: {
|
|
3401
|
+
position: "relative",
|
|
2964
3402
|
display: "flex",
|
|
2965
3403
|
alignItems: "center",
|
|
2966
3404
|
gap: 8,
|
|
2967
3405
|
padding: "6px 8px",
|
|
2968
3406
|
borderBottom: "1px solid rgba(128,128,128,0.2)",
|
|
2969
3407
|
fontSize: 12,
|
|
2970
|
-
flexShrink: 0
|
|
3408
|
+
flexShrink: 0,
|
|
3409
|
+
overflow: "hidden"
|
|
2971
3410
|
},
|
|
2972
3411
|
children: [
|
|
2973
|
-
|
|
3412
|
+
/* @__PURE__ */ jsxs5(
|
|
2974
3413
|
"div",
|
|
2975
3414
|
{
|
|
2976
3415
|
style: {
|
|
2977
3416
|
display: "flex",
|
|
2978
3417
|
alignItems: "center",
|
|
2979
|
-
gap:
|
|
3418
|
+
gap: 8,
|
|
2980
3419
|
flex: "1 1 0%",
|
|
2981
|
-
|
|
3420
|
+
opacity: aiBarOpen ? 0 : 1,
|
|
3421
|
+
transform: aiBarOpen ? "scale(0.97)" : "scale(1)",
|
|
3422
|
+
transition: "opacity 0.25s ease, transform 0.25s ease",
|
|
3423
|
+
pointerEvents: aiBarOpen ? "none" : "auto",
|
|
3424
|
+
minWidth: 0
|
|
3425
|
+
},
|
|
3426
|
+
children: [
|
|
3427
|
+
!hideGlobalSearch && /* @__PURE__ */ jsxs5(
|
|
3428
|
+
"div",
|
|
3429
|
+
{
|
|
3430
|
+
style: {
|
|
3431
|
+
display: "flex",
|
|
3432
|
+
alignItems: "center",
|
|
3433
|
+
gap: 4,
|
|
3434
|
+
flex: "1 1 0%",
|
|
3435
|
+
position: "relative"
|
|
3436
|
+
},
|
|
3437
|
+
children: [
|
|
3438
|
+
/* @__PURE__ */ jsx5(
|
|
3439
|
+
"span",
|
|
3440
|
+
{
|
|
3441
|
+
style: {
|
|
3442
|
+
display: "flex",
|
|
3443
|
+
color: "GrayText",
|
|
3444
|
+
flexShrink: 0
|
|
3445
|
+
},
|
|
3446
|
+
children: icons?.search ?? /* @__PURE__ */ jsx5(SearchIcon, { style: { width: 14, height: 14 } })
|
|
3447
|
+
}
|
|
3448
|
+
),
|
|
3449
|
+
/* @__PURE__ */ jsx5(
|
|
3450
|
+
"input",
|
|
3451
|
+
{
|
|
3452
|
+
type: "text",
|
|
3453
|
+
placeholder: "Search all columns...",
|
|
3454
|
+
value: globalSearchValue ?? internalGlobalSearch,
|
|
3455
|
+
onChange: (e) => {
|
|
3456
|
+
const v = e.target.value;
|
|
3457
|
+
if (onGlobalSearchChange) onGlobalSearchChange(v);
|
|
3458
|
+
else setInternalGlobalSearch(v);
|
|
3459
|
+
},
|
|
3460
|
+
style: {
|
|
3461
|
+
flex: "1 1 0%",
|
|
3462
|
+
border: "none",
|
|
3463
|
+
outline: "none",
|
|
3464
|
+
background: "transparent",
|
|
3465
|
+
font: "inherit",
|
|
3466
|
+
color: "inherit",
|
|
3467
|
+
padding: "4px 6px",
|
|
3468
|
+
minWidth: 0
|
|
3469
|
+
}
|
|
3470
|
+
}
|
|
3471
|
+
),
|
|
3472
|
+
(globalSearchValue ?? internalGlobalSearch) && /* @__PURE__ */ jsx5(
|
|
3473
|
+
"button",
|
|
3474
|
+
{
|
|
3475
|
+
type: "button",
|
|
3476
|
+
onClick: () => {
|
|
3477
|
+
if (onGlobalSearchChange) onGlobalSearchChange("");
|
|
3478
|
+
else setInternalGlobalSearch("");
|
|
3479
|
+
},
|
|
3480
|
+
style: {
|
|
3481
|
+
display: "flex",
|
|
3482
|
+
alignItems: "center",
|
|
3483
|
+
justifyContent: "center",
|
|
3484
|
+
background: "none",
|
|
3485
|
+
border: "none",
|
|
3486
|
+
cursor: "pointer",
|
|
3487
|
+
padding: 2,
|
|
3488
|
+
color: "GrayText",
|
|
3489
|
+
flexShrink: 0
|
|
3490
|
+
},
|
|
3491
|
+
children: icons?.close ?? /* @__PURE__ */ jsx5(XIcon, { style: { width: 12, height: 12 } })
|
|
3492
|
+
}
|
|
3493
|
+
)
|
|
3494
|
+
]
|
|
3495
|
+
}
|
|
3496
|
+
),
|
|
3497
|
+
toolbarContent,
|
|
3498
|
+
showColumnSettings && /* @__PURE__ */ jsxs5("div", { style: { position: "relative", flexShrink: 0 }, children: [
|
|
3499
|
+
/* @__PURE__ */ jsxs5(
|
|
3500
|
+
"button",
|
|
3501
|
+
{
|
|
3502
|
+
type: "button",
|
|
3503
|
+
onClick: () => setShowColumnPicker((p) => !p),
|
|
3504
|
+
style: {
|
|
3505
|
+
display: "flex",
|
|
3506
|
+
alignItems: "center",
|
|
3507
|
+
justifyContent: "center",
|
|
3508
|
+
background: "none",
|
|
3509
|
+
border: "1px solid rgba(128,128,128,0.2)",
|
|
3510
|
+
borderRadius: 4,
|
|
3511
|
+
cursor: "pointer",
|
|
3512
|
+
padding: "4px 6px",
|
|
3513
|
+
color: "inherit",
|
|
3514
|
+
gap: 4,
|
|
3515
|
+
fontSize: 12
|
|
3516
|
+
},
|
|
3517
|
+
title: "Column settings",
|
|
3518
|
+
children: [
|
|
3519
|
+
icons?.columns ?? /* @__PURE__ */ jsx5(ColumnsIcon, { style: { width: 14, height: 14 } }),
|
|
3520
|
+
/* @__PURE__ */ jsx5("span", { children: columnSettingsLabel ?? "Columns" })
|
|
3521
|
+
]
|
|
3522
|
+
}
|
|
3523
|
+
),
|
|
3524
|
+
showColumnPicker && /* @__PURE__ */ jsx5(
|
|
3525
|
+
"div",
|
|
3526
|
+
{
|
|
3527
|
+
ref: columnPickerRef,
|
|
3528
|
+
style: {
|
|
3529
|
+
position: "absolute",
|
|
3530
|
+
top: "100%",
|
|
3531
|
+
right: 0,
|
|
3532
|
+
zIndex: 99999,
|
|
3533
|
+
minWidth: 200,
|
|
3534
|
+
maxHeight: 320,
|
|
3535
|
+
overflowY: "auto",
|
|
3536
|
+
borderRadius: 8,
|
|
3537
|
+
border: "1px solid rgba(128,128,128,0.2)",
|
|
3538
|
+
boxShadow: "0 4px 24px rgba(0,0,0,0.12)",
|
|
3539
|
+
backdropFilter: "blur(16px)",
|
|
3540
|
+
WebkitBackdropFilter: "blur(16px)",
|
|
3541
|
+
backgroundColor: "rgba(128,128,128,0.08)",
|
|
3542
|
+
padding: "4px 0",
|
|
3543
|
+
marginTop: 4
|
|
3544
|
+
},
|
|
3545
|
+
children: initialColumns.filter(
|
|
3546
|
+
(c) => c.key !== "__select__" && c.key !== "__expand__"
|
|
3547
|
+
).map((col) => {
|
|
3548
|
+
const current = columns.find(
|
|
3549
|
+
(c) => c.key === col.key
|
|
3550
|
+
);
|
|
3551
|
+
const isHidden = current?.hidden ?? false;
|
|
3552
|
+
const isPinned = !!current?.pinned;
|
|
3553
|
+
return /* @__PURE__ */ jsxs5(
|
|
3554
|
+
"label",
|
|
3555
|
+
{
|
|
3556
|
+
style: {
|
|
3557
|
+
display: "flex",
|
|
3558
|
+
alignItems: "center",
|
|
3559
|
+
gap: 8,
|
|
3560
|
+
padding: "6px 12px",
|
|
3561
|
+
cursor: isPinned ? "not-allowed" : "pointer",
|
|
3562
|
+
opacity: isPinned ? 0.5 : 1,
|
|
3563
|
+
fontSize: 12
|
|
3564
|
+
},
|
|
3565
|
+
children: [
|
|
3566
|
+
/* @__PURE__ */ jsx5(
|
|
3567
|
+
"input",
|
|
3568
|
+
{
|
|
3569
|
+
type: "checkbox",
|
|
3570
|
+
checked: !isHidden,
|
|
3571
|
+
disabled: isPinned,
|
|
3572
|
+
onChange: () => {
|
|
3573
|
+
if (isPinned) return;
|
|
3574
|
+
handleToggleHide(col.key);
|
|
3575
|
+
},
|
|
3576
|
+
style: {
|
|
3577
|
+
cursor: isPinned ? "not-allowed" : "pointer",
|
|
3578
|
+
accentColor
|
|
3579
|
+
}
|
|
3580
|
+
}
|
|
3581
|
+
),
|
|
3582
|
+
/* @__PURE__ */ jsx5(
|
|
3583
|
+
"span",
|
|
3584
|
+
{
|
|
3585
|
+
style: {
|
|
3586
|
+
overflow: "hidden",
|
|
3587
|
+
textOverflow: "ellipsis",
|
|
3588
|
+
whiteSpace: "nowrap"
|
|
3589
|
+
},
|
|
3590
|
+
children: typeof col.title === "string" ? col.title : col.key
|
|
3591
|
+
}
|
|
3592
|
+
)
|
|
3593
|
+
]
|
|
3594
|
+
},
|
|
3595
|
+
col.key
|
|
3596
|
+
);
|
|
3597
|
+
})
|
|
3598
|
+
}
|
|
3599
|
+
)
|
|
3600
|
+
] }),
|
|
3601
|
+
aiMode && /* @__PURE__ */ jsxs5(
|
|
3602
|
+
"button",
|
|
3603
|
+
{
|
|
3604
|
+
type: "button",
|
|
3605
|
+
onClick: () => setAiBarOpen(true),
|
|
3606
|
+
style: {
|
|
3607
|
+
display: "flex",
|
|
3608
|
+
alignItems: "center",
|
|
3609
|
+
justifyContent: "center",
|
|
3610
|
+
gap: 4,
|
|
3611
|
+
background: `linear-gradient(135deg, ${accentColor}18, ${accentColor}08)`,
|
|
3612
|
+
border: `1px solid ${accentColor}40`,
|
|
3613
|
+
borderRadius: 4,
|
|
3614
|
+
cursor: "pointer",
|
|
3615
|
+
padding: "4px 8px",
|
|
3616
|
+
color: accentColor,
|
|
3617
|
+
fontSize: 12,
|
|
3618
|
+
fontWeight: 500,
|
|
3619
|
+
flexShrink: 0,
|
|
3620
|
+
transition: "all 0.2s ease"
|
|
3621
|
+
},
|
|
3622
|
+
title: "Ask AI",
|
|
3623
|
+
children: [
|
|
3624
|
+
icons?.sparkles ?? /* @__PURE__ */ jsx5(SparklesIcon, { style: { width: 14, height: 14 } }),
|
|
3625
|
+
/* @__PURE__ */ jsx5("span", { children: aiButtonLabel ?? "Ask AI" })
|
|
3626
|
+
]
|
|
3627
|
+
}
|
|
3628
|
+
)
|
|
3629
|
+
]
|
|
3630
|
+
}
|
|
3631
|
+
),
|
|
3632
|
+
aiMode && /* @__PURE__ */ jsxs5(
|
|
3633
|
+
"div",
|
|
3634
|
+
{
|
|
3635
|
+
style: {
|
|
3636
|
+
position: "absolute",
|
|
3637
|
+
inset: 0,
|
|
3638
|
+
display: "flex",
|
|
3639
|
+
alignItems: "center",
|
|
3640
|
+
gap: 8,
|
|
3641
|
+
padding: "4px 8px",
|
|
3642
|
+
opacity: aiBarOpen ? 1 : 0,
|
|
3643
|
+
transform: aiBarOpen ? "translateX(0)" : "translateX(40px)",
|
|
3644
|
+
transition: "opacity 0.3s cubic-bezier(0.4,0,0.2,1), transform 0.3s cubic-bezier(0.4,0,0.2,1)",
|
|
3645
|
+
pointerEvents: aiBarOpen ? "auto" : "none",
|
|
3646
|
+
zIndex: 2,
|
|
3647
|
+
background: "inherit",
|
|
3648
|
+
backdropFilter: "blur(12px)",
|
|
3649
|
+
WebkitBackdropFilter: "blur(12px)"
|
|
2982
3650
|
},
|
|
2983
3651
|
children: [
|
|
2984
3652
|
/* @__PURE__ */ jsx5(
|
|
2985
3653
|
"span",
|
|
2986
3654
|
{
|
|
2987
|
-
style: {
|
|
2988
|
-
|
|
3655
|
+
style: {
|
|
3656
|
+
display: "flex",
|
|
3657
|
+
color: accentColor,
|
|
3658
|
+
flexShrink: 0
|
|
3659
|
+
},
|
|
3660
|
+
children: icons?.sparkles ?? /* @__PURE__ */ jsx5(SparklesIcon, { style: { width: 16, height: 16 } })
|
|
2989
3661
|
}
|
|
2990
3662
|
),
|
|
2991
3663
|
/* @__PURE__ */ jsx5(
|
|
2992
3664
|
"input",
|
|
2993
3665
|
{
|
|
3666
|
+
ref: aiInputRef,
|
|
2994
3667
|
type: "text",
|
|
2995
|
-
placeholder:
|
|
2996
|
-
value:
|
|
2997
|
-
onChange: (e) =>
|
|
2998
|
-
|
|
2999
|
-
if (
|
|
3000
|
-
|
|
3668
|
+
placeholder: aiPlaceholder,
|
|
3669
|
+
value: aiQuery,
|
|
3670
|
+
onChange: (e) => setAiQuery(e.target.value),
|
|
3671
|
+
onKeyDown: (e) => {
|
|
3672
|
+
if (e.key === "Enter" && !aiLoading) handleAISubmit();
|
|
3673
|
+
if (e.key === "Escape") handleAIBarClose();
|
|
3001
3674
|
},
|
|
3675
|
+
disabled: aiLoading,
|
|
3002
3676
|
style: {
|
|
3003
3677
|
flex: "1 1 0%",
|
|
3004
3678
|
border: "none",
|
|
@@ -3007,18 +3681,51 @@ function BoltTable({
|
|
|
3007
3681
|
font: "inherit",
|
|
3008
3682
|
color: "inherit",
|
|
3009
3683
|
padding: "4px 6px",
|
|
3010
|
-
minWidth: 0
|
|
3684
|
+
minWidth: 0,
|
|
3685
|
+
fontSize: 12
|
|
3011
3686
|
}
|
|
3012
3687
|
}
|
|
3013
3688
|
),
|
|
3014
|
-
|
|
3689
|
+
/* @__PURE__ */ jsx5(
|
|
3015
3690
|
"button",
|
|
3016
3691
|
{
|
|
3017
3692
|
type: "button",
|
|
3018
|
-
onClick:
|
|
3019
|
-
|
|
3020
|
-
|
|
3693
|
+
onClick: handleAISubmit,
|
|
3694
|
+
disabled: aiLoading || !aiQuery.trim(),
|
|
3695
|
+
style: {
|
|
3696
|
+
display: "flex",
|
|
3697
|
+
alignItems: "center",
|
|
3698
|
+
justifyContent: "center",
|
|
3699
|
+
background: aiQuery.trim() ? accentColor : "rgba(128,128,128,0.15)",
|
|
3700
|
+
border: "none",
|
|
3701
|
+
borderRadius: 4,
|
|
3702
|
+
cursor: aiLoading || !aiQuery.trim() ? "not-allowed" : "pointer",
|
|
3703
|
+
padding: "4px 8px",
|
|
3704
|
+
color: aiQuery.trim() ? "#fff" : "GrayText",
|
|
3705
|
+
transition: "all 0.2s ease",
|
|
3706
|
+
flexShrink: 0,
|
|
3707
|
+
gap: 4,
|
|
3708
|
+
fontSize: 12,
|
|
3709
|
+
opacity: aiLoading ? 0.7 : 1
|
|
3021
3710
|
},
|
|
3711
|
+
title: "Send",
|
|
3712
|
+
children: aiLoading ? /* @__PURE__ */ jsx5(Fragment4, { children: icons?.loader ?? /* @__PURE__ */ jsx5(
|
|
3713
|
+
LoaderIcon,
|
|
3714
|
+
{
|
|
3715
|
+
style: {
|
|
3716
|
+
width: 14,
|
|
3717
|
+
height: 14,
|
|
3718
|
+
animation: "bt-spin 1s linear infinite"
|
|
3719
|
+
}
|
|
3720
|
+
}
|
|
3721
|
+
) }) : /* @__PURE__ */ jsx5(Fragment4, { children: icons?.send ?? /* @__PURE__ */ jsx5(SendIcon, { style: { width: 14, height: 14 } }) })
|
|
3722
|
+
}
|
|
3723
|
+
),
|
|
3724
|
+
/* @__PURE__ */ jsx5(
|
|
3725
|
+
"button",
|
|
3726
|
+
{
|
|
3727
|
+
type: "button",
|
|
3728
|
+
onClick: handleAIBarClose,
|
|
3022
3729
|
style: {
|
|
3023
3730
|
display: "flex",
|
|
3024
3731
|
alignItems: "center",
|
|
@@ -3030,114 +3737,96 @@ function BoltTable({
|
|
|
3030
3737
|
color: "GrayText",
|
|
3031
3738
|
flexShrink: 0
|
|
3032
3739
|
},
|
|
3033
|
-
|
|
3740
|
+
title: "Close AI",
|
|
3741
|
+
children: icons?.close ?? /* @__PURE__ */ jsx5(XIcon, { style: { width: 14, height: 14 } })
|
|
3034
3742
|
}
|
|
3035
3743
|
)
|
|
3036
3744
|
]
|
|
3037
3745
|
}
|
|
3038
|
-
)
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
/* @__PURE__ */ jsx5(
|
|
3123
|
-
"span",
|
|
3124
|
-
{
|
|
3125
|
-
style: {
|
|
3126
|
-
overflow: "hidden",
|
|
3127
|
-
textOverflow: "ellipsis",
|
|
3128
|
-
whiteSpace: "nowrap"
|
|
3129
|
-
},
|
|
3130
|
-
children: typeof col.title === "string" ? col.title : col.key
|
|
3131
|
-
}
|
|
3132
|
-
)
|
|
3133
|
-
]
|
|
3134
|
-
},
|
|
3135
|
-
col.key
|
|
3136
|
-
);
|
|
3137
|
-
})
|
|
3138
|
-
}
|
|
3139
|
-
)
|
|
3140
|
-
] })
|
|
3746
|
+
)
|
|
3747
|
+
]
|
|
3748
|
+
}
|
|
3749
|
+
),
|
|
3750
|
+
aiResult && /* @__PURE__ */ jsxs5(
|
|
3751
|
+
"div",
|
|
3752
|
+
{
|
|
3753
|
+
style: {
|
|
3754
|
+
display: "flex",
|
|
3755
|
+
alignItems: "center",
|
|
3756
|
+
gap: 8,
|
|
3757
|
+
padding: "6px 12px",
|
|
3758
|
+
fontSize: 12,
|
|
3759
|
+
borderBottom: "1px solid rgba(128,128,128,0.2)",
|
|
3760
|
+
background: `linear-gradient(90deg, ${accentColor}08, transparent)`,
|
|
3761
|
+
flexShrink: 0
|
|
3762
|
+
},
|
|
3763
|
+
children: [
|
|
3764
|
+
/* @__PURE__ */ jsx5("span", { style: { color: accentColor, display: "flex", flexShrink: 0 }, children: icons?.sparkles ?? /* @__PURE__ */ jsx5(SparklesIcon, { style: { width: 14, height: 14 } }) }),
|
|
3765
|
+
/* @__PURE__ */ jsx5("span", { style: { flex: "1 1 0%", opacity: 0.85 }, children: aiResult.message }),
|
|
3766
|
+
/* @__PURE__ */ jsxs5(
|
|
3767
|
+
"button",
|
|
3768
|
+
{
|
|
3769
|
+
type: "button",
|
|
3770
|
+
onClick: handleAIClear,
|
|
3771
|
+
style: {
|
|
3772
|
+
display: "flex",
|
|
3773
|
+
alignItems: "center",
|
|
3774
|
+
gap: 4,
|
|
3775
|
+
background: "none",
|
|
3776
|
+
border: "1px solid rgba(128,128,128,0.2)",
|
|
3777
|
+
borderRadius: 4,
|
|
3778
|
+
cursor: "pointer",
|
|
3779
|
+
padding: "2px 8px",
|
|
3780
|
+
color: "inherit",
|
|
3781
|
+
fontSize: 11,
|
|
3782
|
+
flexShrink: 0,
|
|
3783
|
+
opacity: 0.7
|
|
3784
|
+
},
|
|
3785
|
+
title: "Clear AI results",
|
|
3786
|
+
children: [
|
|
3787
|
+
icons?.close ?? /* @__PURE__ */ jsx5(XIcon, { style: { width: 10, height: 10 } }),
|
|
3788
|
+
/* @__PURE__ */ jsx5("span", { children: "Clear" })
|
|
3789
|
+
]
|
|
3790
|
+
}
|
|
3791
|
+
)
|
|
3792
|
+
]
|
|
3793
|
+
}
|
|
3794
|
+
),
|
|
3795
|
+
aiError && !aiResult && /* @__PURE__ */ jsxs5(
|
|
3796
|
+
"div",
|
|
3797
|
+
{
|
|
3798
|
+
style: {
|
|
3799
|
+
display: "flex",
|
|
3800
|
+
alignItems: "center",
|
|
3801
|
+
gap: 8,
|
|
3802
|
+
padding: "6px 12px",
|
|
3803
|
+
fontSize: 12,
|
|
3804
|
+
borderBottom: "1px solid rgba(239,68,68,0.2)",
|
|
3805
|
+
background: "rgba(239,68,68,0.06)",
|
|
3806
|
+
color: "#ef4444",
|
|
3807
|
+
flexShrink: 0
|
|
3808
|
+
},
|
|
3809
|
+
children: [
|
|
3810
|
+
/* @__PURE__ */ jsx5("span", { style: { flex: "1 1 0%" }, children: aiError }),
|
|
3811
|
+
/* @__PURE__ */ jsx5(
|
|
3812
|
+
"button",
|
|
3813
|
+
{
|
|
3814
|
+
type: "button",
|
|
3815
|
+
onClick: () => setAiError(null),
|
|
3816
|
+
style: {
|
|
3817
|
+
display: "flex",
|
|
3818
|
+
alignItems: "center",
|
|
3819
|
+
justifyContent: "center",
|
|
3820
|
+
background: "none",
|
|
3821
|
+
border: "none",
|
|
3822
|
+
cursor: "pointer",
|
|
3823
|
+
padding: 2,
|
|
3824
|
+
color: "#ef4444",
|
|
3825
|
+
flexShrink: 0
|
|
3826
|
+
},
|
|
3827
|
+
children: icons?.close ?? /* @__PURE__ */ jsx5(XIcon, { style: { width: 12, height: 12 } })
|
|
3828
|
+
}
|
|
3829
|
+
)
|
|
3141
3830
|
]
|
|
3142
3831
|
}
|
|
3143
3832
|
),
|
|
@@ -3639,14 +4328,20 @@ function BoltTable({
|
|
|
3639
4328
|
gridTemplateColumns,
|
|
3640
4329
|
headerHeight: HEADER_HEIGHT,
|
|
3641
4330
|
rowClassName,
|
|
3642
|
-
rowStyle,
|
|
4331
|
+
rowStyle: aiStyleOps.length > 0 ? (record, index) => {
|
|
4332
|
+
const base = rowStyle ? rowStyle(record, index) : void 0;
|
|
4333
|
+
const ai = getAIRowStyleForRecord(record);
|
|
4334
|
+
if (!base && !ai) return {};
|
|
4335
|
+
return { ...base, ...ai };
|
|
4336
|
+
} : rowStyle,
|
|
3643
4337
|
bodyGridRow: hasColumnGroups ? 3 : 2,
|
|
3644
4338
|
onEdit,
|
|
3645
4339
|
editingCell,
|
|
3646
4340
|
onEditComplete: handleEditComplete,
|
|
3647
4341
|
enableDynamicRowHeight,
|
|
3648
4342
|
onRowHeightChange: handleRowHeightChange,
|
|
3649
|
-
columnGridIndexMap
|
|
4343
|
+
columnGridIndexMap,
|
|
4344
|
+
cellStyleFn: aiCellStyleOps.length > 0 ? (record, columnKey) => getAICellStyleForRecord(record, columnKey) : void 0
|
|
3650
4345
|
}
|
|
3651
4346
|
)
|
|
3652
4347
|
]
|
|
@@ -4264,9 +4959,15 @@ function BoltTable({
|
|
|
4264
4959
|
})()
|
|
4265
4960
|
] });
|
|
4266
4961
|
}
|
|
4962
|
+
|
|
4963
|
+
// src/types.ts
|
|
4964
|
+
function defineConfig(config) {
|
|
4965
|
+
return config;
|
|
4966
|
+
}
|
|
4267
4967
|
export {
|
|
4268
4968
|
BoltTable,
|
|
4269
4969
|
DraggableHeader_default as DraggableHeader,
|
|
4270
4970
|
ResizeOverlay_default as ResizeOverlay,
|
|
4271
|
-
TableBody_default as TableBody
|
|
4971
|
+
TableBody_default as TableBody,
|
|
4972
|
+
defineConfig
|
|
4272
4973
|
};
|