@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 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 flex-shrink-0 border-r border-border last:border-r-0",
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
- return visibleColumns.reduce((acc, col) => {
4901
- const width = state.columnWidths[col.key] || col.width || estimateColumnWidth(col);
4902
- return acc + width;
4903
- }, 0);
4904
- }, [visibleColumns, state.columnWidths]);
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: parentRef,
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 = state.columnWidths[column.key] || column.width || estimateColumnWidth(column);
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 = state.columnWidths[column.key] || column.width || estimateColumnWidth(column);
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
- "flex-shrink-0 px-3 py-2 text-sm overflow-hidden",
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 = state.columnWidths[column.key] || column.width || estimateColumnWidth(column);
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 = state.columnWidths[column.key] || column.width || estimateColumnWidth(column);
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
- "flex-shrink-0 px-3 py-2 text-sm overflow-hidden",
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",