@linzjs/step-ag-grid 29.2.4 → 29.3.0

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/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@linzjs/step-ag-grid",
3
3
  "repository": "github:linz/step-ag-grid.git",
4
4
  "license": "MIT",
5
- "version": "29.2.4",
5
+ "version": "29.3.0",
6
6
  "keywords": [
7
7
  "aggrid",
8
8
  "ag-grid",
@@ -14,7 +14,6 @@ import {
14
14
  GetRowIdParams,
15
15
  GridOptions,
16
16
  GridReadyEvent,
17
- GridSizeChangedEvent,
18
17
  IColumnLimit,
19
18
  ModelUpdatedEvent,
20
19
  ModuleRegistry,
@@ -27,15 +26,14 @@ import {
27
26
  } from 'ag-grid-community';
28
27
  import { AgGridReact } from 'ag-grid-react';
29
28
  import clsx from 'clsx';
30
- import { defer, difference, isEmpty, last, omit, sum, xorBy } from 'lodash-es';
29
+ import { defer, difference, isEmpty, last, omit, xorBy } from 'lodash-es';
31
30
  import { ReactElement, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
32
31
  import { useInterval } from 'usehooks-ts';
33
32
 
34
- import { useGridContext } from '../contexts/GridContext';
33
+ import { AutoSizeColumnsResult, useGridContext } from '../contexts/GridContext';
35
34
  import { GridUpdatingContext } from '../contexts/GridUpdatingContext';
36
35
  import { fnOrVar, isNotEmpty } from '../utils/util';
37
36
  import { clickInputWhenContainingCellClicked } from './clickInputWhenContainingCellClicked';
38
- import { ColDefT } from './GridCell';
39
37
  import { GridHeaderSelect } from './gridHeader';
40
38
  import { GridContextMenuComponent, useGridContextMenu } from './gridHook';
41
39
  import { GridNoRowsOverlay } from './GridNoRowsOverlay';
@@ -196,6 +194,8 @@ export const Grid = <TData extends GridBaseRow = GridBaseRow>({
196
194
 
197
195
  const lastFullResize = useRef<number>();
198
196
 
197
+ const autoSizeResultRef = useRef<AutoSizeColumnsResult | null>(null);
198
+ const prevRowsVisibleRef = useRef(false);
199
199
  const setInitialContentSize = useCallback(() => {
200
200
  if (!gridDivRef.current?.clientWidth || rowData == null) {
201
201
  // Don't resize grids if they are offscreen as it doesn't work.
@@ -210,36 +210,50 @@ export const Grid = <TData extends GridBaseRow = GridBaseRow>({
210
210
  return;
211
211
  }
212
212
 
213
- const skipHeader = sizeColumns === 'auto-skip-headers' && gridRendered === 'rows-visible';
214
- if (sizeColumns === 'auto' || skipHeader) {
215
- const result = autoSizeColumns({
216
- skipHeader,
217
- userSizedColIds: new Set(userSizedColIds.current.keys()),
218
- includeFlex: true,
219
- });
220
- if (!result) {
213
+ // 1. First we autosize to get the size of the columns on an infinite grid.
214
+ if (sizeColumns === 'auto' || sizeColumns === 'auto-skip-headers') {
215
+ // You can't skip headers until the grid has content
216
+ const rowsVisible = gridRendered === 'rows-visible';
217
+ const skipHeader = sizeColumns === 'auto-skip-headers' && rowsVisible;
218
+ // If grid was empty and now has content we need to autosize
219
+ if (rowsVisible !== prevRowsVisibleRef.current && rowsVisible) {
220
+ prevRowsVisibleRef.current = rowsVisible;
221
+ autoSizeResultRef.current = null;
222
+ }
223
+ const autoSizeResult =
224
+ autoSizeResultRef.current ??
225
+ autoSizeColumns({
226
+ skipHeader,
227
+ userSizedColIds: new Set(userSizedColIds.current.keys()),
228
+ });
229
+ // Auto-size failed retry later
230
+ if (!autoSizeResult) {
221
231
  needsAutoSize.current = true;
222
232
  return;
223
233
  }
224
- // Default max intial width is 256x initial visible column count, max of 80% window width
225
- const maxWidth =
226
- maxInitialWidth ||
227
- sum(params.columnDefs.map((c: ColDefT<TData>) => (!(c as any).hide ? c.maxInitialWidth || 128 : 0)));
228
- result.width = Math.min(result.width, maxWidth);
234
+
235
+ autoSizeResultRef.current = autoSizeResult;
236
+ // Calculate the auto-sized width, limit it to maxInitialWidth
237
+ autoSizeResult.width = maxInitialWidth ? Math.min(autoSizeResult.width, maxInitialWidth) : autoSizeResult.width;
229
238
  if (gridRendered === 'empty') {
239
+ // If the grid is empty we still do an onContentSize callback, we will do another callback when grid has data
240
+ // We don't do this callback if we have previously had row data, or have already called back for empty
230
241
  if (!hasSetContentSizeEmpty.current && !hasSetContentSize.current) {
231
242
  hasSetContentSizeEmpty.current = true;
232
- params.onContentSize?.(result);
243
+ params.onContentSize?.(autoSizeResult);
233
244
  }
234
245
  } else if (gridRendered === 'rows-visible') {
246
+ // we have rows now so callback grid size
235
247
  if (!hasSetContentSize.current) {
236
- if (lastFullResize.current === result.width) {
248
+ // Only callback if grid size has settled
249
+ if (lastFullResize.current === autoSizeResult.width) {
237
250
  hasSetContentSize.current = true;
238
- params.onContentSize?.(result);
251
+ params.onContentSize?.(autoSizeResult);
239
252
  } else {
240
- needsAutoSize.current = true;
253
+ // Need to retry callback when size has settelled
254
+ lastFullResize.current = autoSizeResult.width;
255
+ return;
241
256
  }
242
- lastFullResize.current = result.width;
243
257
  }
244
258
  } else {
245
259
  // It should be impossible to get here
@@ -247,6 +261,7 @@ export const Grid = <TData extends GridBaseRow = GridBaseRow>({
247
261
  }
248
262
  }
249
263
 
264
+ // 2. Now we size columns to fit the grid width
250
265
  if (sizeColumns !== 'none') {
251
266
  sizeColumnsToFit();
252
267
  }
@@ -430,6 +445,8 @@ export const Grid = <TData extends GridBaseRow = GridBaseRow>({
430
445
  const onRowDataChanged = useCallback(() => {
431
446
  const length = rowData?.length ?? 0;
432
447
  if (previousRowDataLength.current !== length) {
448
+ // We need to autosize all cells again
449
+ autoSizeResultRef.current = null;
433
450
  setInitialContentSize();
434
451
  previousRowDataLength.current = length;
435
452
  }
@@ -594,14 +611,17 @@ export const Grid = <TData extends GridBaseRow = GridBaseRow>({
594
611
  /**
595
612
  * Resize columns to fit if required on window/container resize
596
613
  */
597
- const onGridSizeChanged = useCallback(
598
- (event: GridSizeChangedEvent<TData>) => {
614
+ const onGridResize = useCallback(
615
+ (event: AgGridEvent<TData>) => {
599
616
  if (sizeColumns !== 'none') {
617
+ // Flex columns can expand to fit after resize, but they cannot shrink less than use resized value
618
+ // Double click column resize handle to reset this behaviour
600
619
  const columnLimits = [
601
620
  ...userSizedColIds.current.entries().map(
602
621
  ([c, w]): IColumnLimit => ({
603
622
  key: c,
604
623
  minWidth: w,
624
+ maxWidth: w,
605
625
  }),
606
626
  ),
607
627
  ];
@@ -619,24 +639,32 @@ export const Grid = <TData extends GridBaseRow = GridBaseRow>({
619
639
  /**
620
640
  * Lock/unlock column width on user edit/reset.
621
641
  */
622
- const onColumnResized = useCallback((e: ColumnResizedEvent) => {
623
- const colId = e.column?.getColId();
624
- if (colId == null) {
625
- return;
626
- }
627
- const width = e.column?.getActualWidth();
628
- if (width == null) {
629
- return;
630
- }
631
- switch (e.source) {
632
- case 'uiColumnResized':
633
- userSizedColIds.current.set(colId, width);
634
- break;
635
- case 'autosizeColumns':
636
- userSizedColIds.current.delete(colId);
637
- break;
638
- }
639
- }, []);
642
+ const onColumnResized = useCallback(
643
+ (e: ColumnResizedEvent) => {
644
+ const colId = e.column?.getColId();
645
+ if (colId == null) {
646
+ return;
647
+ }
648
+ const width = e.column?.getActualWidth();
649
+ if (width == null) {
650
+ return;
651
+ }
652
+ switch (e.source) {
653
+ case 'uiColumnResized':
654
+ userSizedColIds.current.set(colId, width);
655
+ const colDef = e.column?.getColDef();
656
+ if (!colDef?.flex) {
657
+ onGridResize(e);
658
+ }
659
+ break;
660
+ case 'autosizeColumns':
661
+ userSizedColIds.current.delete(colId);
662
+ onGridResize(e);
663
+ break;
664
+ }
665
+ },
666
+ [onGridResize],
667
+ );
640
668
 
641
669
  const gridContextMenu = useGridContextMenu({ contextMenu: params.contextMenu, contextMenuSelectRow });
642
670
 
@@ -773,6 +801,7 @@ export const Grid = <TData extends GridBaseRow = GridBaseRow>({
773
801
  );
774
802
 
775
803
  const selectionColumnDef = useMemo((): SelectionColumnDef => {
804
+ // Note this has to be 1 for hidden otherwise ag-grid does crazy things whilst resizing
776
805
  const selectWidth = params.hideSelectColumn ? 0 : selectable && params.onRowDragEnd ? 76 : 48;
777
806
  return {
778
807
  suppressNavigable: params.hideSelectColumn,
@@ -840,7 +869,7 @@ export const Grid = <TData extends GridBaseRow = GridBaseRow>({
840
869
  animateRows={params.animateRows ?? false}
841
870
  rowClassRules={params.rowClassRules}
842
871
  getRowId={getRowId}
843
- onGridSizeChanged={onGridSizeChanged}
872
+ onGridSizeChanged={onGridResize}
844
873
  suppressColumnVirtualisation={suppressColumnVirtualization}
845
874
  suppressClickEdit={true}
846
875
  onColumnVisible={setInitialContentSize}
@@ -71,7 +71,6 @@ export interface ColDefT<TData extends GridBaseRow, ValueType = any> extends Col
71
71
  editable?: boolean | EditableCallback<TData, ValueType>;
72
72
  valueGetter?: string | ValueGetterFunc<TData, ValueType>;
73
73
  valueFormatter?: string | ValueFormatterFunc<TData, ValueType>;
74
- maxInitialWidth?: number;
75
74
  cellRenderer?:
76
75
  | ((props: ICellRendererParams<TData, ValueType>) => ReactElement | string | false | null | undefined)
77
76
  | string;
@@ -1,11 +1,18 @@
1
- import { PropsWithChildren } from 'react';
1
+ import clsx from 'clsx';
2
+ import { forwardRef, PropsWithChildren } from 'react';
2
3
 
3
4
  export interface GridWrapperProps {
5
+ className?: string | undefined;
4
6
  maxHeight?: number | string;
5
7
  }
6
8
 
7
- export const GridWrapper = ({ children, maxHeight }: PropsWithChildren<GridWrapperProps>) => (
8
- <div className={'Grid-wrapper'} style={{ maxHeight }}>
9
- {children}
10
- </div>
11
- );
9
+ export const GridWrapper = forwardRef<HTMLDivElement, PropsWithChildren<GridWrapperProps>>(function GridWrapperFr(
10
+ { children, maxHeight, className },
11
+ ref,
12
+ ) {
13
+ return (
14
+ <div className={clsx('Grid-wrapper', className)} style={{ maxHeight }} ref={ref}>
15
+ {children}
16
+ </div>
17
+ );
18
+ });