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.js
CHANGED
|
@@ -33,7 +33,8 @@ __export(index_exports, {
|
|
|
33
33
|
BoltTable: () => BoltTable,
|
|
34
34
|
DraggableHeader: () => DraggableHeader_default,
|
|
35
35
|
ResizeOverlay: () => ResizeOverlay_default,
|
|
36
|
-
TableBody: () => TableBody_default
|
|
36
|
+
TableBody: () => TableBody_default,
|
|
37
|
+
defineConfig: () => defineConfig
|
|
37
38
|
});
|
|
38
39
|
module.exports = __toCommonJS(index_exports);
|
|
39
40
|
|
|
@@ -136,6 +137,18 @@ var XIcon = ({ style, className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx
|
|
|
136
137
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M18 6 6 18" }),
|
|
137
138
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m6 6 12 12" })
|
|
138
139
|
] });
|
|
140
|
+
var SparklesIcon = ({ style, className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ...svgBase, style, className, children: [
|
|
141
|
+
/* @__PURE__ */ (0, import_jsx_runtime.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" }),
|
|
142
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M5 3v4" }),
|
|
143
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M19 17v4" }),
|
|
144
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M3 5h4" }),
|
|
145
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M17 19h4" })
|
|
146
|
+
] });
|
|
147
|
+
var SendIcon = ({ style, className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ...svgBase, style, className, children: [
|
|
148
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m22 2-7 20-4-9-9-4Z" }),
|
|
149
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M22 2 11 13" })
|
|
150
|
+
] });
|
|
151
|
+
var LoaderIcon = ({ style, className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { ...svgBase, style, className, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }) });
|
|
139
152
|
|
|
140
153
|
// src/DraggableHeader.tsx
|
|
141
154
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
@@ -677,6 +690,280 @@ var DraggableHeader = import_react.default.memo(
|
|
|
677
690
|
DraggableHeader.displayName = "DraggableHeader";
|
|
678
691
|
var DraggableHeader_default = DraggableHeader;
|
|
679
692
|
|
|
693
|
+
// src/ai.ts
|
|
694
|
+
function detectColumnType(key, data) {
|
|
695
|
+
const values = [];
|
|
696
|
+
for (let i = 0; i < Math.min(data.length, 20); i++) {
|
|
697
|
+
const v = data[i]?.[key];
|
|
698
|
+
if (v != null) values.push(v);
|
|
699
|
+
}
|
|
700
|
+
if (values.length === 0) return { type: "unknown", sample: "" };
|
|
701
|
+
const allNumbers = values.every((v) => typeof v === "number");
|
|
702
|
+
const allBooleans = values.every((v) => typeof v === "boolean");
|
|
703
|
+
const uniqueVals = [...new Set(values.map(String))];
|
|
704
|
+
const sampleStr = uniqueVals.length <= 8 ? uniqueVals.join(", ") : uniqueVals.slice(0, 6).join(", ") + "...";
|
|
705
|
+
if (allBooleans) return { type: "boolean", sample: sampleStr };
|
|
706
|
+
if (allNumbers) {
|
|
707
|
+
const nums = values;
|
|
708
|
+
const min = Math.min(...nums);
|
|
709
|
+
const max = Math.max(...nums);
|
|
710
|
+
return { type: "number", sample: `range ${min}\u2013${max}` };
|
|
711
|
+
}
|
|
712
|
+
return { type: "string", sample: sampleStr };
|
|
713
|
+
}
|
|
714
|
+
function buildSystemPrompt(columns, data) {
|
|
715
|
+
const schemaLines = columns.filter((c) => c.key !== "__select__" && c.key !== "__expand__").map((c) => {
|
|
716
|
+
const key = c.dataIndex ?? c.key;
|
|
717
|
+
const title = typeof c.title === "string" ? c.title : c.key;
|
|
718
|
+
const info = detectColumnType(key, data);
|
|
719
|
+
return ` - key: "${c.key}", title: "${title}", dataIndex: "${key}", type: ${info.type}${info.sample ? ` (values: ${info.sample})` : ""}`;
|
|
720
|
+
}).join("\n");
|
|
721
|
+
const sample = data.slice(0, 5).map((row) => {
|
|
722
|
+
const obj = {};
|
|
723
|
+
for (const col of columns) {
|
|
724
|
+
if (col.key === "__select__" || col.key === "__expand__") continue;
|
|
725
|
+
const di = col.dataIndex ?? col.key;
|
|
726
|
+
obj[di] = row[di];
|
|
727
|
+
}
|
|
728
|
+
return obj;
|
|
729
|
+
});
|
|
730
|
+
return `You are a data table assistant. You help users query, filter, sort, and style tabular data.
|
|
731
|
+
You MUST respond with ONLY a valid JSON object \u2014 no markdown fences, no explanation, no extra text.
|
|
732
|
+
|
|
733
|
+
## Table Schema
|
|
734
|
+
${schemaLines}
|
|
735
|
+
|
|
736
|
+
## Sample Data (first ${sample.length} of ${data.length} rows)
|
|
737
|
+
${JSON.stringify(sample, null, 2)}
|
|
738
|
+
|
|
739
|
+
## Available Operations
|
|
740
|
+
Combine any of these in a single response:
|
|
741
|
+
|
|
742
|
+
1. **filter** \u2014 show only rows matching conditions
|
|
743
|
+
{ "type": "filter", "conditions": [{ "column": "<dataIndex>", "op": "<op>", "value": <val> }], "logic": "and" | "or" }
|
|
744
|
+
|
|
745
|
+
2. **rowStyle** \u2014 apply CSS styles to entire rows matching conditions
|
|
746
|
+
{ "type": "rowStyle", "conditions": [...], "logic": "and"|"or", "style": { "<cssProp>": "<value>" } }
|
|
747
|
+
|
|
748
|
+
3. **cellStyle** \u2014 apply CSS styles to a specific column's cells matching conditions
|
|
749
|
+
{ "type": "cellStyle", "column": "<dataIndex>", "conditions": [...], "logic": "and"|"or", "style": { "<cssProp>": "<value>" } }
|
|
750
|
+
|
|
751
|
+
4. **sort** \u2014 sort data by a column
|
|
752
|
+
{ "type": "sort", "column": "<dataIndex>", "direction": "asc" | "desc" }
|
|
753
|
+
|
|
754
|
+
5. **hideColumns** / **showColumns** \u2014 toggle column visibility
|
|
755
|
+
{ "type": "hideColumns" | "showColumns", "columns": ["<key>", ...] }
|
|
756
|
+
|
|
757
|
+
## Operators
|
|
758
|
+
eq, neq, gt, gte, lt, lte, contains, notContains, startsWith, endsWith, in, notIn
|
|
759
|
+
|
|
760
|
+
## Response format
|
|
761
|
+
{
|
|
762
|
+
"operations": [ ... ],
|
|
763
|
+
"message": "Brief user-friendly description of what was applied"
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
## Rules
|
|
767
|
+
- Use the dataIndex values from the schema, not display titles.
|
|
768
|
+
- For colors use semi-transparent values like "rgba(255,0,0,0.15)" so text stays readable.
|
|
769
|
+
- CSS property names must be camelCase (e.g. "backgroundColor", "color", "fontWeight").
|
|
770
|
+
- If the user asks to highlight / color / mark specific rows, use rowStyle or cellStyle.
|
|
771
|
+
- If the user asks to show only certain rows, use filter.
|
|
772
|
+
- You can combine filter + rowStyle + sort etc. in one response.
|
|
773
|
+
- The "message" should be concise: what was done, in plain English.`;
|
|
774
|
+
}
|
|
775
|
+
async function callAI(config, systemPrompt, userQuery) {
|
|
776
|
+
const { provider, apiKey, model, baseUrl, maxTokens = 1024, temperature = 0.1 } = config;
|
|
777
|
+
if (provider === "openai" || provider === "custom") {
|
|
778
|
+
const url = baseUrl ? `${baseUrl.replace(/\/$/, "")}/chat/completions` : "https://api.openai.com/v1/chat/completions";
|
|
779
|
+
const res = await fetch(url, {
|
|
780
|
+
method: "POST",
|
|
781
|
+
headers: {
|
|
782
|
+
"Content-Type": "application/json",
|
|
783
|
+
Authorization: `Bearer ${apiKey}`
|
|
784
|
+
},
|
|
785
|
+
body: JSON.stringify({
|
|
786
|
+
model: model ?? "gpt-4o-mini",
|
|
787
|
+
messages: [
|
|
788
|
+
{ role: "system", content: systemPrompt },
|
|
789
|
+
{ role: "user", content: userQuery }
|
|
790
|
+
],
|
|
791
|
+
max_tokens: maxTokens,
|
|
792
|
+
temperature
|
|
793
|
+
})
|
|
794
|
+
});
|
|
795
|
+
if (!res.ok) {
|
|
796
|
+
const body = await res.text().catch(() => "");
|
|
797
|
+
throw new Error(`AI request failed (${res.status}): ${body}`);
|
|
798
|
+
}
|
|
799
|
+
const json = await res.json();
|
|
800
|
+
return json.choices?.[0]?.message?.content ?? "";
|
|
801
|
+
}
|
|
802
|
+
if (provider === "anthropic") {
|
|
803
|
+
const url = baseUrl ? `${baseUrl.replace(/\/$/, "")}/messages` : "https://api.anthropic.com/v1/messages";
|
|
804
|
+
const res = await fetch(url, {
|
|
805
|
+
method: "POST",
|
|
806
|
+
headers: {
|
|
807
|
+
"Content-Type": "application/json",
|
|
808
|
+
"x-api-key": apiKey,
|
|
809
|
+
"anthropic-version": "2023-06-01",
|
|
810
|
+
"anthropic-dangerous-direct-browser-access": "true"
|
|
811
|
+
},
|
|
812
|
+
body: JSON.stringify({
|
|
813
|
+
model: model ?? "claude-sonnet-4-20250514",
|
|
814
|
+
system: systemPrompt,
|
|
815
|
+
messages: [{ role: "user", content: userQuery }],
|
|
816
|
+
max_tokens: maxTokens,
|
|
817
|
+
temperature
|
|
818
|
+
})
|
|
819
|
+
});
|
|
820
|
+
if (!res.ok) {
|
|
821
|
+
const body = await res.text().catch(() => "");
|
|
822
|
+
throw new Error(`AI request failed (${res.status}): ${body}`);
|
|
823
|
+
}
|
|
824
|
+
const json = await res.json();
|
|
825
|
+
const textBlock = json.content?.find(
|
|
826
|
+
(b) => b.type === "text"
|
|
827
|
+
);
|
|
828
|
+
return textBlock?.text ?? "";
|
|
829
|
+
}
|
|
830
|
+
throw new Error(`Unsupported AI provider: ${provider}`);
|
|
831
|
+
}
|
|
832
|
+
function parseAIResponse(raw) {
|
|
833
|
+
let text = raw.trim();
|
|
834
|
+
const fenceMatch = text.match(/```(?:json)?\s*([\s\S]*?)```/);
|
|
835
|
+
if (fenceMatch) text = fenceMatch[1].trim();
|
|
836
|
+
const start = text.indexOf("{");
|
|
837
|
+
const end = text.lastIndexOf("}");
|
|
838
|
+
if (start !== -1 && end > start) {
|
|
839
|
+
text = text.slice(start, end + 1);
|
|
840
|
+
}
|
|
841
|
+
const parsed = JSON.parse(text);
|
|
842
|
+
if (!parsed.operations || !Array.isArray(parsed.operations)) {
|
|
843
|
+
throw new Error("Invalid AI response: missing operations array");
|
|
844
|
+
}
|
|
845
|
+
return {
|
|
846
|
+
operations: parsed.operations,
|
|
847
|
+
message: parsed.message ?? "AI operations applied."
|
|
848
|
+
};
|
|
849
|
+
}
|
|
850
|
+
function evaluateCondition(condition, row) {
|
|
851
|
+
const rawVal = row[condition.column];
|
|
852
|
+
const target = condition.value;
|
|
853
|
+
switch (condition.op) {
|
|
854
|
+
case "eq":
|
|
855
|
+
return rawVal == target;
|
|
856
|
+
case "neq":
|
|
857
|
+
return rawVal != target;
|
|
858
|
+
case "gt":
|
|
859
|
+
return Number(rawVal) > Number(target);
|
|
860
|
+
case "gte":
|
|
861
|
+
return Number(rawVal) >= Number(target);
|
|
862
|
+
case "lt":
|
|
863
|
+
return Number(rawVal) < Number(target);
|
|
864
|
+
case "lte":
|
|
865
|
+
return Number(rawVal) <= Number(target);
|
|
866
|
+
case "contains":
|
|
867
|
+
return String(rawVal ?? "").toLowerCase().includes(String(target).toLowerCase());
|
|
868
|
+
case "notContains":
|
|
869
|
+
return !String(rawVal ?? "").toLowerCase().includes(String(target).toLowerCase());
|
|
870
|
+
case "startsWith":
|
|
871
|
+
return String(rawVal ?? "").toLowerCase().startsWith(String(target).toLowerCase());
|
|
872
|
+
case "endsWith":
|
|
873
|
+
return String(rawVal ?? "").toLowerCase().endsWith(String(target).toLowerCase());
|
|
874
|
+
case "in":
|
|
875
|
+
if (Array.isArray(target)) {
|
|
876
|
+
return target.some((t) => rawVal == t);
|
|
877
|
+
}
|
|
878
|
+
return false;
|
|
879
|
+
case "notIn":
|
|
880
|
+
if (Array.isArray(target)) {
|
|
881
|
+
return !target.some((t) => rawVal == t);
|
|
882
|
+
}
|
|
883
|
+
return true;
|
|
884
|
+
default:
|
|
885
|
+
return true;
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
function matchesConditions(conditions, logic, row) {
|
|
889
|
+
if (!conditions || conditions.length === 0) return true;
|
|
890
|
+
if (logic === "or") {
|
|
891
|
+
return conditions.some((c) => evaluateCondition(c, row));
|
|
892
|
+
}
|
|
893
|
+
return conditions.every((c) => evaluateCondition(c, row));
|
|
894
|
+
}
|
|
895
|
+
function applyAIFilter(data, op) {
|
|
896
|
+
return data.filter((row) => matchesConditions(op.conditions, op.logic, row));
|
|
897
|
+
}
|
|
898
|
+
function applyAISort(data, op) {
|
|
899
|
+
const dir = op.direction === "asc" ? 1 : -1;
|
|
900
|
+
const col = op.column;
|
|
901
|
+
return [...data].sort((a, b) => {
|
|
902
|
+
const aVal = a[col];
|
|
903
|
+
const bVal = b[col];
|
|
904
|
+
if (aVal == null && bVal == null) return 0;
|
|
905
|
+
if (aVal == null) return 1;
|
|
906
|
+
if (bVal == null) return -1;
|
|
907
|
+
if (typeof aVal === "number" && typeof bVal === "number")
|
|
908
|
+
return (aVal - bVal) * dir;
|
|
909
|
+
return String(aVal).localeCompare(String(bVal)) * dir;
|
|
910
|
+
});
|
|
911
|
+
}
|
|
912
|
+
function getAIRowStyle(row, ops) {
|
|
913
|
+
let merged;
|
|
914
|
+
for (const op of ops) {
|
|
915
|
+
if (matchesConditions(op.conditions, op.logic, row)) {
|
|
916
|
+
if (!merged) merged = {};
|
|
917
|
+
Object.assign(merged, op.style);
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
return merged;
|
|
921
|
+
}
|
|
922
|
+
function getAICellStyle(row, columnKey, ops) {
|
|
923
|
+
let merged;
|
|
924
|
+
for (const op of ops) {
|
|
925
|
+
if (op.column === columnKey && matchesConditions(op.conditions, op.logic, row)) {
|
|
926
|
+
if (!merged) merged = {};
|
|
927
|
+
Object.assign(merged, op.style);
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
return merged;
|
|
931
|
+
}
|
|
932
|
+
function applyAIOperations(data, operations) {
|
|
933
|
+
let filteredData = data;
|
|
934
|
+
let sortOp = null;
|
|
935
|
+
const styleOps = [];
|
|
936
|
+
const cellStyleOps = [];
|
|
937
|
+
const hideColumns = [];
|
|
938
|
+
const showColumns = [];
|
|
939
|
+
for (const op of operations) {
|
|
940
|
+
switch (op.type) {
|
|
941
|
+
case "filter":
|
|
942
|
+
filteredData = applyAIFilter(filteredData, op);
|
|
943
|
+
break;
|
|
944
|
+
case "sort":
|
|
945
|
+
sortOp = op;
|
|
946
|
+
break;
|
|
947
|
+
case "rowStyle":
|
|
948
|
+
styleOps.push(op);
|
|
949
|
+
break;
|
|
950
|
+
case "cellStyle":
|
|
951
|
+
cellStyleOps.push(op);
|
|
952
|
+
break;
|
|
953
|
+
case "hideColumns":
|
|
954
|
+
hideColumns.push(...op.columns);
|
|
955
|
+
break;
|
|
956
|
+
case "showColumns":
|
|
957
|
+
showColumns.push(...op.columns);
|
|
958
|
+
break;
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
if (sortOp) {
|
|
962
|
+
filteredData = applyAISort(filteredData, sortOp);
|
|
963
|
+
}
|
|
964
|
+
return { filteredData, sortOp, styleOps, cellStyleOps, hideColumns, showColumns };
|
|
965
|
+
}
|
|
966
|
+
|
|
680
967
|
// src/ResizeOverlay.tsx
|
|
681
968
|
var import_react2 = require("react");
|
|
682
969
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
@@ -898,9 +1185,11 @@ var Cell = import_react3.default.memo(
|
|
|
898
1185
|
isLoading,
|
|
899
1186
|
onEdit,
|
|
900
1187
|
isEditing,
|
|
901
|
-
onEditComplete
|
|
1188
|
+
onEditComplete,
|
|
1189
|
+
cellStyleFn
|
|
902
1190
|
}) => {
|
|
903
1191
|
const isPinned = Boolean(column.pinned);
|
|
1192
|
+
const extraCellStyle = cellStyleFn?.(record, column.dataIndex ?? column.key);
|
|
904
1193
|
if (isLoading && column.key !== "__select__" && column.key !== "__expand__") {
|
|
905
1194
|
const shimmerContent = column.shimmerRender ? column.shimmerRender() : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
906
1195
|
"div",
|
|
@@ -1052,7 +1341,8 @@ var Cell = import_react3.default.memo(
|
|
|
1052
1341
|
minWidth: 0,
|
|
1053
1342
|
...column.style,
|
|
1054
1343
|
...isPinned ? styles?.pinnedCell : void 0,
|
|
1055
|
-
...styles?.cell
|
|
1344
|
+
...styles?.cell,
|
|
1345
|
+
...extraCellStyle
|
|
1056
1346
|
},
|
|
1057
1347
|
children: isSystem ? content : showEditor ? content : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1058
1348
|
"div",
|
|
@@ -1079,6 +1369,7 @@ var Cell = import_react3.default.memo(
|
|
|
1079
1369
|
if (prev.onEdit !== next.onEdit) return false;
|
|
1080
1370
|
if (prev.isEditing !== next.isEditing) return false;
|
|
1081
1371
|
if (prev.onEditComplete !== next.onEditComplete) return false;
|
|
1372
|
+
if (prev.cellStyleFn !== next.cellStyleFn) return false;
|
|
1082
1373
|
if (prev.column.key === "__select__") {
|
|
1083
1374
|
return prev.isSelected === next.isSelected && prev.normalizedSelectedKeys === next.normalizedSelectedKeys;
|
|
1084
1375
|
}
|
|
@@ -1180,7 +1471,8 @@ var TableBody = ({
|
|
|
1180
1471
|
onEditComplete,
|
|
1181
1472
|
enableDynamicRowHeight = false,
|
|
1182
1473
|
onRowHeightChange,
|
|
1183
|
-
columnGridIndexMap
|
|
1474
|
+
columnGridIndexMap,
|
|
1475
|
+
cellStyleFn
|
|
1184
1476
|
}) => {
|
|
1185
1477
|
const virtualItems = rowVirtualizer.getVirtualItems();
|
|
1186
1478
|
const totalSize = rowVirtualizer.getTotalSize();
|
|
@@ -1309,7 +1601,8 @@ var TableBody = ({
|
|
|
1309
1601
|
recordFingerprint,
|
|
1310
1602
|
onEdit,
|
|
1311
1603
|
isEditing: editingCell?.rowKey === rowKey && editingCell?.columnKey === col.key,
|
|
1312
|
-
onEditComplete
|
|
1604
|
+
onEditComplete,
|
|
1605
|
+
cellStyleFn
|
|
1313
1606
|
}
|
|
1314
1607
|
)
|
|
1315
1608
|
}
|
|
@@ -1346,7 +1639,8 @@ var TableBody = ({
|
|
|
1346
1639
|
recordFingerprint,
|
|
1347
1640
|
onEdit,
|
|
1348
1641
|
isEditing: editingCell?.rowKey === rowKey && editingCell?.columnKey === col.key,
|
|
1349
|
-
onEditComplete
|
|
1642
|
+
onEditComplete,
|
|
1643
|
+
cellStyleFn
|
|
1350
1644
|
}
|
|
1351
1645
|
)
|
|
1352
1646
|
}
|
|
@@ -1536,7 +1830,8 @@ var TableBody = ({
|
|
|
1536
1830
|
recordFingerprint,
|
|
1537
1831
|
onEdit,
|
|
1538
1832
|
isEditing: editingCell?.rowKey === rk && editingCell?.columnKey === col.key,
|
|
1539
|
-
onEditComplete
|
|
1833
|
+
onEditComplete,
|
|
1834
|
+
cellStyleFn
|
|
1540
1835
|
}
|
|
1541
1836
|
)
|
|
1542
1837
|
}
|
|
@@ -1664,7 +1959,8 @@ var TableBody = ({
|
|
|
1664
1959
|
recordFingerprint,
|
|
1665
1960
|
onEdit,
|
|
1666
1961
|
isEditing: editingCell?.rowKey === rk && editingCell?.columnKey === col.key,
|
|
1667
|
-
onEditComplete
|
|
1962
|
+
onEditComplete,
|
|
1963
|
+
cellStyleFn
|
|
1668
1964
|
}
|
|
1669
1965
|
)
|
|
1670
1966
|
}
|
|
@@ -1759,7 +2055,13 @@ function BoltTable({
|
|
|
1759
2055
|
globalSearchValue,
|
|
1760
2056
|
onGlobalSearchChange,
|
|
1761
2057
|
toolbarContent,
|
|
1762
|
-
columnSettingsLabel
|
|
2058
|
+
columnSettingsLabel,
|
|
2059
|
+
aiMode = false,
|
|
2060
|
+
aiConfig,
|
|
2061
|
+
onAIQuery,
|
|
2062
|
+
onAIResponse,
|
|
2063
|
+
aiPlaceholder = "Ask AI anything about your data...",
|
|
2064
|
+
aiButtonLabel
|
|
1763
2065
|
}) {
|
|
1764
2066
|
const data = (0, import_react4.useMemo)(() => {
|
|
1765
2067
|
if (!Array.isArray(rawData)) return STABLE_EMPTY_DATA;
|
|
@@ -1933,6 +2235,96 @@ function BoltTable({
|
|
|
1933
2235
|
document.removeEventListener("keydown", onKey);
|
|
1934
2236
|
};
|
|
1935
2237
|
}, [showColumnPicker]);
|
|
2238
|
+
const [aiBarOpen, setAiBarOpen] = (0, import_react4.useState)(false);
|
|
2239
|
+
const [aiQuery, setAiQuery] = (0, import_react4.useState)("");
|
|
2240
|
+
const [aiLoading, setAiLoading] = (0, import_react4.useState)(false);
|
|
2241
|
+
const [aiResult, setAiResult] = (0, import_react4.useState)(null);
|
|
2242
|
+
const [aiError, setAiError] = (0, import_react4.useState)(null);
|
|
2243
|
+
const aiInputRef = (0, import_react4.useRef)(null);
|
|
2244
|
+
const [aiStyleOps, setAiStyleOps] = (0, import_react4.useState)([]);
|
|
2245
|
+
const [aiCellStyleOps, setAiCellStyleOps] = (0, import_react4.useState)(
|
|
2246
|
+
[]
|
|
2247
|
+
);
|
|
2248
|
+
const [aiFilteredDataKeys, setAiFilteredDataKeys] = (0, import_react4.useState)(null);
|
|
2249
|
+
const [aiSortKey, setAiSortKey] = (0, import_react4.useState)(null);
|
|
2250
|
+
const [aiSortDir, setAiSortDir] = (0, import_react4.useState)(null);
|
|
2251
|
+
const onAIResponseRef = (0, import_react4.useRef)(onAIResponse);
|
|
2252
|
+
onAIResponseRef.current = onAIResponse;
|
|
2253
|
+
const handleAISubmit = (0, import_react4.useCallback)(async () => {
|
|
2254
|
+
const query = aiQuery.trim();
|
|
2255
|
+
if (!query) return;
|
|
2256
|
+
setAiLoading(true);
|
|
2257
|
+
setAiError(null);
|
|
2258
|
+
try {
|
|
2259
|
+
let response;
|
|
2260
|
+
if (onAIQuery) {
|
|
2261
|
+
response = await onAIQuery(query, {
|
|
2262
|
+
data,
|
|
2263
|
+
columns: initialColumns
|
|
2264
|
+
});
|
|
2265
|
+
} else if (aiConfig) {
|
|
2266
|
+
const sysPrompt = buildSystemPrompt(initialColumns, data);
|
|
2267
|
+
const raw = await callAI(aiConfig, sysPrompt, query);
|
|
2268
|
+
response = parseAIResponse(raw);
|
|
2269
|
+
} else {
|
|
2270
|
+
throw new Error("AI mode requires either aiConfig or onAIQuery prop");
|
|
2271
|
+
}
|
|
2272
|
+
const { filteredData, sortOp, styleOps: sOps, cellStyleOps: csOps, hideColumns, showColumns } = applyAIOperations(data, response.operations);
|
|
2273
|
+
setAiStyleOps(sOps);
|
|
2274
|
+
setAiCellStyleOps(csOps);
|
|
2275
|
+
if (response.operations.some((op) => op.type === "filter")) {
|
|
2276
|
+
const keySet = /* @__PURE__ */ new Set();
|
|
2277
|
+
filteredData.forEach((row, idx) => {
|
|
2278
|
+
const k = typeof rowKey === "function" ? rowKey(row) : String(row[typeof rowKey === "string" ? rowKey : "id"] ?? idx);
|
|
2279
|
+
keySet.add(k);
|
|
2280
|
+
});
|
|
2281
|
+
setAiFilteredDataKeys(keySet);
|
|
2282
|
+
} else {
|
|
2283
|
+
setAiFilteredDataKeys(null);
|
|
2284
|
+
}
|
|
2285
|
+
if (sortOp) {
|
|
2286
|
+
setAiSortKey(sortOp.column);
|
|
2287
|
+
setAiSortDir(sortOp.direction);
|
|
2288
|
+
} else {
|
|
2289
|
+
setAiSortKey(null);
|
|
2290
|
+
setAiSortDir(null);
|
|
2291
|
+
}
|
|
2292
|
+
if (hideColumns.length > 0 || showColumns.length > 0) {
|
|
2293
|
+
setColumns(
|
|
2294
|
+
(prev) => prev.map((col) => {
|
|
2295
|
+
if (hideColumns.includes(col.key)) return { ...col, hidden: true };
|
|
2296
|
+
if (showColumns.includes(col.key)) return { ...col, hidden: false };
|
|
2297
|
+
return col;
|
|
2298
|
+
})
|
|
2299
|
+
);
|
|
2300
|
+
}
|
|
2301
|
+
setAiResult(response);
|
|
2302
|
+
onAIResponseRef.current?.(response);
|
|
2303
|
+
} catch (err) {
|
|
2304
|
+
setAiError(err instanceof Error ? err.message : "AI query failed");
|
|
2305
|
+
} finally {
|
|
2306
|
+
setAiLoading(false);
|
|
2307
|
+
}
|
|
2308
|
+
}, [aiQuery, aiConfig, onAIQuery, data, initialColumns, rowKey]);
|
|
2309
|
+
const handleAIClear = (0, import_react4.useCallback)(() => {
|
|
2310
|
+
setAiResult(null);
|
|
2311
|
+
setAiError(null);
|
|
2312
|
+
setAiStyleOps([]);
|
|
2313
|
+
setAiCellStyleOps([]);
|
|
2314
|
+
setAiFilteredDataKeys(null);
|
|
2315
|
+
setAiSortKey(null);
|
|
2316
|
+
setAiSortDir(null);
|
|
2317
|
+
setAiQuery("");
|
|
2318
|
+
}, []);
|
|
2319
|
+
const handleAIBarClose = (0, import_react4.useCallback)(() => {
|
|
2320
|
+
setAiBarOpen(false);
|
|
2321
|
+
handleAIClear();
|
|
2322
|
+
}, [handleAIClear]);
|
|
2323
|
+
import_react4.default.useEffect(() => {
|
|
2324
|
+
if (aiBarOpen && aiInputRef.current) {
|
|
2325
|
+
setTimeout(() => aiInputRef.current?.focus(), 300);
|
|
2326
|
+
}
|
|
2327
|
+
}, [aiBarOpen]);
|
|
1936
2328
|
const columnsWithPersistedWidths = (0, import_react4.useMemo)(
|
|
1937
2329
|
() => columns.map((col) => ({
|
|
1938
2330
|
...col,
|
|
@@ -2574,6 +2966,47 @@ function BoltTable({
|
|
|
2574
2966
|
}
|
|
2575
2967
|
return result;
|
|
2576
2968
|
}, [data, sortState, columnFilters, globalSearchValue, internalGlobalSearch]);
|
|
2969
|
+
const aiProcessedData = (0, import_react4.useMemo)(() => {
|
|
2970
|
+
let result = processedData;
|
|
2971
|
+
if (aiFilteredDataKeys) {
|
|
2972
|
+
result = result.filter((row, idx) => {
|
|
2973
|
+
if (row == null) return false;
|
|
2974
|
+
const k = typeof rowKey === "function" ? rowKey(row) : String(
|
|
2975
|
+
row[typeof rowKey === "string" ? rowKey : "id"] ?? idx
|
|
2976
|
+
);
|
|
2977
|
+
return aiFilteredDataKeys.has(k);
|
|
2978
|
+
});
|
|
2979
|
+
}
|
|
2980
|
+
if (aiSortKey && aiSortDir) {
|
|
2981
|
+
const dir = aiSortDir === "asc" ? 1 : -1;
|
|
2982
|
+
const col = aiSortKey;
|
|
2983
|
+
result = [...result].sort((a, b) => {
|
|
2984
|
+
const aVal = a[col];
|
|
2985
|
+
const bVal = b[col];
|
|
2986
|
+
if (aVal == null && bVal == null) return 0;
|
|
2987
|
+
if (aVal == null) return 1;
|
|
2988
|
+
if (bVal == null) return -1;
|
|
2989
|
+
if (typeof aVal === "number" && typeof bVal === "number")
|
|
2990
|
+
return (aVal - bVal) * dir;
|
|
2991
|
+
return String(aVal).localeCompare(String(bVal)) * dir;
|
|
2992
|
+
});
|
|
2993
|
+
}
|
|
2994
|
+
return result;
|
|
2995
|
+
}, [processedData, aiFilteredDataKeys, aiSortKey, aiSortDir, rowKey]);
|
|
2996
|
+
const getAIRowStyleForRecord = (0, import_react4.useCallback)(
|
|
2997
|
+
(record) => {
|
|
2998
|
+
if (aiStyleOps.length === 0) return void 0;
|
|
2999
|
+
return getAIRowStyle(record, aiStyleOps);
|
|
3000
|
+
},
|
|
3001
|
+
[aiStyleOps]
|
|
3002
|
+
);
|
|
3003
|
+
const getAICellStyleForRecord = (0, import_react4.useCallback)(
|
|
3004
|
+
(record, columnKey) => {
|
|
3005
|
+
if (aiCellStyleOps.length === 0) return void 0;
|
|
3006
|
+
return getAICellStyle(record, columnKey, aiCellStyleOps);
|
|
3007
|
+
},
|
|
3008
|
+
[aiCellStyleOps]
|
|
3009
|
+
);
|
|
2577
3010
|
const pinnedRowCacheRef = (0, import_react4.useRef)(/* @__PURE__ */ new Map());
|
|
2578
3011
|
const { pinnedTopRows, pinnedBottomRows, unpinnedProcessedData } = (0, import_react4.useMemo)(() => {
|
|
2579
3012
|
if (!resolvedRowPinning || !resolvedRowPinning.top?.length && !resolvedRowPinning.bottom?.length) {
|
|
@@ -2581,7 +3014,7 @@ function BoltTable({
|
|
|
2581
3014
|
return {
|
|
2582
3015
|
pinnedTopRows: [],
|
|
2583
3016
|
pinnedBottomRows: [],
|
|
2584
|
-
unpinnedProcessedData:
|
|
3017
|
+
unpinnedProcessedData: aiProcessedData
|
|
2585
3018
|
};
|
|
2586
3019
|
}
|
|
2587
3020
|
const topKeySet = new Set((resolvedRowPinning.top ?? []).map(String));
|
|
@@ -2591,7 +3024,7 @@ function BoltTable({
|
|
|
2591
3024
|
const topMap = /* @__PURE__ */ new Map();
|
|
2592
3025
|
const bottomMap = /* @__PURE__ */ new Map();
|
|
2593
3026
|
const rest = [];
|
|
2594
|
-
|
|
3027
|
+
aiProcessedData.forEach((row, idx) => {
|
|
2595
3028
|
if (row == null) return;
|
|
2596
3029
|
const key = getSafeRowKey(row, idx);
|
|
2597
3030
|
if (topKeySet.has(key)) {
|
|
@@ -2631,7 +3064,7 @@ function BoltTable({
|
|
|
2631
3064
|
unpinnedProcessedData: rest
|
|
2632
3065
|
};
|
|
2633
3066
|
}, [
|
|
2634
|
-
|
|
3067
|
+
aiProcessedData,
|
|
2635
3068
|
resolvedRowPinning,
|
|
2636
3069
|
getSafeRowKey,
|
|
2637
3070
|
keepPinnedRowsAcrossPages
|
|
@@ -2700,7 +3133,7 @@ function BoltTable({
|
|
|
2700
3133
|
return unpinnedProcessedData.slice(start, start + pgSize);
|
|
2701
3134
|
}, [unpinnedProcessedData, needsClientPagination, pgCurrent, pgSize]);
|
|
2702
3135
|
const shimmerCount = pgEnabled ? pgSize : 15;
|
|
2703
|
-
const showShimmer = isLoading &&
|
|
3136
|
+
const showShimmer = isLoading && aiProcessedData.length === 0;
|
|
2704
3137
|
const shimmerRowKeyField = typeof rowKey === "string" ? rowKey : "id";
|
|
2705
3138
|
const shimmerData = (0, import_react4.useMemo)(() => {
|
|
2706
3139
|
if (!showShimmer) return null;
|
|
@@ -2984,49 +3417,291 @@ function BoltTable({
|
|
|
2984
3417
|
border: 1px dashed ${accentColor} !important;
|
|
2985
3418
|
}
|
|
2986
3419
|
${onRowClick ? "[data-bt-cell] { cursor: pointer; }" : ""}
|
|
3420
|
+
@keyframes bt-spin { to { transform: rotate(360deg); } }
|
|
3421
|
+
@keyframes bt-ai-shimmer {
|
|
3422
|
+
0% { background-position: -200% 0; }
|
|
3423
|
+
100% { background-position: 200% 0; }
|
|
3424
|
+
}
|
|
2987
3425
|
` }),
|
|
2988
|
-
(!hideGlobalSearch || showColumnSettings) && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
3426
|
+
(!hideGlobalSearch || showColumnSettings || aiMode) && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
2989
3427
|
"div",
|
|
2990
3428
|
{
|
|
2991
3429
|
style: {
|
|
3430
|
+
position: "relative",
|
|
2992
3431
|
display: "flex",
|
|
2993
3432
|
alignItems: "center",
|
|
2994
3433
|
gap: 8,
|
|
2995
3434
|
padding: "6px 8px",
|
|
2996
3435
|
borderBottom: "1px solid rgba(128,128,128,0.2)",
|
|
2997
3436
|
fontSize: 12,
|
|
2998
|
-
flexShrink: 0
|
|
3437
|
+
flexShrink: 0,
|
|
3438
|
+
overflow: "hidden"
|
|
2999
3439
|
},
|
|
3000
3440
|
children: [
|
|
3001
|
-
|
|
3441
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
3002
3442
|
"div",
|
|
3003
3443
|
{
|
|
3004
3444
|
style: {
|
|
3005
3445
|
display: "flex",
|
|
3006
3446
|
alignItems: "center",
|
|
3007
|
-
gap:
|
|
3447
|
+
gap: 8,
|
|
3008
3448
|
flex: "1 1 0%",
|
|
3009
|
-
|
|
3449
|
+
opacity: aiBarOpen ? 0 : 1,
|
|
3450
|
+
transform: aiBarOpen ? "scale(0.97)" : "scale(1)",
|
|
3451
|
+
transition: "opacity 0.25s ease, transform 0.25s ease",
|
|
3452
|
+
pointerEvents: aiBarOpen ? "none" : "auto",
|
|
3453
|
+
minWidth: 0
|
|
3454
|
+
},
|
|
3455
|
+
children: [
|
|
3456
|
+
!hideGlobalSearch && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
3457
|
+
"div",
|
|
3458
|
+
{
|
|
3459
|
+
style: {
|
|
3460
|
+
display: "flex",
|
|
3461
|
+
alignItems: "center",
|
|
3462
|
+
gap: 4,
|
|
3463
|
+
flex: "1 1 0%",
|
|
3464
|
+
position: "relative"
|
|
3465
|
+
},
|
|
3466
|
+
children: [
|
|
3467
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3468
|
+
"span",
|
|
3469
|
+
{
|
|
3470
|
+
style: {
|
|
3471
|
+
display: "flex",
|
|
3472
|
+
color: "GrayText",
|
|
3473
|
+
flexShrink: 0
|
|
3474
|
+
},
|
|
3475
|
+
children: icons?.search ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SearchIcon, { style: { width: 14, height: 14 } })
|
|
3476
|
+
}
|
|
3477
|
+
),
|
|
3478
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3479
|
+
"input",
|
|
3480
|
+
{
|
|
3481
|
+
type: "text",
|
|
3482
|
+
placeholder: "Search all columns...",
|
|
3483
|
+
value: globalSearchValue ?? internalGlobalSearch,
|
|
3484
|
+
onChange: (e) => {
|
|
3485
|
+
const v = e.target.value;
|
|
3486
|
+
if (onGlobalSearchChange) onGlobalSearchChange(v);
|
|
3487
|
+
else setInternalGlobalSearch(v);
|
|
3488
|
+
},
|
|
3489
|
+
style: {
|
|
3490
|
+
flex: "1 1 0%",
|
|
3491
|
+
border: "none",
|
|
3492
|
+
outline: "none",
|
|
3493
|
+
background: "transparent",
|
|
3494
|
+
font: "inherit",
|
|
3495
|
+
color: "inherit",
|
|
3496
|
+
padding: "4px 6px",
|
|
3497
|
+
minWidth: 0
|
|
3498
|
+
}
|
|
3499
|
+
}
|
|
3500
|
+
),
|
|
3501
|
+
(globalSearchValue ?? internalGlobalSearch) && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3502
|
+
"button",
|
|
3503
|
+
{
|
|
3504
|
+
type: "button",
|
|
3505
|
+
onClick: () => {
|
|
3506
|
+
if (onGlobalSearchChange) onGlobalSearchChange("");
|
|
3507
|
+
else setInternalGlobalSearch("");
|
|
3508
|
+
},
|
|
3509
|
+
style: {
|
|
3510
|
+
display: "flex",
|
|
3511
|
+
alignItems: "center",
|
|
3512
|
+
justifyContent: "center",
|
|
3513
|
+
background: "none",
|
|
3514
|
+
border: "none",
|
|
3515
|
+
cursor: "pointer",
|
|
3516
|
+
padding: 2,
|
|
3517
|
+
color: "GrayText",
|
|
3518
|
+
flexShrink: 0
|
|
3519
|
+
},
|
|
3520
|
+
children: icons?.close ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(XIcon, { style: { width: 12, height: 12 } })
|
|
3521
|
+
}
|
|
3522
|
+
)
|
|
3523
|
+
]
|
|
3524
|
+
}
|
|
3525
|
+
),
|
|
3526
|
+
toolbarContent,
|
|
3527
|
+
showColumnSettings && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { position: "relative", flexShrink: 0 }, children: [
|
|
3528
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
3529
|
+
"button",
|
|
3530
|
+
{
|
|
3531
|
+
type: "button",
|
|
3532
|
+
onClick: () => setShowColumnPicker((p) => !p),
|
|
3533
|
+
style: {
|
|
3534
|
+
display: "flex",
|
|
3535
|
+
alignItems: "center",
|
|
3536
|
+
justifyContent: "center",
|
|
3537
|
+
background: "none",
|
|
3538
|
+
border: "1px solid rgba(128,128,128,0.2)",
|
|
3539
|
+
borderRadius: 4,
|
|
3540
|
+
cursor: "pointer",
|
|
3541
|
+
padding: "4px 6px",
|
|
3542
|
+
color: "inherit",
|
|
3543
|
+
gap: 4,
|
|
3544
|
+
fontSize: 12
|
|
3545
|
+
},
|
|
3546
|
+
title: "Column settings",
|
|
3547
|
+
children: [
|
|
3548
|
+
icons?.columns ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ColumnsIcon, { style: { width: 14, height: 14 } }),
|
|
3549
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: columnSettingsLabel ?? "Columns" })
|
|
3550
|
+
]
|
|
3551
|
+
}
|
|
3552
|
+
),
|
|
3553
|
+
showColumnPicker && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3554
|
+
"div",
|
|
3555
|
+
{
|
|
3556
|
+
ref: columnPickerRef,
|
|
3557
|
+
style: {
|
|
3558
|
+
position: "absolute",
|
|
3559
|
+
top: "100%",
|
|
3560
|
+
right: 0,
|
|
3561
|
+
zIndex: 99999,
|
|
3562
|
+
minWidth: 200,
|
|
3563
|
+
maxHeight: 320,
|
|
3564
|
+
overflowY: "auto",
|
|
3565
|
+
borderRadius: 8,
|
|
3566
|
+
border: "1px solid rgba(128,128,128,0.2)",
|
|
3567
|
+
boxShadow: "0 4px 24px rgba(0,0,0,0.12)",
|
|
3568
|
+
backdropFilter: "blur(16px)",
|
|
3569
|
+
WebkitBackdropFilter: "blur(16px)",
|
|
3570
|
+
backgroundColor: "rgba(128,128,128,0.08)",
|
|
3571
|
+
padding: "4px 0",
|
|
3572
|
+
marginTop: 4
|
|
3573
|
+
},
|
|
3574
|
+
children: initialColumns.filter(
|
|
3575
|
+
(c) => c.key !== "__select__" && c.key !== "__expand__"
|
|
3576
|
+
).map((col) => {
|
|
3577
|
+
const current = columns.find(
|
|
3578
|
+
(c) => c.key === col.key
|
|
3579
|
+
);
|
|
3580
|
+
const isHidden = current?.hidden ?? false;
|
|
3581
|
+
const isPinned = !!current?.pinned;
|
|
3582
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
3583
|
+
"label",
|
|
3584
|
+
{
|
|
3585
|
+
style: {
|
|
3586
|
+
display: "flex",
|
|
3587
|
+
alignItems: "center",
|
|
3588
|
+
gap: 8,
|
|
3589
|
+
padding: "6px 12px",
|
|
3590
|
+
cursor: isPinned ? "not-allowed" : "pointer",
|
|
3591
|
+
opacity: isPinned ? 0.5 : 1,
|
|
3592
|
+
fontSize: 12
|
|
3593
|
+
},
|
|
3594
|
+
children: [
|
|
3595
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3596
|
+
"input",
|
|
3597
|
+
{
|
|
3598
|
+
type: "checkbox",
|
|
3599
|
+
checked: !isHidden,
|
|
3600
|
+
disabled: isPinned,
|
|
3601
|
+
onChange: () => {
|
|
3602
|
+
if (isPinned) return;
|
|
3603
|
+
handleToggleHide(col.key);
|
|
3604
|
+
},
|
|
3605
|
+
style: {
|
|
3606
|
+
cursor: isPinned ? "not-allowed" : "pointer",
|
|
3607
|
+
accentColor
|
|
3608
|
+
}
|
|
3609
|
+
}
|
|
3610
|
+
),
|
|
3611
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3612
|
+
"span",
|
|
3613
|
+
{
|
|
3614
|
+
style: {
|
|
3615
|
+
overflow: "hidden",
|
|
3616
|
+
textOverflow: "ellipsis",
|
|
3617
|
+
whiteSpace: "nowrap"
|
|
3618
|
+
},
|
|
3619
|
+
children: typeof col.title === "string" ? col.title : col.key
|
|
3620
|
+
}
|
|
3621
|
+
)
|
|
3622
|
+
]
|
|
3623
|
+
},
|
|
3624
|
+
col.key
|
|
3625
|
+
);
|
|
3626
|
+
})
|
|
3627
|
+
}
|
|
3628
|
+
)
|
|
3629
|
+
] }),
|
|
3630
|
+
aiMode && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
3631
|
+
"button",
|
|
3632
|
+
{
|
|
3633
|
+
type: "button",
|
|
3634
|
+
onClick: () => setAiBarOpen(true),
|
|
3635
|
+
style: {
|
|
3636
|
+
display: "flex",
|
|
3637
|
+
alignItems: "center",
|
|
3638
|
+
justifyContent: "center",
|
|
3639
|
+
gap: 4,
|
|
3640
|
+
background: `linear-gradient(135deg, ${accentColor}18, ${accentColor}08)`,
|
|
3641
|
+
border: `1px solid ${accentColor}40`,
|
|
3642
|
+
borderRadius: 4,
|
|
3643
|
+
cursor: "pointer",
|
|
3644
|
+
padding: "4px 8px",
|
|
3645
|
+
color: accentColor,
|
|
3646
|
+
fontSize: 12,
|
|
3647
|
+
fontWeight: 500,
|
|
3648
|
+
flexShrink: 0,
|
|
3649
|
+
transition: "all 0.2s ease"
|
|
3650
|
+
},
|
|
3651
|
+
title: "Ask AI",
|
|
3652
|
+
children: [
|
|
3653
|
+
icons?.sparkles ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SparklesIcon, { style: { width: 14, height: 14 } }),
|
|
3654
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: aiButtonLabel ?? "Ask AI" })
|
|
3655
|
+
]
|
|
3656
|
+
}
|
|
3657
|
+
)
|
|
3658
|
+
]
|
|
3659
|
+
}
|
|
3660
|
+
),
|
|
3661
|
+
aiMode && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
3662
|
+
"div",
|
|
3663
|
+
{
|
|
3664
|
+
style: {
|
|
3665
|
+
position: "absolute",
|
|
3666
|
+
inset: 0,
|
|
3667
|
+
display: "flex",
|
|
3668
|
+
alignItems: "center",
|
|
3669
|
+
gap: 8,
|
|
3670
|
+
padding: "4px 8px",
|
|
3671
|
+
opacity: aiBarOpen ? 1 : 0,
|
|
3672
|
+
transform: aiBarOpen ? "translateX(0)" : "translateX(40px)",
|
|
3673
|
+
transition: "opacity 0.3s cubic-bezier(0.4,0,0.2,1), transform 0.3s cubic-bezier(0.4,0,0.2,1)",
|
|
3674
|
+
pointerEvents: aiBarOpen ? "auto" : "none",
|
|
3675
|
+
zIndex: 2,
|
|
3676
|
+
background: "inherit",
|
|
3677
|
+
backdropFilter: "blur(12px)",
|
|
3678
|
+
WebkitBackdropFilter: "blur(12px)"
|
|
3010
3679
|
},
|
|
3011
3680
|
children: [
|
|
3012
3681
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3013
3682
|
"span",
|
|
3014
3683
|
{
|
|
3015
|
-
style: {
|
|
3016
|
-
|
|
3684
|
+
style: {
|
|
3685
|
+
display: "flex",
|
|
3686
|
+
color: accentColor,
|
|
3687
|
+
flexShrink: 0
|
|
3688
|
+
},
|
|
3689
|
+
children: icons?.sparkles ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SparklesIcon, { style: { width: 16, height: 16 } })
|
|
3017
3690
|
}
|
|
3018
3691
|
),
|
|
3019
3692
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3020
3693
|
"input",
|
|
3021
3694
|
{
|
|
3695
|
+
ref: aiInputRef,
|
|
3022
3696
|
type: "text",
|
|
3023
|
-
placeholder:
|
|
3024
|
-
value:
|
|
3025
|
-
onChange: (e) =>
|
|
3026
|
-
|
|
3027
|
-
if (
|
|
3028
|
-
|
|
3697
|
+
placeholder: aiPlaceholder,
|
|
3698
|
+
value: aiQuery,
|
|
3699
|
+
onChange: (e) => setAiQuery(e.target.value),
|
|
3700
|
+
onKeyDown: (e) => {
|
|
3701
|
+
if (e.key === "Enter" && !aiLoading) handleAISubmit();
|
|
3702
|
+
if (e.key === "Escape") handleAIBarClose();
|
|
3029
3703
|
},
|
|
3704
|
+
disabled: aiLoading,
|
|
3030
3705
|
style: {
|
|
3031
3706
|
flex: "1 1 0%",
|
|
3032
3707
|
border: "none",
|
|
@@ -3035,18 +3710,51 @@ function BoltTable({
|
|
|
3035
3710
|
font: "inherit",
|
|
3036
3711
|
color: "inherit",
|
|
3037
3712
|
padding: "4px 6px",
|
|
3038
|
-
minWidth: 0
|
|
3713
|
+
minWidth: 0,
|
|
3714
|
+
fontSize: 12
|
|
3039
3715
|
}
|
|
3040
3716
|
}
|
|
3041
3717
|
),
|
|
3042
|
-
|
|
3718
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3043
3719
|
"button",
|
|
3044
3720
|
{
|
|
3045
3721
|
type: "button",
|
|
3046
|
-
onClick:
|
|
3047
|
-
|
|
3048
|
-
|
|
3722
|
+
onClick: handleAISubmit,
|
|
3723
|
+
disabled: aiLoading || !aiQuery.trim(),
|
|
3724
|
+
style: {
|
|
3725
|
+
display: "flex",
|
|
3726
|
+
alignItems: "center",
|
|
3727
|
+
justifyContent: "center",
|
|
3728
|
+
background: aiQuery.trim() ? accentColor : "rgba(128,128,128,0.15)",
|
|
3729
|
+
border: "none",
|
|
3730
|
+
borderRadius: 4,
|
|
3731
|
+
cursor: aiLoading || !aiQuery.trim() ? "not-allowed" : "pointer",
|
|
3732
|
+
padding: "4px 8px",
|
|
3733
|
+
color: aiQuery.trim() ? "#fff" : "GrayText",
|
|
3734
|
+
transition: "all 0.2s ease",
|
|
3735
|
+
flexShrink: 0,
|
|
3736
|
+
gap: 4,
|
|
3737
|
+
fontSize: 12,
|
|
3738
|
+
opacity: aiLoading ? 0.7 : 1
|
|
3049
3739
|
},
|
|
3740
|
+
title: "Send",
|
|
3741
|
+
children: aiLoading ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, { children: icons?.loader ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3742
|
+
LoaderIcon,
|
|
3743
|
+
{
|
|
3744
|
+
style: {
|
|
3745
|
+
width: 14,
|
|
3746
|
+
height: 14,
|
|
3747
|
+
animation: "bt-spin 1s linear infinite"
|
|
3748
|
+
}
|
|
3749
|
+
}
|
|
3750
|
+
) }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, { children: icons?.send ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SendIcon, { style: { width: 14, height: 14 } }) })
|
|
3751
|
+
}
|
|
3752
|
+
),
|
|
3753
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3754
|
+
"button",
|
|
3755
|
+
{
|
|
3756
|
+
type: "button",
|
|
3757
|
+
onClick: handleAIBarClose,
|
|
3050
3758
|
style: {
|
|
3051
3759
|
display: "flex",
|
|
3052
3760
|
alignItems: "center",
|
|
@@ -3058,114 +3766,96 @@ function BoltTable({
|
|
|
3058
3766
|
color: "GrayText",
|
|
3059
3767
|
flexShrink: 0
|
|
3060
3768
|
},
|
|
3061
|
-
|
|
3769
|
+
title: "Close AI",
|
|
3770
|
+
children: icons?.close ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(XIcon, { style: { width: 14, height: 14 } })
|
|
3062
3771
|
}
|
|
3063
3772
|
)
|
|
3064
3773
|
]
|
|
3065
3774
|
}
|
|
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
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3151
|
-
"span",
|
|
3152
|
-
{
|
|
3153
|
-
style: {
|
|
3154
|
-
overflow: "hidden",
|
|
3155
|
-
textOverflow: "ellipsis",
|
|
3156
|
-
whiteSpace: "nowrap"
|
|
3157
|
-
},
|
|
3158
|
-
children: typeof col.title === "string" ? col.title : col.key
|
|
3159
|
-
}
|
|
3160
|
-
)
|
|
3161
|
-
]
|
|
3162
|
-
},
|
|
3163
|
-
col.key
|
|
3164
|
-
);
|
|
3165
|
-
})
|
|
3166
|
-
}
|
|
3167
|
-
)
|
|
3168
|
-
] })
|
|
3775
|
+
)
|
|
3776
|
+
]
|
|
3777
|
+
}
|
|
3778
|
+
),
|
|
3779
|
+
aiResult && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
3780
|
+
"div",
|
|
3781
|
+
{
|
|
3782
|
+
style: {
|
|
3783
|
+
display: "flex",
|
|
3784
|
+
alignItems: "center",
|
|
3785
|
+
gap: 8,
|
|
3786
|
+
padding: "6px 12px",
|
|
3787
|
+
fontSize: 12,
|
|
3788
|
+
borderBottom: "1px solid rgba(128,128,128,0.2)",
|
|
3789
|
+
background: `linear-gradient(90deg, ${accentColor}08, transparent)`,
|
|
3790
|
+
flexShrink: 0
|
|
3791
|
+
},
|
|
3792
|
+
children: [
|
|
3793
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: { color: accentColor, display: "flex", flexShrink: 0 }, children: icons?.sparkles ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SparklesIcon, { style: { width: 14, height: 14 } }) }),
|
|
3794
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: { flex: "1 1 0%", opacity: 0.85 }, children: aiResult.message }),
|
|
3795
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
3796
|
+
"button",
|
|
3797
|
+
{
|
|
3798
|
+
type: "button",
|
|
3799
|
+
onClick: handleAIClear,
|
|
3800
|
+
style: {
|
|
3801
|
+
display: "flex",
|
|
3802
|
+
alignItems: "center",
|
|
3803
|
+
gap: 4,
|
|
3804
|
+
background: "none",
|
|
3805
|
+
border: "1px solid rgba(128,128,128,0.2)",
|
|
3806
|
+
borderRadius: 4,
|
|
3807
|
+
cursor: "pointer",
|
|
3808
|
+
padding: "2px 8px",
|
|
3809
|
+
color: "inherit",
|
|
3810
|
+
fontSize: 11,
|
|
3811
|
+
flexShrink: 0,
|
|
3812
|
+
opacity: 0.7
|
|
3813
|
+
},
|
|
3814
|
+
title: "Clear AI results",
|
|
3815
|
+
children: [
|
|
3816
|
+
icons?.close ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(XIcon, { style: { width: 10, height: 10 } }),
|
|
3817
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Clear" })
|
|
3818
|
+
]
|
|
3819
|
+
}
|
|
3820
|
+
)
|
|
3821
|
+
]
|
|
3822
|
+
}
|
|
3823
|
+
),
|
|
3824
|
+
aiError && !aiResult && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
3825
|
+
"div",
|
|
3826
|
+
{
|
|
3827
|
+
style: {
|
|
3828
|
+
display: "flex",
|
|
3829
|
+
alignItems: "center",
|
|
3830
|
+
gap: 8,
|
|
3831
|
+
padding: "6px 12px",
|
|
3832
|
+
fontSize: 12,
|
|
3833
|
+
borderBottom: "1px solid rgba(239,68,68,0.2)",
|
|
3834
|
+
background: "rgba(239,68,68,0.06)",
|
|
3835
|
+
color: "#ef4444",
|
|
3836
|
+
flexShrink: 0
|
|
3837
|
+
},
|
|
3838
|
+
children: [
|
|
3839
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: { flex: "1 1 0%" }, children: aiError }),
|
|
3840
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3841
|
+
"button",
|
|
3842
|
+
{
|
|
3843
|
+
type: "button",
|
|
3844
|
+
onClick: () => setAiError(null),
|
|
3845
|
+
style: {
|
|
3846
|
+
display: "flex",
|
|
3847
|
+
alignItems: "center",
|
|
3848
|
+
justifyContent: "center",
|
|
3849
|
+
background: "none",
|
|
3850
|
+
border: "none",
|
|
3851
|
+
cursor: "pointer",
|
|
3852
|
+
padding: 2,
|
|
3853
|
+
color: "#ef4444",
|
|
3854
|
+
flexShrink: 0
|
|
3855
|
+
},
|
|
3856
|
+
children: icons?.close ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(XIcon, { style: { width: 12, height: 12 } })
|
|
3857
|
+
}
|
|
3858
|
+
)
|
|
3169
3859
|
]
|
|
3170
3860
|
}
|
|
3171
3861
|
),
|
|
@@ -3667,14 +4357,20 @@ function BoltTable({
|
|
|
3667
4357
|
gridTemplateColumns,
|
|
3668
4358
|
headerHeight: HEADER_HEIGHT,
|
|
3669
4359
|
rowClassName,
|
|
3670
|
-
rowStyle,
|
|
4360
|
+
rowStyle: aiStyleOps.length > 0 ? (record, index) => {
|
|
4361
|
+
const base = rowStyle ? rowStyle(record, index) : void 0;
|
|
4362
|
+
const ai = getAIRowStyleForRecord(record);
|
|
4363
|
+
if (!base && !ai) return {};
|
|
4364
|
+
return { ...base, ...ai };
|
|
4365
|
+
} : rowStyle,
|
|
3671
4366
|
bodyGridRow: hasColumnGroups ? 3 : 2,
|
|
3672
4367
|
onEdit,
|
|
3673
4368
|
editingCell,
|
|
3674
4369
|
onEditComplete: handleEditComplete,
|
|
3675
4370
|
enableDynamicRowHeight,
|
|
3676
4371
|
onRowHeightChange: handleRowHeightChange,
|
|
3677
|
-
columnGridIndexMap
|
|
4372
|
+
columnGridIndexMap,
|
|
4373
|
+
cellStyleFn: aiCellStyleOps.length > 0 ? (record, columnKey) => getAICellStyleForRecord(record, columnKey) : void 0
|
|
3678
4374
|
}
|
|
3679
4375
|
)
|
|
3680
4376
|
]
|
|
@@ -4292,10 +4988,16 @@ function BoltTable({
|
|
|
4292
4988
|
})()
|
|
4293
4989
|
] });
|
|
4294
4990
|
}
|
|
4991
|
+
|
|
4992
|
+
// src/types.ts
|
|
4993
|
+
function defineConfig(config) {
|
|
4994
|
+
return config;
|
|
4995
|
+
}
|
|
4295
4996
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4296
4997
|
0 && (module.exports = {
|
|
4297
4998
|
BoltTable,
|
|
4298
4999
|
DraggableHeader,
|
|
4299
5000
|
ResizeOverlay,
|
|
4300
|
-
TableBody
|
|
5001
|
+
TableBody,
|
|
5002
|
+
defineConfig
|
|
4301
5003
|
});
|