@optilogic/core 1.3.0 → 1.3.2
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.cjs +91 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +15 -2
- package/dist/index.d.ts +15 -2
- package/dist/index.js +91 -26
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/data-grid/DataGrid.tsx +81 -25
- package/src/components/data-grid/components/HeaderCell.tsx +5 -1
- package/src/components/data-grid/hooks/useColumnResize.ts +30 -1
- package/src/components/data-grid/types.ts +5 -0
package/dist/index.cjs
CHANGED
|
@@ -3471,6 +3471,7 @@ function HeaderCell({
|
|
|
3471
3471
|
sorting,
|
|
3472
3472
|
filter,
|
|
3473
3473
|
isResizable,
|
|
3474
|
+
fillWidth,
|
|
3474
3475
|
onSort,
|
|
3475
3476
|
onFilterChange,
|
|
3476
3477
|
onResizeMouseDown,
|
|
@@ -3514,7 +3515,8 @@ function HeaderCell({
|
|
|
3514
3515
|
"div",
|
|
3515
3516
|
{
|
|
3516
3517
|
className: cn(
|
|
3517
|
-
"relative
|
|
3518
|
+
"relative border-r border-border last:border-r-0",
|
|
3519
|
+
!fillWidth && "flex-shrink-0",
|
|
3518
3520
|
"bg-muted select-none",
|
|
3519
3521
|
isResizing && "bg-accent/20"
|
|
3520
3522
|
),
|
|
@@ -4454,11 +4456,15 @@ function useColumnResizeManager(options) {
|
|
|
4454
4456
|
resizableColumns,
|
|
4455
4457
|
onColumnResize,
|
|
4456
4458
|
onColumnResizeStart,
|
|
4457
|
-
onColumnResizeEnd
|
|
4459
|
+
onColumnResizeEnd,
|
|
4460
|
+
fillWidth,
|
|
4461
|
+
containerWidth,
|
|
4462
|
+
effectiveColumnWidths
|
|
4458
4463
|
} = options;
|
|
4459
4464
|
const [resizingColumn, setResizingColumn] = React20.useState(null);
|
|
4460
4465
|
const startXRef = React20.useRef(0);
|
|
4461
4466
|
const startWidthRef = React20.useRef(0);
|
|
4467
|
+
const startEffectiveWidthsRef = React20.useRef({});
|
|
4462
4468
|
const getColumn = React20.useCallback(
|
|
4463
4469
|
(columnKey) => {
|
|
4464
4470
|
return columns.find((c) => c.key === columnKey);
|
|
@@ -4482,9 +4488,20 @@ function useColumnResizeManager(options) {
|
|
|
4482
4488
|
resizingColumn,
|
|
4483
4489
|
startWidthRef.current + deltaX
|
|
4484
4490
|
);
|
|
4491
|
+
if (fillWidth && containerWidth) {
|
|
4492
|
+
const otherCols = columns.filter((c) => c.key !== resizingColumn);
|
|
4493
|
+
const startEffective = startEffectiveWidthsRef.current;
|
|
4494
|
+
const otherTotal = otherCols.reduce((s, c) => s + (startEffective[c.key] || 0), 0);
|
|
4495
|
+
const remaining = containerWidth - newWidth;
|
|
4496
|
+
for (const col of otherCols) {
|
|
4497
|
+
const proportion = (startEffective[col.key] || 0) / otherTotal;
|
|
4498
|
+
const adjusted = clampWidth(col.key, Math.floor(remaining * proportion));
|
|
4499
|
+
onColumnResize(col.key, adjusted);
|
|
4500
|
+
}
|
|
4501
|
+
}
|
|
4485
4502
|
onColumnResize(resizingColumn, newWidth);
|
|
4486
4503
|
},
|
|
4487
|
-
[resizingColumn, clampWidth, onColumnResize]
|
|
4504
|
+
[resizingColumn, clampWidth, onColumnResize, fillWidth, containerWidth, columns]
|
|
4488
4505
|
);
|
|
4489
4506
|
const handleMouseUp = React20.useCallback(() => {
|
|
4490
4507
|
if (!resizingColumn) return;
|
|
@@ -4518,6 +4535,9 @@ function useColumnResizeManager(options) {
|
|
|
4518
4535
|
document.body.style.userSelect = "none";
|
|
4519
4536
|
document.body.style.cursor = "col-resize";
|
|
4520
4537
|
onColumnResizeStart?.(columnKey);
|
|
4538
|
+
if (fillWidth && effectiveColumnWidths) {
|
|
4539
|
+
startEffectiveWidthsRef.current = { ...effectiveColumnWidths };
|
|
4540
|
+
}
|
|
4521
4541
|
};
|
|
4522
4542
|
const handleDoubleClick = (event) => {
|
|
4523
4543
|
if (!isResizable) return;
|
|
@@ -4543,7 +4563,9 @@ function useColumnResizeManager(options) {
|
|
|
4543
4563
|
resizingColumn,
|
|
4544
4564
|
onColumnResize,
|
|
4545
4565
|
onColumnResizeStart,
|
|
4546
|
-
onColumnResizeEnd
|
|
4566
|
+
onColumnResizeEnd,
|
|
4567
|
+
fillWidth,
|
|
4568
|
+
effectiveColumnWidths
|
|
4547
4569
|
]
|
|
4548
4570
|
);
|
|
4549
4571
|
return {
|
|
@@ -4768,6 +4790,7 @@ function DataGrid({
|
|
|
4768
4790
|
tooltipMinLength = 30,
|
|
4769
4791
|
enableKeyboardNavigation = true,
|
|
4770
4792
|
showColumnBorders = true,
|
|
4793
|
+
fillWidth,
|
|
4771
4794
|
enableInternalSorting = true,
|
|
4772
4795
|
enableInternalFiltering = true,
|
|
4773
4796
|
// Controlled sorting
|
|
@@ -4822,6 +4845,26 @@ function DataGrid({
|
|
|
4822
4845
|
const headerRef = React20__namespace.useRef(null);
|
|
4823
4846
|
const [headerHeight, setHeaderHeight] = React20__namespace.useState(40);
|
|
4824
4847
|
const [hoveredCell, setHoveredCell] = React20__namespace.useState(null);
|
|
4848
|
+
const [containerWidth, setContainerWidth] = React20__namespace.useState(0);
|
|
4849
|
+
const fillWidthObserverRef = React20__namespace.useRef(null);
|
|
4850
|
+
const parentCallbackRef = React20__namespace.useCallback(
|
|
4851
|
+
(node) => {
|
|
4852
|
+
fillWidthObserverRef.current?.disconnect();
|
|
4853
|
+
fillWidthObserverRef.current = null;
|
|
4854
|
+
parentRef.current = node;
|
|
4855
|
+
if (!fillWidth || !node) return;
|
|
4856
|
+
const observer = new ResizeObserver((entries) => {
|
|
4857
|
+
const w = entries[0]?.contentRect.width;
|
|
4858
|
+
if (w && w > 0) setContainerWidth(w);
|
|
4859
|
+
});
|
|
4860
|
+
observer.observe(node);
|
|
4861
|
+
fillWidthObserverRef.current = observer;
|
|
4862
|
+
},
|
|
4863
|
+
[fillWidth]
|
|
4864
|
+
);
|
|
4865
|
+
React20__namespace.useEffect(() => {
|
|
4866
|
+
return () => fillWidthObserverRef.current?.disconnect();
|
|
4867
|
+
}, []);
|
|
4825
4868
|
const visibleColumns = React20__namespace.useMemo(
|
|
4826
4869
|
() => columns.filter((col) => !col.hidden),
|
|
4827
4870
|
[columns]
|
|
@@ -4875,14 +4918,6 @@ function DataGrid({
|
|
|
4875
4918
|
visibleColumns
|
|
4876
4919
|
]);
|
|
4877
4920
|
processedDataRef.current = processedData;
|
|
4878
|
-
const { resizingColumn, getResizeProps } = useColumnResizeManager({
|
|
4879
|
-
columns: visibleColumns,
|
|
4880
|
-
columnWidths: state.columnWidths,
|
|
4881
|
-
resizableColumns,
|
|
4882
|
-
onColumnResize: actions.setColumnWidth,
|
|
4883
|
-
onColumnResizeStart,
|
|
4884
|
-
onColumnResizeEnd
|
|
4885
|
-
});
|
|
4886
4921
|
const shouldVirtualize = virtualized ?? processedData.length > 100;
|
|
4887
4922
|
React20__namespace.useLayoutEffect(() => {
|
|
4888
4923
|
if (headerRef.current && shouldVirtualize) {
|
|
@@ -4896,12 +4931,38 @@ function DataGrid({
|
|
|
4896
4931
|
overscan: DEFAULT_OVERSCAN,
|
|
4897
4932
|
enabled: shouldVirtualize
|
|
4898
4933
|
});
|
|
4899
|
-
const tableWidth = React20__namespace.useMemo(() => {
|
|
4900
|
-
|
|
4901
|
-
|
|
4902
|
-
|
|
4903
|
-
|
|
4904
|
-
|
|
4934
|
+
const { tableWidth, effectiveColumnWidths } = React20__namespace.useMemo(() => {
|
|
4935
|
+
const rawWidths = {};
|
|
4936
|
+
let rawTotal = 0;
|
|
4937
|
+
for (const col of visibleColumns) {
|
|
4938
|
+
const w = state.columnWidths[col.key] || col.width || estimateColumnWidth(col);
|
|
4939
|
+
rawWidths[col.key] = w;
|
|
4940
|
+
rawTotal += w;
|
|
4941
|
+
}
|
|
4942
|
+
if (!fillWidth || !containerWidth || rawTotal >= containerWidth) {
|
|
4943
|
+
return { tableWidth: rawTotal, effectiveColumnWidths: rawWidths };
|
|
4944
|
+
}
|
|
4945
|
+
const scale = containerWidth / rawTotal;
|
|
4946
|
+
const scaled = {};
|
|
4947
|
+
for (const col of visibleColumns) {
|
|
4948
|
+
let w = Math.floor(rawWidths[col.key] * scale);
|
|
4949
|
+
if (col.minWidth) w = Math.max(w, col.minWidth);
|
|
4950
|
+
if (col.maxWidth) w = Math.min(w, col.maxWidth);
|
|
4951
|
+
scaled[col.key] = w;
|
|
4952
|
+
}
|
|
4953
|
+
return { tableWidth: containerWidth, effectiveColumnWidths: scaled };
|
|
4954
|
+
}, [visibleColumns, state.columnWidths, fillWidth, containerWidth]);
|
|
4955
|
+
const { resizingColumn, getResizeProps } = useColumnResizeManager({
|
|
4956
|
+
columns: visibleColumns,
|
|
4957
|
+
columnWidths: state.columnWidths,
|
|
4958
|
+
resizableColumns,
|
|
4959
|
+
onColumnResize: actions.setColumnWidth,
|
|
4960
|
+
onColumnResizeStart,
|
|
4961
|
+
onColumnResizeEnd,
|
|
4962
|
+
fillWidth,
|
|
4963
|
+
containerWidth,
|
|
4964
|
+
effectiveColumnWidths
|
|
4965
|
+
});
|
|
4905
4966
|
const visibleRowCount = React20__namespace.useMemo(() => {
|
|
4906
4967
|
if (!parentRef.current) return 10;
|
|
4907
4968
|
return Math.floor(parentRef.current.clientHeight / DEFAULT_ROW_HEIGHT);
|
|
@@ -5106,7 +5167,7 @@ function DataGrid({
|
|
|
5106
5167
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5107
5168
|
"div",
|
|
5108
5169
|
{
|
|
5109
|
-
ref:
|
|
5170
|
+
ref: parentCallbackRef,
|
|
5110
5171
|
className: "flex-1 overflow-auto bg-background relative w-full min-h-0 max-h-full",
|
|
5111
5172
|
style: { contain: "strict" },
|
|
5112
5173
|
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -5133,7 +5194,7 @@ function DataGrid({
|
|
|
5133
5194
|
},
|
|
5134
5195
|
role: "row",
|
|
5135
5196
|
children: visibleColumns.map((column, colIndex) => {
|
|
5136
|
-
const width =
|
|
5197
|
+
const width = effectiveColumnWidths[column.key];
|
|
5137
5198
|
const resizeProps = getResizeProps(column.key);
|
|
5138
5199
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5139
5200
|
HeaderCell,
|
|
@@ -5144,6 +5205,7 @@ function DataGrid({
|
|
|
5144
5205
|
sorting: getColumnSort(column.key),
|
|
5145
5206
|
filter: getColumnFilter(column.key),
|
|
5146
5207
|
isResizable: resizableColumns && column.resizable !== false,
|
|
5208
|
+
fillWidth,
|
|
5147
5209
|
onSort: () => handleSort(column.key),
|
|
5148
5210
|
onFilterChange: (filter) => handleFilterChange(column.key, filter),
|
|
5149
5211
|
onResizeMouseDown: resizeProps.handleMouseDown,
|
|
@@ -5192,7 +5254,7 @@ function DataGrid({
|
|
|
5192
5254
|
"aria-rowindex": virtualRow.index + 1,
|
|
5193
5255
|
"aria-selected": isSelected,
|
|
5194
5256
|
children: visibleColumns.map((column, colIndex) => {
|
|
5195
|
-
const width =
|
|
5257
|
+
const width = effectiveColumnWidths[column.key];
|
|
5196
5258
|
const isEditingThisCell = state.editingCell?.rowIndex === virtualRow.index && state.editingCell?.columnKey === column.key;
|
|
5197
5259
|
const isFocused = state.focusedCell?.rowIndex === virtualRow.index && state.focusedCell?.columnKey === column.key;
|
|
5198
5260
|
const cellContent = renderCell(
|
|
@@ -5207,7 +5269,8 @@ function DataGrid({
|
|
|
5207
5269
|
"div",
|
|
5208
5270
|
{
|
|
5209
5271
|
className: cn(
|
|
5210
|
-
"
|
|
5272
|
+
"px-3 py-2 text-sm overflow-hidden",
|
|
5273
|
+
!fillWidth && "flex-shrink-0",
|
|
5211
5274
|
showColumnBorders && "border-r border-border last:border-r-0",
|
|
5212
5275
|
isFocused && !isEditingThisCell && "ring-2 ring-inset ring-primary",
|
|
5213
5276
|
isEditingThisCell && "ring-2 ring-inset ring-primary bg-background",
|
|
@@ -5319,7 +5382,7 @@ function DataGrid({
|
|
|
5319
5382
|
}
|
|
5320
5383
|
)
|
|
5321
5384
|
] }) }),
|
|
5322
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 overflow-auto min-h-0", children: [
|
|
5385
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { ref: parentCallbackRef, className: "flex-1 overflow-auto min-h-0", children: [
|
|
5323
5386
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5324
5387
|
"div",
|
|
5325
5388
|
{
|
|
@@ -5330,7 +5393,7 @@ function DataGrid({
|
|
|
5330
5393
|
style: { width: tableWidth ? `${tableWidth}px` : "100%" },
|
|
5331
5394
|
role: "row",
|
|
5332
5395
|
children: visibleColumns.map((column, colIndex) => {
|
|
5333
|
-
const width =
|
|
5396
|
+
const width = effectiveColumnWidths[column.key];
|
|
5334
5397
|
const resizeProps = getResizeProps(column.key);
|
|
5335
5398
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5336
5399
|
HeaderCell,
|
|
@@ -5341,6 +5404,7 @@ function DataGrid({
|
|
|
5341
5404
|
sorting: getColumnSort(column.key),
|
|
5342
5405
|
filter: getColumnFilter(column.key),
|
|
5343
5406
|
isResizable: resizableColumns && column.resizable !== false,
|
|
5407
|
+
fillWidth,
|
|
5344
5408
|
onSort: () => handleSort(column.key),
|
|
5345
5409
|
onFilterChange: (filter) => handleFilterChange(column.key, filter),
|
|
5346
5410
|
onResizeMouseDown: resizeProps.handleMouseDown,
|
|
@@ -5370,14 +5434,15 @@ function DataGrid({
|
|
|
5370
5434
|
onDoubleClick: () => onRowDoubleClick?.(row, rowIndex),
|
|
5371
5435
|
role: "row",
|
|
5372
5436
|
children: visibleColumns.map((column) => {
|
|
5373
|
-
const width =
|
|
5437
|
+
const width = effectiveColumnWidths[column.key];
|
|
5374
5438
|
const isEditingThisCell = state.editingCell?.rowIndex === rowIndex && state.editingCell?.columnKey === column.key;
|
|
5375
5439
|
const isFocused = state.focusedCell?.rowIndex === rowIndex && state.focusedCell?.columnKey === column.key;
|
|
5376
5440
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5377
5441
|
"div",
|
|
5378
5442
|
{
|
|
5379
5443
|
className: cn(
|
|
5380
|
-
"
|
|
5444
|
+
"px-3 py-2 text-sm overflow-hidden",
|
|
5445
|
+
!fillWidth && "flex-shrink-0",
|
|
5381
5446
|
showColumnBorders && "border-r border-border last:border-r-0",
|
|
5382
5447
|
isFocused && !isEditingThisCell && "ring-2 ring-inset ring-primary",
|
|
5383
5448
|
isEditingThisCell && "ring-2 ring-inset ring-primary bg-background",
|