bolt-table 0.1.37 → 0.1.39
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 +34 -4
- package/dist/index.d.ts +34 -4
- package/dist/index.js +635 -77
- package/dist/index.mjs +635 -77
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -149,7 +149,8 @@ var DraggableHeader = React.memo(
|
|
|
149
149
|
headerGridRow = 1,
|
|
150
150
|
headerHeight = 36,
|
|
151
151
|
stickyTop = 0,
|
|
152
|
-
isFirstColumn = false
|
|
152
|
+
isFirstColumn = false,
|
|
153
|
+
onAutoFitColumn
|
|
153
154
|
}) => {
|
|
154
155
|
const effectivelySortable = isColumnSortable(column);
|
|
155
156
|
const effectivelyFilterable = !disabledFilters && isColumnFilterable(column);
|
|
@@ -217,6 +218,12 @@ var DraggableHeader = React.memo(
|
|
|
217
218
|
if (column.pinned) return;
|
|
218
219
|
onResizeStart?.(column.key, e);
|
|
219
220
|
};
|
|
221
|
+
const handleResizeDoubleClick = (e) => {
|
|
222
|
+
e.preventDefault();
|
|
223
|
+
e.stopPropagation();
|
|
224
|
+
if (column.pinned) return;
|
|
225
|
+
onAutoFitColumn?.(column.key);
|
|
226
|
+
};
|
|
220
227
|
const columnWidth = column.width ?? 150;
|
|
221
228
|
const widthPx = `${columnWidth}px`;
|
|
222
229
|
const isPinned = Boolean(column.pinned);
|
|
@@ -364,7 +371,8 @@ var DraggableHeader = React.memo(
|
|
|
364
371
|
padding: 0
|
|
365
372
|
},
|
|
366
373
|
onMouseDown: handleResizeStart,
|
|
367
|
-
|
|
374
|
+
onDoubleClick: handleResizeDoubleClick,
|
|
375
|
+
"aria-label": `Resize ${column.key} column (double-click to auto-fit)`,
|
|
368
376
|
children: /* @__PURE__ */ jsx2(
|
|
369
377
|
"div",
|
|
370
378
|
{
|
|
@@ -676,66 +684,68 @@ function detectColumnType(key, data) {
|
|
|
676
684
|
}
|
|
677
685
|
return { type: "string", sample: sampleStr };
|
|
678
686
|
}
|
|
687
|
+
var cachedSchema = null;
|
|
688
|
+
function buildSchemaFingerprint(columns, dataLen) {
|
|
689
|
+
return columns.filter((c) => c.key !== "__select__" && c.key !== "__expand__").map((c) => c.key).join(",") + `:${dataLen}`;
|
|
690
|
+
}
|
|
679
691
|
function buildSystemPrompt(columns, data) {
|
|
680
|
-
const
|
|
692
|
+
const fingerprint = buildSchemaFingerprint(columns, data.length);
|
|
693
|
+
if (cachedSchema?.fingerprint === fingerprint) {
|
|
694
|
+
return cachedSchema.prompt;
|
|
695
|
+
}
|
|
696
|
+
const cols = columns.filter((c) => c.key !== "__select__" && c.key !== "__expand__");
|
|
697
|
+
const schema = cols.map((c) => {
|
|
681
698
|
const key = c.dataIndex ?? c.key;
|
|
682
699
|
const title = typeof c.title === "string" ? c.title : c.key;
|
|
683
700
|
const info = detectColumnType(key, data);
|
|
684
|
-
|
|
701
|
+
const w = c.width ?? 150;
|
|
702
|
+
const pin = c.pinned ? `, pinned: "${c.pinned}"` : "";
|
|
703
|
+
const hidden = c.hidden ? ", hidden: true" : "";
|
|
704
|
+
const vals = info.sample ? "|vals: " + info.sample : "";
|
|
705
|
+
return ` ${c.key}|${key}|"${title}"|${info.type}|w:${w}${pin}${hidden}${vals}`;
|
|
685
706
|
}).join("\n");
|
|
686
|
-
const sample = data.slice(0,
|
|
707
|
+
const sample = data.slice(0, 3).map((row) => {
|
|
687
708
|
const obj = {};
|
|
688
|
-
for (const col of
|
|
689
|
-
if (col.key === "__select__" || col.key === "__expand__") continue;
|
|
709
|
+
for (const col of cols) {
|
|
690
710
|
const di = col.dataIndex ?? col.key;
|
|
691
711
|
obj[di] = row[di];
|
|
692
712
|
}
|
|
693
713
|
return obj;
|
|
694
714
|
});
|
|
695
|
-
|
|
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:
|
|
715
|
+
const prompt = `Data table AI. Respond ONLY with valid JSON, no markdown/explanation.
|
|
706
716
|
|
|
707
|
-
|
|
708
|
-
|
|
717
|
+
SCHEMA (key|dataIndex|title|type|width|flags|sample):
|
|
718
|
+
${schema}
|
|
709
719
|
|
|
710
|
-
|
|
711
|
-
|
|
720
|
+
SAMPLE (${sample.length}/${data.length} rows):
|
|
721
|
+
${JSON.stringify(sample)}
|
|
712
722
|
|
|
713
|
-
|
|
714
|
-
{ "type": "cellStyle", "column": "<dataIndex>", "conditions": [...], "logic": "and"|"or", "style": { "<cssProp>": "<value>" } }
|
|
723
|
+
COLUMN ORDER: [${cols.map((c) => `"${c.key}"`).join(",")}]
|
|
715
724
|
|
|
716
|
-
|
|
717
|
-
|
|
725
|
+
OPS (combine any):
|
|
726
|
+
filter: {type:"filter",conditions:[{column:"<dataIndex>",op:"<op>",value:<v>}],logic:"and"|"or"}
|
|
727
|
+
sort: {type:"sort",column:"<dataIndex>",direction:"asc"|"desc"}
|
|
728
|
+
rowStyle: {type:"rowStyle",conditions:[...],logic:"and"|"or",style:{cssProp:"val"}}
|
|
729
|
+
cellStyle: {type:"cellStyle",column:"<dataIndex>",conditions:[...],logic:"and"|"or",style:{cssProp:"val"}}
|
|
730
|
+
hideColumns: {type:"hideColumns",columns:["key",...]}
|
|
731
|
+
showColumns: {type:"showColumns",columns:["key",...]}
|
|
732
|
+
resizeColumn: {type:"resizeColumn",column:"<key>",width:<px>}
|
|
733
|
+
reorderColumns: {type:"reorderColumns",order:["key1","key2",...]} (full column order)
|
|
734
|
+
pinColumn: {type:"pinColumn",column:"<key>",pinned:"left"|"right"|false}
|
|
735
|
+
setPage: {type:"setPage",page:<number>}
|
|
718
736
|
|
|
719
|
-
|
|
720
|
-
{ "type": "hideColumns" | "showColumns", "columns": ["<key>", ...] }
|
|
737
|
+
OPS: eq,neq,gt,gte,lt,lte,contains,notContains,startsWith,endsWith,in,notIn
|
|
721
738
|
|
|
722
|
-
|
|
723
|
-
eq, neq, gt, gte, lt, lte, contains, notContains, startsWith, endsWith, in, notIn
|
|
739
|
+
FORMAT: {"operations":[...],"message":"brief description"}
|
|
724
740
|
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
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.`;
|
|
741
|
+
RULES:
|
|
742
|
+
- Use dataIndex for data ops, key for column ops (hide/show/resize/reorder/pin).
|
|
743
|
+
- Colors: semi-transparent rgba. CSS props: camelCase.
|
|
744
|
+
- reorderColumns: provide FULL ordered array of ALL visible column keys.
|
|
745
|
+
- resizeColumn width: integer pixels (min 40, max 800).
|
|
746
|
+
- Combine multiple ops freely. Message: concise plain English.`;
|
|
747
|
+
cachedSchema = { fingerprint, prompt };
|
|
748
|
+
return prompt;
|
|
739
749
|
}
|
|
740
750
|
async function callAI(config, systemPrompt, userQuery) {
|
|
741
751
|
const { provider, apiKey, model, baseUrl, maxTokens = 1024, temperature = 0.1 } = config;
|
|
@@ -901,6 +911,10 @@ function applyAIOperations(data, operations) {
|
|
|
901
911
|
const cellStyleOps = [];
|
|
902
912
|
const hideColumns = [];
|
|
903
913
|
const showColumns = [];
|
|
914
|
+
const resizeOps = [];
|
|
915
|
+
let reorderOp = null;
|
|
916
|
+
const pinOps = [];
|
|
917
|
+
let setPageOp = null;
|
|
904
918
|
for (const op of operations) {
|
|
905
919
|
switch (op.type) {
|
|
906
920
|
case "filter":
|
|
@@ -921,12 +935,24 @@ function applyAIOperations(data, operations) {
|
|
|
921
935
|
case "showColumns":
|
|
922
936
|
showColumns.push(...op.columns);
|
|
923
937
|
break;
|
|
938
|
+
case "resizeColumn":
|
|
939
|
+
resizeOps.push(op);
|
|
940
|
+
break;
|
|
941
|
+
case "reorderColumns":
|
|
942
|
+
reorderOp = op;
|
|
943
|
+
break;
|
|
944
|
+
case "pinColumn":
|
|
945
|
+
pinOps.push(op);
|
|
946
|
+
break;
|
|
947
|
+
case "setPage":
|
|
948
|
+
setPageOp = op;
|
|
949
|
+
break;
|
|
924
950
|
}
|
|
925
951
|
}
|
|
926
952
|
if (sortOp) {
|
|
927
953
|
filteredData = applyAISort(filteredData, sortOp);
|
|
928
954
|
}
|
|
929
|
-
return { filteredData, sortOp, styleOps, cellStyleOps, hideColumns, showColumns };
|
|
955
|
+
return { filteredData, sortOp, styleOps, cellStyleOps, hideColumns, showColumns, resizeOps, reorderOp, pinOps, setPageOp };
|
|
930
956
|
}
|
|
931
957
|
|
|
932
958
|
// src/ResizeOverlay.tsx
|
|
@@ -1443,7 +1469,8 @@ var TableBody = ({
|
|
|
1443
1469
|
enableDynamicRowHeight = false,
|
|
1444
1470
|
onRowHeightChange,
|
|
1445
1471
|
columnGridIndexMap,
|
|
1446
|
-
cellStyleFn
|
|
1472
|
+
cellStyleFn,
|
|
1473
|
+
onRowDragStart
|
|
1447
1474
|
}) => {
|
|
1448
1475
|
const virtualItems = rowVirtualizer.getVirtualItems();
|
|
1449
1476
|
const totalSize = rowVirtualizer.getTotalSize();
|
|
@@ -1525,6 +1552,7 @@ var TableBody = ({
|
|
|
1525
1552
|
"div",
|
|
1526
1553
|
{
|
|
1527
1554
|
"data-row-key": rowKey,
|
|
1555
|
+
"data-row-index": virtualRow.index,
|
|
1528
1556
|
"data-column-key": col.key,
|
|
1529
1557
|
"data-bt-cell": "",
|
|
1530
1558
|
"data-selected": isSelected || void 0,
|
|
@@ -1537,7 +1565,45 @@ var TableBody = ({
|
|
|
1537
1565
|
height: enableDynamicRowHeight ? void 0 : `${virtualRow.size}px`,
|
|
1538
1566
|
minHeight: enableDynamicRowHeight ? `${rowHeight}px` : void 0
|
|
1539
1567
|
},
|
|
1540
|
-
children:
|
|
1568
|
+
children: col.key === "__drag__" && onRowDragStart ? /* @__PURE__ */ jsx4(
|
|
1569
|
+
"div",
|
|
1570
|
+
{
|
|
1571
|
+
style: {
|
|
1572
|
+
height: `${rowHeight}px`,
|
|
1573
|
+
display: "flex",
|
|
1574
|
+
alignItems: "center",
|
|
1575
|
+
justifyContent: "center",
|
|
1576
|
+
borderBottom: "1px solid rgba(128,128,128,0.2)",
|
|
1577
|
+
...rowSty
|
|
1578
|
+
},
|
|
1579
|
+
children: /* @__PURE__ */ jsx4(
|
|
1580
|
+
"span",
|
|
1581
|
+
{
|
|
1582
|
+
"data-bt-row-grip": "",
|
|
1583
|
+
onPointerDown: (e) => {
|
|
1584
|
+
if (e.button !== 0) return;
|
|
1585
|
+
onRowDragStart(virtualRow.index, e);
|
|
1586
|
+
},
|
|
1587
|
+
style: {
|
|
1588
|
+
display: "flex",
|
|
1589
|
+
alignItems: "center",
|
|
1590
|
+
justifyContent: "center",
|
|
1591
|
+
touchAction: "none",
|
|
1592
|
+
width: "100%",
|
|
1593
|
+
height: "100%"
|
|
1594
|
+
},
|
|
1595
|
+
children: /* @__PURE__ */ jsxs4("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
1596
|
+
/* @__PURE__ */ jsx4("circle", { cx: "9", cy: "5", r: "1" }),
|
|
1597
|
+
/* @__PURE__ */ jsx4("circle", { cx: "9", cy: "12", r: "1" }),
|
|
1598
|
+
/* @__PURE__ */ jsx4("circle", { cx: "9", cy: "19", r: "1" }),
|
|
1599
|
+
/* @__PURE__ */ jsx4("circle", { cx: "15", cy: "5", r: "1" }),
|
|
1600
|
+
/* @__PURE__ */ jsx4("circle", { cx: "15", cy: "12", r: "1" }),
|
|
1601
|
+
/* @__PURE__ */ jsx4("circle", { cx: "15", cy: "19", r: "1" })
|
|
1602
|
+
] })
|
|
1603
|
+
}
|
|
1604
|
+
)
|
|
1605
|
+
}
|
|
1606
|
+
) : enableDynamicRowHeight && onRowHeightChange && colIndex === 0 ? /* @__PURE__ */ jsx4(
|
|
1541
1607
|
DynamicRowMeasurer,
|
|
1542
1608
|
{
|
|
1543
1609
|
index: virtualRow.index,
|
|
@@ -2032,7 +2098,9 @@ function BoltTable({
|
|
|
2032
2098
|
onAIQuery,
|
|
2033
2099
|
onAIResponse,
|
|
2034
2100
|
aiPlaceholder = "Ask AI anything about your data...",
|
|
2035
|
-
aiButtonLabel
|
|
2101
|
+
aiButtonLabel,
|
|
2102
|
+
rowDragEnabled = false,
|
|
2103
|
+
onRowReorder
|
|
2036
2104
|
}) {
|
|
2037
2105
|
const data = useMemo2(() => {
|
|
2038
2106
|
if (!Array.isArray(rawData)) return STABLE_EMPTY_DATA;
|
|
@@ -2219,6 +2287,104 @@ function BoltTable({
|
|
|
2219
2287
|
const [aiFilteredDataKeys, setAiFilteredDataKeys] = useState3(null);
|
|
2220
2288
|
const [aiSortKey, setAiSortKey] = useState3(null);
|
|
2221
2289
|
const [aiSortDir, setAiSortDir] = useState3(null);
|
|
2290
|
+
const aiFiltersStorageKey = columnPersistence && typeof columnPersistence === "object" ? `bt-ai-filters-${columnPersistence.storageKey}` : "bt-ai-filters";
|
|
2291
|
+
const [savedAIFilters, setSavedAIFilters] = useState3(() => {
|
|
2292
|
+
try {
|
|
2293
|
+
const raw = localStorage.getItem(aiFiltersStorageKey);
|
|
2294
|
+
return raw ? JSON.parse(raw) : [];
|
|
2295
|
+
} catch {
|
|
2296
|
+
return [];
|
|
2297
|
+
}
|
|
2298
|
+
});
|
|
2299
|
+
const [showSavedFilters, setShowSavedFilters] = useState3(false);
|
|
2300
|
+
const [justSavedFilter, setJustSavedFilter] = useState3(false);
|
|
2301
|
+
const savedFiltersRef = useRef4(null);
|
|
2302
|
+
React4.useEffect(() => {
|
|
2303
|
+
if (!showSavedFilters) return;
|
|
2304
|
+
const close = (e) => {
|
|
2305
|
+
if (savedFiltersRef.current && !savedFiltersRef.current.contains(e.target)) {
|
|
2306
|
+
setShowSavedFilters(false);
|
|
2307
|
+
}
|
|
2308
|
+
};
|
|
2309
|
+
document.addEventListener("mousedown", close);
|
|
2310
|
+
return () => document.removeEventListener("mousedown", close);
|
|
2311
|
+
}, [showSavedFilters]);
|
|
2312
|
+
const saveCurrentAIFilter = useCallback2(() => {
|
|
2313
|
+
if (!aiResult) return;
|
|
2314
|
+
const label = aiQuery || aiResult.message;
|
|
2315
|
+
const entry = { label, operations: aiResult.operations, query: aiQuery };
|
|
2316
|
+
const next = [...savedAIFilters, entry];
|
|
2317
|
+
setSavedAIFilters(next);
|
|
2318
|
+
try {
|
|
2319
|
+
localStorage.setItem(aiFiltersStorageKey, JSON.stringify(next));
|
|
2320
|
+
} catch {
|
|
2321
|
+
}
|
|
2322
|
+
setJustSavedFilter(true);
|
|
2323
|
+
setTimeout(() => setJustSavedFilter(false), 1500);
|
|
2324
|
+
}, [aiResult, aiQuery, savedAIFilters, aiFiltersStorageKey]);
|
|
2325
|
+
const removeSavedFilter = useCallback2((index) => {
|
|
2326
|
+
const next = savedAIFilters.filter((_, i) => i !== index);
|
|
2327
|
+
setSavedAIFilters(next);
|
|
2328
|
+
try {
|
|
2329
|
+
localStorage.setItem(aiFiltersStorageKey, JSON.stringify(next));
|
|
2330
|
+
} catch {
|
|
2331
|
+
}
|
|
2332
|
+
}, [savedAIFilters, aiFiltersStorageKey]);
|
|
2333
|
+
const applySavedFilter = useCallback2((filter) => {
|
|
2334
|
+
const { filteredData, sortOp, styleOps: sOps, cellStyleOps: csOps, hideColumns: hideCols, showColumns: showCols, resizeOps, reorderOp, pinOps, setPageOp } = applyAIOperations(data, filter.operations);
|
|
2335
|
+
setAiStyleOps(sOps);
|
|
2336
|
+
setAiCellStyleOps(csOps);
|
|
2337
|
+
if (filter.operations.some((op) => op.type === "filter")) {
|
|
2338
|
+
const keySet = /* @__PURE__ */ new Set();
|
|
2339
|
+
filteredData.forEach((row, idx) => {
|
|
2340
|
+
const k = typeof rowKey === "function" ? rowKey(row) : String(row[typeof rowKey === "string" ? rowKey : "id"] ?? idx);
|
|
2341
|
+
keySet.add(k);
|
|
2342
|
+
});
|
|
2343
|
+
setAiFilteredDataKeys(keySet);
|
|
2344
|
+
} else {
|
|
2345
|
+
setAiFilteredDataKeys(null);
|
|
2346
|
+
}
|
|
2347
|
+
if (sortOp) {
|
|
2348
|
+
setAiSortKey(sortOp.column);
|
|
2349
|
+
setAiSortDir(sortOp.direction);
|
|
2350
|
+
} else {
|
|
2351
|
+
setAiSortKey(null);
|
|
2352
|
+
setAiSortDir(null);
|
|
2353
|
+
}
|
|
2354
|
+
if (hideCols.length > 0 || showCols.length > 0) {
|
|
2355
|
+
setColumns(
|
|
2356
|
+
(prev) => prev.map((col) => {
|
|
2357
|
+
if (hideCols.includes(col.key)) return { ...col, hidden: true };
|
|
2358
|
+
if (showCols.includes(col.key)) return { ...col, hidden: false };
|
|
2359
|
+
return col;
|
|
2360
|
+
})
|
|
2361
|
+
);
|
|
2362
|
+
}
|
|
2363
|
+
for (const rOp of resizeOps) {
|
|
2364
|
+
const w = Math.max(40, Math.min(800, rOp.width));
|
|
2365
|
+
setColumnWidths((prev) => {
|
|
2366
|
+
const n = new Map(prev);
|
|
2367
|
+
n.set(rOp.column, w);
|
|
2368
|
+
return n;
|
|
2369
|
+
});
|
|
2370
|
+
onColumnResize?.(rOp.column, w);
|
|
2371
|
+
}
|
|
2372
|
+
if (reorderOp) {
|
|
2373
|
+
setColumnOrder(reorderOp.order);
|
|
2374
|
+
onColumnOrderChange?.(reorderOp.order);
|
|
2375
|
+
}
|
|
2376
|
+
for (const pOp of pinOps) {
|
|
2377
|
+
setColumns(
|
|
2378
|
+
(prev) => prev.map((col) => col.key === pOp.column ? { ...col, pinned: pOp.pinned } : col)
|
|
2379
|
+
);
|
|
2380
|
+
onColumnPin?.(pOp.column, pOp.pinned);
|
|
2381
|
+
}
|
|
2382
|
+
if (setPageOp) {
|
|
2383
|
+
setInternalPage(setPageOp.page);
|
|
2384
|
+
}
|
|
2385
|
+
setAiResult({ operations: filter.operations, message: `Applied saved filter: ${filter.label}` });
|
|
2386
|
+
setShowSavedFilters(false);
|
|
2387
|
+
}, [data, rowKey, onColumnResize, onColumnOrderChange, onColumnPin]);
|
|
2222
2388
|
const onAIResponseRef = useRef4(onAIResponse);
|
|
2223
2389
|
onAIResponseRef.current = onAIResponse;
|
|
2224
2390
|
const handleAISubmit = useCallback2(async () => {
|
|
@@ -2240,7 +2406,7 @@ function BoltTable({
|
|
|
2240
2406
|
} else {
|
|
2241
2407
|
throw new Error("AI mode requires either aiConfig or onAIQuery prop");
|
|
2242
2408
|
}
|
|
2243
|
-
const { filteredData, sortOp, styleOps: sOps, cellStyleOps: csOps, hideColumns, showColumns } = applyAIOperations(data, response.operations);
|
|
2409
|
+
const { filteredData, sortOp, styleOps: sOps, cellStyleOps: csOps, hideColumns: hideCols, showColumns: showCols, resizeOps, reorderOp, pinOps, setPageOp } = applyAIOperations(data, response.operations);
|
|
2244
2410
|
setAiStyleOps(sOps);
|
|
2245
2411
|
setAiCellStyleOps(csOps);
|
|
2246
2412
|
if (response.operations.some((op) => op.type === "filter")) {
|
|
@@ -2260,15 +2426,37 @@ function BoltTable({
|
|
|
2260
2426
|
setAiSortKey(null);
|
|
2261
2427
|
setAiSortDir(null);
|
|
2262
2428
|
}
|
|
2263
|
-
if (
|
|
2429
|
+
if (hideCols.length > 0 || showCols.length > 0) {
|
|
2264
2430
|
setColumns(
|
|
2265
2431
|
(prev) => prev.map((col) => {
|
|
2266
|
-
if (
|
|
2267
|
-
if (
|
|
2432
|
+
if (hideCols.includes(col.key)) return { ...col, hidden: true };
|
|
2433
|
+
if (showCols.includes(col.key)) return { ...col, hidden: false };
|
|
2268
2434
|
return col;
|
|
2269
2435
|
})
|
|
2270
2436
|
);
|
|
2271
2437
|
}
|
|
2438
|
+
for (const rOp of resizeOps) {
|
|
2439
|
+
const w = Math.max(40, Math.min(800, rOp.width));
|
|
2440
|
+
setColumnWidths((prev) => {
|
|
2441
|
+
const n = new Map(prev);
|
|
2442
|
+
n.set(rOp.column, w);
|
|
2443
|
+
return n;
|
|
2444
|
+
});
|
|
2445
|
+
onColumnResize?.(rOp.column, w);
|
|
2446
|
+
}
|
|
2447
|
+
if (reorderOp) {
|
|
2448
|
+
setColumnOrder(reorderOp.order);
|
|
2449
|
+
onColumnOrderChange?.(reorderOp.order);
|
|
2450
|
+
}
|
|
2451
|
+
for (const pOp of pinOps) {
|
|
2452
|
+
setColumns(
|
|
2453
|
+
(prev) => prev.map((col) => col.key === pOp.column ? { ...col, pinned: pOp.pinned } : col)
|
|
2454
|
+
);
|
|
2455
|
+
onColumnPin?.(pOp.column, pOp.pinned);
|
|
2456
|
+
}
|
|
2457
|
+
if (setPageOp) {
|
|
2458
|
+
setInternalPage(setPageOp.page);
|
|
2459
|
+
}
|
|
2272
2460
|
setAiResult(response);
|
|
2273
2461
|
onAIResponseRef.current?.(response);
|
|
2274
2462
|
} catch (err) {
|
|
@@ -2346,17 +2534,29 @@ function BoltTable({
|
|
|
2346
2534
|
}, []);
|
|
2347
2535
|
const getRowKey = useCallback2(
|
|
2348
2536
|
(record, index) => {
|
|
2349
|
-
if (record == null) return
|
|
2537
|
+
if (record == null) return `__row_${index}`;
|
|
2350
2538
|
try {
|
|
2351
|
-
if (typeof rowKey === "function")
|
|
2539
|
+
if (typeof rowKey === "function") {
|
|
2540
|
+
const result = rowKey(record);
|
|
2541
|
+
const str = String(result);
|
|
2542
|
+
if (str === "undefined" || str === "null" || str === "NaN" || str === "") {
|
|
2543
|
+
return `__row_${index}`;
|
|
2544
|
+
}
|
|
2545
|
+
return str;
|
|
2546
|
+
}
|
|
2352
2547
|
if (typeof rowKey === "string") {
|
|
2353
2548
|
const val = record[rowKey];
|
|
2354
|
-
|
|
2549
|
+
if (val == null) return `__row_${index}`;
|
|
2550
|
+
const str = String(val);
|
|
2551
|
+
if (str === "undefined" || str === "null" || str === "NaN" || str === "") {
|
|
2552
|
+
return `__row_${index}`;
|
|
2553
|
+
}
|
|
2554
|
+
return str;
|
|
2355
2555
|
}
|
|
2356
2556
|
} catch {
|
|
2357
|
-
return
|
|
2557
|
+
return `__row_${index}`;
|
|
2358
2558
|
}
|
|
2359
|
-
return
|
|
2559
|
+
return `__row_${index}`;
|
|
2360
2560
|
},
|
|
2361
2561
|
[rowKey]
|
|
2362
2562
|
);
|
|
@@ -2390,11 +2590,20 @@ function BoltTable({
|
|
|
2390
2590
|
(record, index) => {
|
|
2391
2591
|
if (record == null) return index;
|
|
2392
2592
|
try {
|
|
2393
|
-
if (typeof rowKey === "function")
|
|
2593
|
+
if (typeof rowKey === "function") {
|
|
2594
|
+
const result = rowKey(record);
|
|
2595
|
+
if (result == null || typeof result === "number" && Number.isNaN(result)) return index;
|
|
2596
|
+
const str = String(result);
|
|
2597
|
+
if (str === "undefined" || str === "null" || str === "NaN" || str === "") return index;
|
|
2598
|
+
return result;
|
|
2599
|
+
}
|
|
2394
2600
|
if (typeof rowKey === "string") {
|
|
2395
2601
|
const val = record[rowKey];
|
|
2602
|
+
if (val == null || typeof val === "number" && Number.isNaN(val)) return index;
|
|
2603
|
+
const str = String(val);
|
|
2604
|
+
if (str === "undefined" || str === "null" || str === "NaN" || str === "") return index;
|
|
2396
2605
|
if (typeof val === "number" || typeof val === "string") return val;
|
|
2397
|
-
return
|
|
2606
|
+
return str;
|
|
2398
2607
|
}
|
|
2399
2608
|
} catch {
|
|
2400
2609
|
return index;
|
|
@@ -2481,6 +2690,19 @@ function BoltTable({
|
|
|
2481
2690
|
};
|
|
2482
2691
|
return [selectionColumn, ...columnsWithExpand];
|
|
2483
2692
|
}, [rowSelection, columnsWithExpand]);
|
|
2693
|
+
const columnsWithDrag = useMemo2(() => {
|
|
2694
|
+
if (!rowDragEnabled || !onRowReorder) return columnsWithSelection;
|
|
2695
|
+
const dragColumn = {
|
|
2696
|
+
key: "__drag__",
|
|
2697
|
+
dataIndex: "__drag__",
|
|
2698
|
+
title: "",
|
|
2699
|
+
width: 36,
|
|
2700
|
+
pinned: "left",
|
|
2701
|
+
hidden: false,
|
|
2702
|
+
render: () => null
|
|
2703
|
+
};
|
|
2704
|
+
return [dragColumn, ...columnsWithSelection];
|
|
2705
|
+
}, [rowDragEnabled, onRowReorder, columnsWithSelection]);
|
|
2484
2706
|
const resizeOverlayRef = useRef4(null);
|
|
2485
2707
|
const tableAreaRef = useRef4(null);
|
|
2486
2708
|
const [scrollAreaWidth, setScrollAreaWidth] = useState3(0);
|
|
@@ -2563,7 +2785,7 @@ function BoltTable({
|
|
|
2563
2785
|
onColumnOrderChangeRef.current = onColumnOrderChange;
|
|
2564
2786
|
const handleColumnDragStart = useCallback2(
|
|
2565
2787
|
(columnKey, e) => {
|
|
2566
|
-
if (columnKey === "__select__" || columnKey === "__expand__") return;
|
|
2788
|
+
if (columnKey === "__select__" || columnKey === "__expand__" || columnKey === "__drag__") return;
|
|
2567
2789
|
const headerEl = e.currentTarget.closest(
|
|
2568
2790
|
"[data-column-key]"
|
|
2569
2791
|
);
|
|
@@ -2598,7 +2820,7 @@ function BoltTable({
|
|
|
2598
2820
|
let newOverId = null;
|
|
2599
2821
|
headers.forEach((h) => {
|
|
2600
2822
|
const key = h.dataset.columnKey;
|
|
2601
|
-
if (!key || key === "__select__" || key === "__expand__" || key === columnKey) {
|
|
2823
|
+
if (!key || key === "__select__" || key === "__expand__" || key === "__drag__" || key === columnKey) {
|
|
2602
2824
|
h.removeAttribute("data-drag-over");
|
|
2603
2825
|
return;
|
|
2604
2826
|
}
|
|
@@ -2650,16 +2872,97 @@ function BoltTable({
|
|
|
2650
2872
|
},
|
|
2651
2873
|
[]
|
|
2652
2874
|
);
|
|
2875
|
+
const rowDragGhostRef = useRef4(null);
|
|
2876
|
+
const rowDragFromRef = useRef4(null);
|
|
2877
|
+
const rowDragOverRef = useRef4(null);
|
|
2878
|
+
const onRowReorderRef = useRef4(onRowReorder);
|
|
2879
|
+
onRowReorderRef.current = onRowReorder;
|
|
2880
|
+
const handleRowDragStart = useCallback2(
|
|
2881
|
+
(rowIndex, e) => {
|
|
2882
|
+
if (!onRowReorderRef.current) return;
|
|
2883
|
+
e.preventDefault();
|
|
2884
|
+
rowDragFromRef.current = rowIndex;
|
|
2885
|
+
rowDragOverRef.current = null;
|
|
2886
|
+
const target = e.currentTarget.closest("[data-row-key]");
|
|
2887
|
+
const rowHeight2 = target?.offsetHeight ?? 40;
|
|
2888
|
+
const ghost = rowDragGhostRef.current;
|
|
2889
|
+
if (ghost) {
|
|
2890
|
+
ghost.textContent = `Row ${rowIndex + 1}`;
|
|
2891
|
+
ghost.style.display = "flex";
|
|
2892
|
+
ghost.style.left = `${e.clientX + 12}px`;
|
|
2893
|
+
ghost.style.top = `${e.clientY - 12}px`;
|
|
2894
|
+
ghost.style.height = `${Math.min(rowHeight2, 36)}px`;
|
|
2895
|
+
}
|
|
2896
|
+
const grabStyle = document.createElement("style");
|
|
2897
|
+
grabStyle.textContent = "* { cursor: grabbing !important; }";
|
|
2898
|
+
document.head.appendChild(grabStyle);
|
|
2899
|
+
const scrollEl = tableAreaRef.current;
|
|
2900
|
+
const onMove = (ev) => {
|
|
2901
|
+
if (ghost) {
|
|
2902
|
+
ghost.style.left = `${ev.clientX + 12}px`;
|
|
2903
|
+
ghost.style.top = `${ev.clientY - 12}px`;
|
|
2904
|
+
}
|
|
2905
|
+
if (!scrollEl) return;
|
|
2906
|
+
const cells = scrollEl.querySelectorAll("[data-bt-cell][data-row-key]");
|
|
2907
|
+
let closestIdx = null;
|
|
2908
|
+
let closestDist = Infinity;
|
|
2909
|
+
cells.forEach((cell) => {
|
|
2910
|
+
const rk = cell.dataset.rowKey;
|
|
2911
|
+
if (!rk) return;
|
|
2912
|
+
const rect = cell.getBoundingClientRect();
|
|
2913
|
+
const midY = rect.top + rect.height / 2;
|
|
2914
|
+
const dist = Math.abs(ev.clientY - midY);
|
|
2915
|
+
if (dist < closestDist) {
|
|
2916
|
+
closestDist = dist;
|
|
2917
|
+
const idxAttr = cell.dataset.rowIndex;
|
|
2918
|
+
if (idxAttr != null) closestIdx = Number(idxAttr);
|
|
2919
|
+
}
|
|
2920
|
+
});
|
|
2921
|
+
scrollEl.querySelectorAll("[data-row-drag-over]").forEach(
|
|
2922
|
+
(el) => el.removeAttribute("data-row-drag-over")
|
|
2923
|
+
);
|
|
2924
|
+
if (closestIdx != null && closestIdx !== rowDragFromRef.current) {
|
|
2925
|
+
rowDragOverRef.current = closestIdx;
|
|
2926
|
+
scrollEl.querySelectorAll(
|
|
2927
|
+
`[data-bt-cell][data-row-index="${closestIdx}"]`
|
|
2928
|
+
).forEach((el) => el.setAttribute("data-row-drag-over", ""));
|
|
2929
|
+
} else {
|
|
2930
|
+
rowDragOverRef.current = null;
|
|
2931
|
+
}
|
|
2932
|
+
};
|
|
2933
|
+
const onUp = () => {
|
|
2934
|
+
document.removeEventListener("pointermove", onMove);
|
|
2935
|
+
document.removeEventListener("pointerup", onUp);
|
|
2936
|
+
grabStyle.remove();
|
|
2937
|
+
if (ghost) ghost.style.display = "none";
|
|
2938
|
+
if (scrollEl) {
|
|
2939
|
+
scrollEl.querySelectorAll("[data-row-drag-over]").forEach(
|
|
2940
|
+
(el) => el.removeAttribute("data-row-drag-over")
|
|
2941
|
+
);
|
|
2942
|
+
}
|
|
2943
|
+
const from = rowDragFromRef.current;
|
|
2944
|
+
const to = rowDragOverRef.current;
|
|
2945
|
+
if (from != null && to != null && from !== to) {
|
|
2946
|
+
onRowReorderRef.current?.(from, to);
|
|
2947
|
+
}
|
|
2948
|
+
rowDragFromRef.current = null;
|
|
2949
|
+
rowDragOverRef.current = null;
|
|
2950
|
+
};
|
|
2951
|
+
document.addEventListener("pointermove", onMove);
|
|
2952
|
+
document.addEventListener("pointerup", onUp);
|
|
2953
|
+
},
|
|
2954
|
+
[]
|
|
2955
|
+
);
|
|
2653
2956
|
const handleResizeStart = (columnKey, e) => {
|
|
2654
2957
|
e.preventDefault();
|
|
2655
2958
|
e.stopPropagation();
|
|
2656
|
-
if (columnKey === "__select__" || columnKey === "__expand__") return;
|
|
2657
|
-
const columnIndex =
|
|
2959
|
+
if (columnKey === "__select__" || columnKey === "__expand__" || columnKey === "__drag__") return;
|
|
2960
|
+
const columnIndex = columnsWithDrag.findIndex(
|
|
2658
2961
|
(col) => col.key === columnKey
|
|
2659
2962
|
);
|
|
2660
2963
|
if (columnIndex === -1) return;
|
|
2661
|
-
if (
|
|
2662
|
-
const column =
|
|
2964
|
+
if (columnsWithDrag[columnIndex].pinned) return;
|
|
2965
|
+
const column = columnsWithDrag[columnIndex];
|
|
2663
2966
|
const startWidth = column.width ?? 150;
|
|
2664
2967
|
resizeStateRef.current = {
|
|
2665
2968
|
columnKey,
|
|
@@ -2716,9 +3019,50 @@ function BoltTable({
|
|
|
2716
3019
|
});
|
|
2717
3020
|
onColumnResize?.(columnKey, finalWidth);
|
|
2718
3021
|
}, [onColumnResize]);
|
|
3022
|
+
const handleAutoFitColumn = useCallback2((columnKey) => {
|
|
3023
|
+
const scrollEl = tableAreaRef.current;
|
|
3024
|
+
if (!scrollEl) return;
|
|
3025
|
+
const col = columnsWithDrag.find((c) => c.key === columnKey);
|
|
3026
|
+
if (!col) return;
|
|
3027
|
+
const headerEl = scrollEl.querySelector(
|
|
3028
|
+
`[data-column-key="${columnKey}"] [data-bt-grip]`
|
|
3029
|
+
)?.parentElement ?? scrollEl.querySelector(`[data-column-key="${columnKey}"]`);
|
|
3030
|
+
let maxWidth = 0;
|
|
3031
|
+
if (headerEl) {
|
|
3032
|
+
const title = typeof col.title === "string" ? col.title : col.key;
|
|
3033
|
+
const canvas = document.createElement("canvas");
|
|
3034
|
+
const ctx = canvas.getContext("2d");
|
|
3035
|
+
if (ctx) {
|
|
3036
|
+
const computedStyle = window.getComputedStyle(headerEl);
|
|
3037
|
+
ctx.font = `${computedStyle.fontWeight} ${computedStyle.fontSize} ${computedStyle.fontFamily}`;
|
|
3038
|
+
maxWidth = ctx.measureText(title).width + 60;
|
|
3039
|
+
}
|
|
3040
|
+
}
|
|
3041
|
+
const cells = scrollEl.querySelectorAll(
|
|
3042
|
+
`[data-bt-cell][data-column-key="${columnKey}"]`
|
|
3043
|
+
);
|
|
3044
|
+
cells.forEach((cell) => {
|
|
3045
|
+
const inner = cell.querySelector("div > div");
|
|
3046
|
+
if (inner) {
|
|
3047
|
+
const scrollW = inner.scrollWidth;
|
|
3048
|
+
if (scrollW > maxWidth) maxWidth = scrollW;
|
|
3049
|
+
}
|
|
3050
|
+
});
|
|
3051
|
+
const finalWidth = Math.max(60, Math.min(Math.ceil(maxWidth) + 24, 800));
|
|
3052
|
+
manuallyResizedRef.current.add(columnKey);
|
|
3053
|
+
React4.startTransition(() => {
|
|
3054
|
+
setColumnWidths((prev) => {
|
|
3055
|
+
const next = new Map(prev);
|
|
3056
|
+
next.set(columnKey, finalWidth);
|
|
3057
|
+
return next;
|
|
3058
|
+
});
|
|
3059
|
+
});
|
|
3060
|
+
onColumnResize?.(columnKey, finalWidth);
|
|
3061
|
+
}, [columnsWithDrag, onColumnResize]);
|
|
2719
3062
|
const { leftPinned, unpinned, rightPinned } = useMemo2(() => {
|
|
2720
|
-
const columnMap = new Map(
|
|
3063
|
+
const columnMap = new Map(columnsWithDrag.map((c) => [c.key, c]));
|
|
2721
3064
|
const systemKeys = [
|
|
3065
|
+
...rowDragEnabled && onRowReorder ? ["__drag__"] : [],
|
|
2722
3066
|
...rowSelection ? ["__select__"] : [],
|
|
2723
3067
|
...expandable ? ["__expand__"] : []
|
|
2724
3068
|
];
|
|
@@ -2730,7 +3074,7 @@ function BoltTable({
|
|
|
2730
3074
|
else center.push(col);
|
|
2731
3075
|
});
|
|
2732
3076
|
return { leftPinned: left, unpinned: center, rightPinned: right };
|
|
2733
|
-
}, [columnOrder,
|
|
3077
|
+
}, [columnOrder, columnsWithDrag, rowSelection, expandable, rowDragEnabled, onRowReorder]);
|
|
2734
3078
|
const orderedColumns = useMemo2(
|
|
2735
3079
|
() => [...leftPinned, ...unpinned, ...rightPinned],
|
|
2736
3080
|
[leftPinned, unpinned, rightPinned]
|
|
@@ -2738,7 +3082,7 @@ function BoltTable({
|
|
|
2738
3082
|
const freshOrderedColumns = useMemo2(() => {
|
|
2739
3083
|
const latestMap = new Map(initialColumnsRef.current.map((c) => [c.key, c]));
|
|
2740
3084
|
return orderedColumns.map((col) => {
|
|
2741
|
-
if (col.key === "__select__" || col.key === "__expand__") return col;
|
|
3085
|
+
if (col.key === "__select__" || col.key === "__expand__" || col.key === "__drag__") return col;
|
|
2742
3086
|
const latest = latestMap.get(col.key);
|
|
2743
3087
|
if (!latest) return col;
|
|
2744
3088
|
return {
|
|
@@ -3231,7 +3575,7 @@ function BoltTable({
|
|
|
3231
3575
|
return freshOrderedColumns;
|
|
3232
3576
|
return freshOrderedColumns.filter((col, idx) => {
|
|
3233
3577
|
if (col.pinned) return true;
|
|
3234
|
-
if (col.key === "__select__" || col.key === "__expand__") return true;
|
|
3578
|
+
if (col.key === "__select__" || col.key === "__expand__" || col.key === "__drag__") return true;
|
|
3235
3579
|
return idx >= visibleColumnRange.start && idx <= visibleColumnRange.end;
|
|
3236
3580
|
});
|
|
3237
3581
|
}, [enableColumnVirtualization, visibleColumnRange, freshOrderedColumns]);
|
|
@@ -3378,8 +3722,11 @@ function BoltTable({
|
|
|
3378
3722
|
[data-bt-resize]:hover [data-bt-resize-line] {
|
|
3379
3723
|
opacity: 1 !important;
|
|
3380
3724
|
}
|
|
3725
|
+
[data-bt-ctx-item] {
|
|
3726
|
+
transition: background-color 0.15s ease;
|
|
3727
|
+
}
|
|
3381
3728
|
[data-bt-ctx-item]:not(:disabled):hover {
|
|
3382
|
-
background-color: rgba(128, 128, 128, 0.15);
|
|
3729
|
+
background-color: rgba(128, 128, 128, 0.15) !important;
|
|
3383
3730
|
}
|
|
3384
3731
|
[data-bt-header][data-dragging] {
|
|
3385
3732
|
opacity: 0.2 !important;
|
|
@@ -3388,6 +3735,17 @@ function BoltTable({
|
|
|
3388
3735
|
border: 1px dashed ${accentColor} !important;
|
|
3389
3736
|
}
|
|
3390
3737
|
${onRowClick ? "[data-bt-cell] { cursor: pointer; }" : ""}
|
|
3738
|
+
[data-row-drag-over] {
|
|
3739
|
+
box-shadow: 0 -2px 0 0 ${accentColor} inset;
|
|
3740
|
+
}
|
|
3741
|
+
[data-bt-row-grip] {
|
|
3742
|
+
cursor: grab;
|
|
3743
|
+
opacity: 0.3;
|
|
3744
|
+
transition: opacity 0.15s;
|
|
3745
|
+
}
|
|
3746
|
+
[data-bt-row-grip]:hover {
|
|
3747
|
+
opacity: 0.8;
|
|
3748
|
+
}
|
|
3391
3749
|
@keyframes bt-spin { to { transform: rotate(360deg); } }
|
|
3392
3750
|
@keyframes bt-ai-shimmer {
|
|
3393
3751
|
0% { background-position: -200% 0; }
|
|
@@ -3406,7 +3764,7 @@ function BoltTable({
|
|
|
3406
3764
|
borderBottom: "1px solid rgba(128,128,128,0.2)",
|
|
3407
3765
|
fontSize: 12,
|
|
3408
3766
|
flexShrink: 0,
|
|
3409
|
-
|
|
3767
|
+
zIndex: 20
|
|
3410
3768
|
},
|
|
3411
3769
|
children: [
|
|
3412
3770
|
/* @__PURE__ */ jsxs5(
|
|
@@ -3543,7 +3901,7 @@ function BoltTable({
|
|
|
3543
3901
|
marginTop: 4
|
|
3544
3902
|
},
|
|
3545
3903
|
children: initialColumns.filter(
|
|
3546
|
-
(c) => c.key !== "__select__" && c.key !== "__expand__"
|
|
3904
|
+
(c) => c.key !== "__select__" && c.key !== "__expand__" && c.key !== "__drag__"
|
|
3547
3905
|
).map((col) => {
|
|
3548
3906
|
const current = columns.find(
|
|
3549
3907
|
(c) => c.key === col.key
|
|
@@ -3598,6 +3956,110 @@ function BoltTable({
|
|
|
3598
3956
|
}
|
|
3599
3957
|
)
|
|
3600
3958
|
] }),
|
|
3959
|
+
aiMode && savedAIFilters.length > 0 && /* @__PURE__ */ jsxs5("div", { ref: savedFiltersRef, style: { position: "relative", flexShrink: 0 }, children: [
|
|
3960
|
+
/* @__PURE__ */ jsxs5(
|
|
3961
|
+
"button",
|
|
3962
|
+
{
|
|
3963
|
+
type: "button",
|
|
3964
|
+
onClick: () => setShowSavedFilters((p) => !p),
|
|
3965
|
+
style: {
|
|
3966
|
+
display: "flex",
|
|
3967
|
+
alignItems: "center",
|
|
3968
|
+
gap: 4,
|
|
3969
|
+
background: "none",
|
|
3970
|
+
border: "1px solid rgba(128,128,128,0.2)",
|
|
3971
|
+
borderRadius: 4,
|
|
3972
|
+
cursor: "pointer",
|
|
3973
|
+
padding: "4px 6px",
|
|
3974
|
+
color: "inherit",
|
|
3975
|
+
fontSize: 12
|
|
3976
|
+
},
|
|
3977
|
+
title: "Saved AI filters",
|
|
3978
|
+
children: [
|
|
3979
|
+
/* @__PURE__ */ jsx5("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx5("polygon", { points: "22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3" }) }),
|
|
3980
|
+
/* @__PURE__ */ jsx5("span", { children: savedAIFilters.length })
|
|
3981
|
+
]
|
|
3982
|
+
}
|
|
3983
|
+
),
|
|
3984
|
+
showSavedFilters && /* @__PURE__ */ jsxs5(
|
|
3985
|
+
"div",
|
|
3986
|
+
{
|
|
3987
|
+
style: {
|
|
3988
|
+
position: "absolute",
|
|
3989
|
+
top: "100%",
|
|
3990
|
+
right: 0,
|
|
3991
|
+
zIndex: 99999,
|
|
3992
|
+
minWidth: 240,
|
|
3993
|
+
maxWidth: 360,
|
|
3994
|
+
maxHeight: 320,
|
|
3995
|
+
overflowY: "auto",
|
|
3996
|
+
borderRadius: 8,
|
|
3997
|
+
border: "1px solid rgba(128,128,128,0.2)",
|
|
3998
|
+
boxShadow: "0 4px 24px rgba(0,0,0,0.12)",
|
|
3999
|
+
backdropFilter: "blur(16px)",
|
|
4000
|
+
WebkitBackdropFilter: "blur(16px)",
|
|
4001
|
+
backgroundColor: "rgba(128,128,128,0.08)",
|
|
4002
|
+
padding: "4px 0",
|
|
4003
|
+
marginTop: 4
|
|
4004
|
+
},
|
|
4005
|
+
children: [
|
|
4006
|
+
/* @__PURE__ */ jsx5("div", { style: { padding: "6px 12px", fontSize: 11, opacity: 0.5, fontWeight: 600 }, children: "Saved Filters" }),
|
|
4007
|
+
savedAIFilters.map((f, i) => /* @__PURE__ */ jsxs5(
|
|
4008
|
+
"div",
|
|
4009
|
+
{
|
|
4010
|
+
style: {
|
|
4011
|
+
display: "flex",
|
|
4012
|
+
alignItems: "center",
|
|
4013
|
+
gap: 6,
|
|
4014
|
+
padding: "6px 12px",
|
|
4015
|
+
cursor: "pointer",
|
|
4016
|
+
fontSize: 12
|
|
4017
|
+
},
|
|
4018
|
+
onMouseEnter: (e) => {
|
|
4019
|
+
e.currentTarget.style.backgroundColor = "rgba(128,128,128,0.15)";
|
|
4020
|
+
},
|
|
4021
|
+
onMouseLeave: (e) => {
|
|
4022
|
+
e.currentTarget.style.backgroundColor = "transparent";
|
|
4023
|
+
},
|
|
4024
|
+
children: [
|
|
4025
|
+
/* @__PURE__ */ jsx5(
|
|
4026
|
+
"span",
|
|
4027
|
+
{
|
|
4028
|
+
style: { flex: "1 1 0%", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" },
|
|
4029
|
+
onClick: () => applySavedFilter(f),
|
|
4030
|
+
children: f.label
|
|
4031
|
+
}
|
|
4032
|
+
),
|
|
4033
|
+
/* @__PURE__ */ jsx5(
|
|
4034
|
+
"button",
|
|
4035
|
+
{
|
|
4036
|
+
type: "button",
|
|
4037
|
+
onClick: (e) => {
|
|
4038
|
+
e.stopPropagation();
|
|
4039
|
+
removeSavedFilter(i);
|
|
4040
|
+
},
|
|
4041
|
+
style: {
|
|
4042
|
+
display: "flex",
|
|
4043
|
+
alignItems: "center",
|
|
4044
|
+
background: "none",
|
|
4045
|
+
border: "none",
|
|
4046
|
+
cursor: "pointer",
|
|
4047
|
+
padding: 2,
|
|
4048
|
+
color: "GrayText",
|
|
4049
|
+
flexShrink: 0
|
|
4050
|
+
},
|
|
4051
|
+
title: "Remove",
|
|
4052
|
+
children: icons?.close ?? /* @__PURE__ */ jsx5(XIcon, { style: { width: 10, height: 10 } })
|
|
4053
|
+
}
|
|
4054
|
+
)
|
|
4055
|
+
]
|
|
4056
|
+
},
|
|
4057
|
+
i
|
|
4058
|
+
))
|
|
4059
|
+
]
|
|
4060
|
+
}
|
|
4061
|
+
)
|
|
4062
|
+
] }),
|
|
3601
4063
|
aiMode && /* @__PURE__ */ jsxs5(
|
|
3602
4064
|
"button",
|
|
3603
4065
|
{
|
|
@@ -3763,6 +4225,38 @@ function BoltTable({
|
|
|
3763
4225
|
children: [
|
|
3764
4226
|
/* @__PURE__ */ jsx5("span", { style: { color: accentColor, display: "flex", flexShrink: 0 }, children: icons?.sparkles ?? /* @__PURE__ */ jsx5(SparklesIcon, { style: { width: 14, height: 14 } }) }),
|
|
3765
4227
|
/* @__PURE__ */ jsx5("span", { style: { flex: "1 1 0%", opacity: 0.85 }, children: aiResult.message }),
|
|
4228
|
+
/* @__PURE__ */ jsxs5(
|
|
4229
|
+
"button",
|
|
4230
|
+
{
|
|
4231
|
+
type: "button",
|
|
4232
|
+
onClick: saveCurrentAIFilter,
|
|
4233
|
+
disabled: justSavedFilter,
|
|
4234
|
+
style: {
|
|
4235
|
+
display: "flex",
|
|
4236
|
+
alignItems: "center",
|
|
4237
|
+
gap: 4,
|
|
4238
|
+
background: justSavedFilter ? `${accentColor}25` : `${accentColor}12`,
|
|
4239
|
+
border: `1px solid ${justSavedFilter ? accentColor : `${accentColor}30`}`,
|
|
4240
|
+
borderRadius: 4,
|
|
4241
|
+
cursor: justSavedFilter ? "default" : "pointer",
|
|
4242
|
+
padding: "2px 8px",
|
|
4243
|
+
color: accentColor,
|
|
4244
|
+
fontSize: 11,
|
|
4245
|
+
flexShrink: 0,
|
|
4246
|
+
fontWeight: 500,
|
|
4247
|
+
transition: "all 0.2s ease"
|
|
4248
|
+
},
|
|
4249
|
+
title: justSavedFilter ? "Filter saved!" : "Save this filter for quick access later",
|
|
4250
|
+
children: [
|
|
4251
|
+
justSavedFilter ? /* @__PURE__ */ jsx5("svg", { width: "10", height: "10", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx5("polyline", { points: "20 6 9 17 4 12" }) }) : /* @__PURE__ */ jsxs5("svg", { width: "10", height: "10", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
4252
|
+
/* @__PURE__ */ jsx5("path", { d: "M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z" }),
|
|
4253
|
+
/* @__PURE__ */ jsx5("polyline", { points: "17 21 17 13 7 13 7 21" }),
|
|
4254
|
+
/* @__PURE__ */ jsx5("polyline", { points: "7 3 7 8 15 8" })
|
|
4255
|
+
] }),
|
|
4256
|
+
/* @__PURE__ */ jsx5("span", { children: justSavedFilter ? "Saved" : "Save Filter" })
|
|
4257
|
+
]
|
|
4258
|
+
}
|
|
4259
|
+
),
|
|
3766
4260
|
/* @__PURE__ */ jsxs5(
|
|
3767
4261
|
"button",
|
|
3768
4262
|
{
|
|
@@ -3866,7 +4360,7 @@ function BoltTable({
|
|
|
3866
4360
|
orderedColumns.map((column) => {
|
|
3867
4361
|
const isPinned = !!column.pinned;
|
|
3868
4362
|
const offset = columnOffsets.get(column.key);
|
|
3869
|
-
const isSystem = column.key === "__select__" || column.key === "__expand__";
|
|
4363
|
+
const isSystem = column.key === "__select__" || column.key === "__expand__" || column.key === "__drag__";
|
|
3870
4364
|
return /* @__PURE__ */ jsx5(
|
|
3871
4365
|
"div",
|
|
3872
4366
|
{
|
|
@@ -3905,7 +4399,7 @@ function BoltTable({
|
|
|
3905
4399
|
children: orderedColumns.map((column, colIndex) => {
|
|
3906
4400
|
const isPinned = !!column.pinned;
|
|
3907
4401
|
const offset = columnOffsets.get(column.key);
|
|
3908
|
-
const isSystem = column.key === "__select__" || column.key === "__expand__";
|
|
4402
|
+
const isSystem = column.key === "__select__" || column.key === "__expand__" || column.key === "__drag__";
|
|
3909
4403
|
const widthPercent = SHIMMER_WIDTHS2[(rowIndex * 7 + colIndex) % SHIMMER_WIDTHS2.length];
|
|
3910
4404
|
return /* @__PURE__ */ jsx5(
|
|
3911
4405
|
"div",
|
|
@@ -4115,7 +4609,7 @@ function BoltTable({
|
|
|
4115
4609
|
}),
|
|
4116
4610
|
(() => {
|
|
4117
4611
|
const firstDataColIndex = orderedColumns.findIndex(
|
|
4118
|
-
(c) => c.key !== "__select__" && c.key !== "__expand__"
|
|
4612
|
+
(c) => c.key !== "__select__" && c.key !== "__expand__" && c.key !== "__drag__"
|
|
4119
4613
|
);
|
|
4120
4614
|
return orderedColumns.map((column, visualIndex) => {
|
|
4121
4615
|
const isInGroup = groupedColumnKeySet?.has(column.key) ?? false;
|
|
@@ -4192,6 +4686,39 @@ function BoltTable({
|
|
|
4192
4686
|
"__select__"
|
|
4193
4687
|
);
|
|
4194
4688
|
}
|
|
4689
|
+
if (column.key === "__drag__") {
|
|
4690
|
+
return /* @__PURE__ */ jsx5(
|
|
4691
|
+
"div",
|
|
4692
|
+
{
|
|
4693
|
+
"data-bt-header": "",
|
|
4694
|
+
"data-bt-pinned": "",
|
|
4695
|
+
className: `${classNames.header ?? ""} ${classNames.pinnedHeader ?? ""}`,
|
|
4696
|
+
style: {
|
|
4697
|
+
display: "flex",
|
|
4698
|
+
height: leafHeight,
|
|
4699
|
+
alignItems: "center",
|
|
4700
|
+
justifyContent: "center",
|
|
4701
|
+
overflow: "hidden",
|
|
4702
|
+
whiteSpace: "nowrap",
|
|
4703
|
+
boxSizing: "border-box",
|
|
4704
|
+
position: "sticky",
|
|
4705
|
+
left: columnOffsets.get("__drag__") ?? 0,
|
|
4706
|
+
top: 0,
|
|
4707
|
+
zIndex: 13,
|
|
4708
|
+
width: "36px",
|
|
4709
|
+
gridRow: leafGridRow,
|
|
4710
|
+
...styles.header,
|
|
4711
|
+
...styles.pinnedHeader,
|
|
4712
|
+
borderTop: "none",
|
|
4713
|
+
borderLeft: "none",
|
|
4714
|
+
borderBottom: "1px solid rgba(128,128,128,0.2)",
|
|
4715
|
+
borderRight: "1px solid rgba(128,128,128,0.2)"
|
|
4716
|
+
},
|
|
4717
|
+
children: /* @__PURE__ */ jsx5(GripVerticalIcon, { style: { width: 12, height: 12, opacity: 0.4 } })
|
|
4718
|
+
},
|
|
4719
|
+
"__drag__"
|
|
4720
|
+
);
|
|
4721
|
+
}
|
|
4195
4722
|
if (column.key === "__expand__") {
|
|
4196
4723
|
return /* @__PURE__ */ jsx5(
|
|
4197
4724
|
"div",
|
|
@@ -4256,7 +4783,8 @@ function BoltTable({
|
|
|
4256
4783
|
disabledFilters,
|
|
4257
4784
|
headerGridRow: leafGridRow,
|
|
4258
4785
|
headerHeight: leafHeight,
|
|
4259
|
-
stickyTop: leafStickyTop
|
|
4786
|
+
stickyTop: leafStickyTop,
|
|
4787
|
+
onAutoFitColumn: handleAutoFitColumn
|
|
4260
4788
|
},
|
|
4261
4789
|
column.key
|
|
4262
4790
|
);
|
|
@@ -4341,7 +4869,8 @@ function BoltTable({
|
|
|
4341
4869
|
enableDynamicRowHeight,
|
|
4342
4870
|
onRowHeightChange: handleRowHeightChange,
|
|
4343
4871
|
columnGridIndexMap,
|
|
4344
|
-
cellStyleFn: aiCellStyleOps.length > 0 ? (record, columnKey) => getAICellStyleForRecord(record, columnKey) : void 0
|
|
4872
|
+
cellStyleFn: aiCellStyleOps.length > 0 ? (record, columnKey) => getAICellStyleForRecord(record, columnKey) : void 0,
|
|
4873
|
+
onRowDragStart: rowDragEnabled && onRowReorder ? handleRowDragStart : void 0
|
|
4345
4874
|
}
|
|
4346
4875
|
)
|
|
4347
4876
|
]
|
|
@@ -4695,6 +5224,35 @@ function BoltTable({
|
|
|
4695
5224
|
),
|
|
4696
5225
|
document.body
|
|
4697
5226
|
),
|
|
5227
|
+
mounted && rowDragEnabled && onRowReorder && createPortal2(
|
|
5228
|
+
/* @__PURE__ */ jsx5(
|
|
5229
|
+
"div",
|
|
5230
|
+
{
|
|
5231
|
+
ref: rowDragGhostRef,
|
|
5232
|
+
style: {
|
|
5233
|
+
display: "none",
|
|
5234
|
+
position: "fixed",
|
|
5235
|
+
zIndex: 99999,
|
|
5236
|
+
height: 32,
|
|
5237
|
+
fontSize: 11,
|
|
5238
|
+
alignItems: "center",
|
|
5239
|
+
justifyContent: "center",
|
|
5240
|
+
padding: "0 12px",
|
|
5241
|
+
borderRadius: 6,
|
|
5242
|
+
border: `1px dashed ${accentColor}60`,
|
|
5243
|
+
boxShadow: "0 8px 32px rgba(0,0,0,0.18)",
|
|
5244
|
+
backdropFilter: "blur(16px)",
|
|
5245
|
+
WebkitBackdropFilter: "blur(16px)",
|
|
5246
|
+
backgroundColor: "rgba(128,128,128,0.12)",
|
|
5247
|
+
cursor: "grabbing",
|
|
5248
|
+
pointerEvents: "none",
|
|
5249
|
+
fontWeight: 500,
|
|
5250
|
+
color: accentColor
|
|
5251
|
+
}
|
|
5252
|
+
}
|
|
5253
|
+
),
|
|
5254
|
+
document.body
|
|
5255
|
+
),
|
|
4698
5256
|
cellContextMenu && mounted && (() => {
|
|
4699
5257
|
const menuCol = freshOrderedColumns.find(
|
|
4700
5258
|
(c) => c.key === cellContextMenu.columnKey
|