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.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: processedData
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
- processedData.forEach((row, idx) => {
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
- processedData,
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 && processedData.length === 0;
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
- !hideGlobalSearch && /* @__PURE__ */ jsxs5(
3412
+ /* @__PURE__ */ jsxs5(
2974
3413
  "div",
2975
3414
  {
2976
3415
  style: {
2977
3416
  display: "flex",
2978
3417
  alignItems: "center",
2979
- gap: 4,
3418
+ gap: 8,
2980
3419
  flex: "1 1 0%",
2981
- position: "relative"
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: { display: "flex", color: "GrayText", flexShrink: 0 },
2988
- children: icons?.search ?? /* @__PURE__ */ jsx5(SearchIcon, { style: { width: 14, height: 14 } })
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: "Search all columns...",
2996
- value: globalSearchValue ?? internalGlobalSearch,
2997
- onChange: (e) => {
2998
- const v = e.target.value;
2999
- if (onGlobalSearchChange) onGlobalSearchChange(v);
3000
- else setInternalGlobalSearch(v);
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
- (globalSearchValue ?? internalGlobalSearch) && /* @__PURE__ */ jsx5(
3689
+ /* @__PURE__ */ jsx5(
3015
3690
  "button",
3016
3691
  {
3017
3692
  type: "button",
3018
- onClick: () => {
3019
- if (onGlobalSearchChange) onGlobalSearchChange("");
3020
- else setInternalGlobalSearch("");
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
- children: icons?.close ?? /* @__PURE__ */ jsx5(XIcon, { style: { width: 12, height: 12 } })
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
- toolbarContent,
3040
- showColumnSettings && /* @__PURE__ */ jsxs5("div", { style: { position: "relative", flexShrink: 0 }, children: [
3041
- /* @__PURE__ */ jsxs5(
3042
- "button",
3043
- {
3044
- type: "button",
3045
- onClick: () => setShowColumnPicker((p) => !p),
3046
- style: {
3047
- display: "flex",
3048
- alignItems: "center",
3049
- justifyContent: "center",
3050
- background: "none",
3051
- border: "1px solid rgba(128,128,128,0.2)",
3052
- borderRadius: 4,
3053
- cursor: "pointer",
3054
- padding: "4px 6px",
3055
- color: "inherit",
3056
- gap: 4,
3057
- fontSize: 12
3058
- },
3059
- title: "Column settings",
3060
- children: [
3061
- icons?.columns ?? /* @__PURE__ */ jsx5(ColumnsIcon, { style: { width: 14, height: 14 } }),
3062
- /* @__PURE__ */ jsx5("span", { children: columnSettingsLabel ?? "Columns" })
3063
- ]
3064
- }
3065
- ),
3066
- showColumnPicker && /* @__PURE__ */ jsx5(
3067
- "div",
3068
- {
3069
- ref: columnPickerRef,
3070
- style: {
3071
- position: "absolute",
3072
- top: "100%",
3073
- right: 0,
3074
- zIndex: 99999,
3075
- minWidth: 200,
3076
- maxHeight: 320,
3077
- overflowY: "auto",
3078
- borderRadius: 8,
3079
- border: "1px solid rgba(128,128,128,0.2)",
3080
- boxShadow: "0 4px 24px rgba(0,0,0,0.12)",
3081
- backdropFilter: "blur(16px)",
3082
- WebkitBackdropFilter: "blur(16px)",
3083
- backgroundColor: "rgba(128,128,128,0.08)",
3084
- padding: "4px 0",
3085
- marginTop: 4
3086
- },
3087
- children: initialColumns.filter(
3088
- (c) => c.key !== "__select__" && c.key !== "__expand__"
3089
- ).map((col) => {
3090
- const current = columns.find((c) => c.key === col.key);
3091
- const isHidden = current?.hidden ?? false;
3092
- const isPinned = !!current?.pinned;
3093
- return /* @__PURE__ */ jsxs5(
3094
- "label",
3095
- {
3096
- style: {
3097
- display: "flex",
3098
- alignItems: "center",
3099
- gap: 8,
3100
- padding: "6px 12px",
3101
- cursor: isPinned ? "not-allowed" : "pointer",
3102
- opacity: isPinned ? 0.5 : 1,
3103
- fontSize: 12
3104
- },
3105
- children: [
3106
- /* @__PURE__ */ jsx5(
3107
- "input",
3108
- {
3109
- type: "checkbox",
3110
- checked: !isHidden,
3111
- disabled: isPinned,
3112
- onChange: () => {
3113
- if (isPinned) return;
3114
- handleToggleHide(col.key);
3115
- },
3116
- style: {
3117
- cursor: isPinned ? "not-allowed" : "pointer",
3118
- accentColor
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
  };