@linzjs/step-ag-grid 29.11.2 → 29.11.4

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.
@@ -2,7 +2,7 @@ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
2
  import { LuiMiniSpinner, LuiStatusSpinner, LuiIcon, LuiButtonGroup, LuiButton, LuiCheckboxInput } from '@linzjs/lui';
3
3
  import { ModuleRegistry, AllCommunityModule } from 'ag-grid-community';
4
4
  import { AgGridReact } from 'ag-grid-react';
5
- import { negate, isEmpty, findIndex, defer, debounce as debounce$1, xorBy, last, difference, delay, omit, sortBy, partition, compact, pick, groupBy, fromPairs, toPairs, isEqual, pull, filter, sumBy, remove, flatten, castArray } from 'lodash-es';
5
+ import { negate, isEmpty, findIndex, defer, debounce as debounce$1, xorBy, last, difference, delay, omit, sortBy, partition, compact, pick, groupBy, fromPairs, toPairs, isEqual, pull, filter, remove, sumBy, flatten, castArray } from 'lodash-es';
6
6
  import React, { useRef, useLayoutEffect, useEffect, createContext, useContext, useState, useMemo, memo, forwardRef, useCallback, useReducer, cloneElement, useImperativeHandle, Fragment as Fragment$1, useId } from 'react';
7
7
  import { unstable_batchedUpdates, flushSync, createPortal } from 'react-dom';
8
8
  import { createRoot } from 'react-dom/client';
@@ -507,9 +507,9 @@ const GridContext = createContext({
507
507
  console.error('no context provider for getFirstRowId');
508
508
  return -1;
509
509
  },
510
- autoSizeColumns: () => {
510
+ autoSizeColumns: async () => {
511
511
  console.error('no context provider for autoSizeColumns');
512
- return null;
512
+ return Promise.resolve(null);
513
513
  },
514
514
  sizeColumnsToFit: () => {
515
515
  console.error('no context provider for autoSizeAllColumns');
@@ -2785,67 +2785,77 @@ const Grid = ({ 'data-testid': dataTestId, defaultPostSort = true, rowSelection
2785
2785
  const needsAutoSize = useRef(true);
2786
2786
  const autoSizeResultRef = useRef(null);
2787
2787
  const prevRowsVisibleRef = useRef(false);
2788
- const setInitialContentSize = useCallback(() => {
2789
- if (!gridDivRef.current?.clientWidth || rowData == null) {
2790
- // Don't resize grids if they are offscreen as it doesn't work.
2791
- needsAutoSize.current = true;
2792
- return;
2793
- }
2794
- const gridRendered = gridRenderState();
2795
- if (gridRendered === null) {
2796
- // Don't resize until grid has rendered, or it has 0 rows.
2797
- needsAutoSize.current = true;
2788
+ const initialContentSizeInProgressRef = useRef(false);
2789
+ const setInitialContentSize = useCallback(async () => {
2790
+ if (initialContentSizeInProgressRef.current) {
2798
2791
  return;
2799
2792
  }
2800
- // 1. First we autosize to get the size of the columns on an infinite grid.
2801
- if (sizeColumns === 'auto' || sizeColumns === 'auto-skip-headers') {
2802
- // You can't skip headers until the grid has content
2803
- const rowsVisible = gridRendered === 'rows-visible';
2804
- const skipHeader = sizeColumns === 'auto-skip-headers' && rowsVisible;
2805
- // If grid was empty and now has content we need to autosize
2806
- if (rowsVisible !== prevRowsVisibleRef.current && rowsVisible) {
2807
- prevRowsVisibleRef.current = rowsVisible;
2808
- autoSizeResultRef.current = null;
2793
+ initialContentSizeInProgressRef.current = true;
2794
+ try {
2795
+ needsAutoSize.current = false;
2796
+ if (!gridDivRef.current?.clientWidth || rowData == null) {
2797
+ // Don't resize grids if they are offscreen as it doesn't work.
2798
+ needsAutoSize.current = true;
2799
+ return;
2809
2800
  }
2810
- const autoSizeResult = autoSizeResultRef.current ??
2811
- autoSizeColumns({
2812
- skipHeader,
2813
- userSizedColIds: new Set(userSizedColIds.current.keys()),
2814
- });
2815
- // Auto-size failed retry later
2816
- if (!autoSizeResult) {
2801
+ const gridRendered = gridRenderState();
2802
+ if (gridRendered === null) {
2803
+ // Don't resize until grid has rendered, or it has 0 rows.
2817
2804
  needsAutoSize.current = true;
2818
2805
  return;
2819
2806
  }
2820
- autoSizeResultRef.current = autoSizeResult;
2821
- // Calculate the auto-sized width, limit it to maxInitialWidth
2822
- autoSizeResult.width = maxInitialWidth ? Math.min(autoSizeResult.width, maxInitialWidth) : autoSizeResult.width;
2823
- if (gridRendered === 'empty') {
2824
- // If the grid is empty we still do an onContentSize callback, we will do another callback when grid has data
2825
- // We don't do this callback if we have previously had row data, or have already called back for empty
2826
- if (!hasSetContentSizeEmpty.current && !hasSetContentSize.current) {
2827
- hasSetContentSizeEmpty.current = true;
2828
- params.onContentSize?.(autoSizeResult);
2807
+ // 1. First we autosize to get the size of the columns on an infinite grid.
2808
+ if (sizeColumns === 'auto' || sizeColumns === 'auto-skip-headers') {
2809
+ // You can't skip headers until the grid has content
2810
+ const rowsVisible = gridRendered === 'rows-visible';
2811
+ const skipHeader = sizeColumns === 'auto-skip-headers' && rowsVisible;
2812
+ // If grid was empty and now has content we need to autosize
2813
+ if (rowsVisible !== prevRowsVisibleRef.current && rowsVisible) {
2814
+ prevRowsVisibleRef.current = rowsVisible;
2815
+ autoSizeResultRef.current = null;
2829
2816
  }
2830
- }
2831
- else if (gridRendered === 'rows-visible') {
2832
- // we have rows now so callback grid size
2833
- if (!hasSetContentSize.current) {
2834
- hasSetContentSize.current = true;
2835
- params.onContentSize?.(autoSizeResult);
2817
+ const autoSizeResult = autoSizeResultRef.current ??
2818
+ (await autoSizeColumns({
2819
+ skipHeader,
2820
+ userSizedColIds: new Set(userSizedColIds.current.keys()),
2821
+ }));
2822
+ // Auto-size failed retry later
2823
+ if (!autoSizeResult) {
2824
+ needsAutoSize.current = true;
2825
+ return;
2826
+ }
2827
+ autoSizeResultRef.current = autoSizeResult;
2828
+ // Calculate the auto-sized width, limit it to maxInitialWidth
2829
+ autoSizeResult.width = maxInitialWidth ? Math.min(autoSizeResult.width, maxInitialWidth) : autoSizeResult.width;
2830
+ if (gridRendered === 'empty') {
2831
+ // If the grid is empty we still do an onContentSize callback, we will do another callback when grid has data
2832
+ // We don't do this callback if we have previously had row data, or have already called back for empty
2833
+ if (!hasSetContentSizeEmpty.current && !hasSetContentSize.current) {
2834
+ hasSetContentSizeEmpty.current = true;
2835
+ params.onContentSize?.(autoSizeResult);
2836
+ }
2837
+ }
2838
+ else if (gridRendered === 'rows-visible') {
2839
+ // we have rows now so callback grid size
2840
+ if (!hasSetContentSize.current) {
2841
+ hasSetContentSize.current = true;
2842
+ params.onContentSize?.(autoSizeResult);
2843
+ }
2844
+ }
2845
+ else {
2846
+ // It should be impossible to get here
2847
+ console.error('Unknown value returned from hasGridRendered');
2836
2848
  }
2837
2849
  }
2838
2850
  else {
2839
- // It should be impossible to get here
2840
- console.error('Unknown value returned from hasGridRendered');
2851
+ sizeColumnsToFit();
2841
2852
  }
2853
+ setAutoSized(true);
2854
+ needsAutoSize.current = false;
2842
2855
  }
2843
- else {
2844
- console.log('sizeColumnsToFit 3');
2845
- sizeColumnsToFit();
2856
+ finally {
2857
+ initialContentSizeInProgressRef.current = false;
2846
2858
  }
2847
- setAutoSized(true);
2848
- needsAutoSize.current = false;
2849
2859
  }, [autoSizeColumns, gridRenderState, maxInitialWidth, params, rowData, sizeColumns, sizeColumnsToFit]);
2850
2860
  const lastOwnerDocumentRef = useRef();
2851
2861
  const wasVisibleRef = useRef(false);
@@ -2879,8 +2889,7 @@ const Grid = ({ 'data-testid': dataTestId, defaultPostSort = true, rowSelection
2879
2889
  }
2880
2890
  if (needsAutoSize.current ||
2881
2891
  (!hasSetContentSize.current && (sizeColumns === 'auto' || sizeColumns === 'auto-skip-headers'))) {
2882
- needsAutoSize.current = false;
2883
- setInitialContentSize();
2892
+ void setInitialContentSize();
2884
2893
  }
2885
2894
  }, 200);
2886
2895
  /**
@@ -3009,11 +3018,13 @@ const Grid = ({ 'data-testid': dataTestId, defaultPostSort = true, rowSelection
3009
3018
  if (previousRowDataLength.current !== length) {
3010
3019
  // We need to autosize all cells again
3011
3020
  autoSizeResultRef.current = null;
3012
- setInitialContentSize();
3013
3021
  previousRowDataLength.current = length;
3022
+ void setInitialContentSize();
3023
+ return;
3014
3024
  }
3015
- if (lastUpdatedDep.current === updatedDep || isEmpty(colIdsEdited.current))
3025
+ if (lastUpdatedDep.current === updatedDep || isEmpty(colIdsEdited.current)) {
3016
3026
  return;
3027
+ }
3017
3028
  lastUpdatedDep.current = updatedDep;
3018
3029
  // Don't update while there are spinners
3019
3030
  if (anyUpdating()) {
@@ -3021,7 +3032,7 @@ const Grid = ({ 'data-testid': dataTestId, defaultPostSort = true, rowSelection
3021
3032
  }
3022
3033
  const skipHeader = sizeColumns === 'auto-skip-headers';
3023
3034
  if ((sizeColumns === 'auto' || sizeColumns === 'auto-skip-headers') && hasSetContentSize.current) {
3024
- autoSizeColumns({
3035
+ void autoSizeColumns({
3025
3036
  skipHeader,
3026
3037
  userSizedColIds: new Set(userSizedColIds.current.keys()),
3027
3038
  colIds: colIdsEdited.current,
@@ -3111,11 +3122,21 @@ const Grid = ({ 'data-testid': dataTestId, defaultPostSort = true, rowSelection
3111
3122
  ...colDef,
3112
3123
  children: colDef.children.map((colDef) => adjustColDefOrGroup(colDef)),
3113
3124
  });
3114
- const adjustColDef = (colDef) => ({
3115
- ...colDef,
3116
- suppressSizeToFit: (sizeColumns === 'auto' || sizeColumns === 'auto-skip-headers') && !colDef.flex,
3117
- sortable: colDef.sortable && params.defaultColDef?.sortable !== false,
3118
- });
3125
+ const adjustColDef = (colDef) => {
3126
+ const flex = colDef.flex ?? (sizeColumns === 'fit' ? 1 : undefined);
3127
+ return {
3128
+ ...colDef,
3129
+ // You cannot pass a width to a flex
3130
+ width: !!colDef.flex ? undefined : colDef.width,
3131
+ flexAutoSizeWidth: colDef.width,
3132
+ // If this is allowed flex columns don't size based on flex
3133
+ suppressSizeToFit: true,
3134
+ // Auto-sizing flex columns breaks everything
3135
+ flex,
3136
+ suppressAutoSize: !!flex,
3137
+ sortable: colDef.sortable && params.defaultColDef?.sortable !== false,
3138
+ };
3139
+ };
3119
3140
  return columnDefs.map((colDef) => adjustColDefOrGroup(colDef));
3120
3141
  }, [columnDefs, params.defaultColDef?.sortable, sizeColumns]);
3121
3142
  /**
@@ -3140,7 +3161,7 @@ const Grid = ({ 'data-testid': dataTestId, defaultPostSort = true, rowSelection
3140
3161
  if (sizeColumns === 'auto' || skipHeader) {
3141
3162
  defer(() => {
3142
3163
  if (hasSetContentSize.current) {
3143
- autoSizeColumns({
3164
+ void autoSizeColumns({
3144
3165
  skipHeader,
3145
3166
  userSizedColIds: new Set(userSizedColIds.current.keys()),
3146
3167
  colIds: colIdsEdited.current,
@@ -3295,7 +3316,7 @@ const Grid = ({ 'data-testid': dataTestId, defaultPostSort = true, rowSelection
3295
3316
  }, [columnDefs, params.loading, params.noRowsMatchingOverlayText, params.noRowsOverlayText, rowData, rowHeight]);
3296
3317
  const selectionColumnDef = useMemo(() => {
3297
3318
  // Note this has to be 1 for hidden otherwise ag-grid does crazy things whilst resizing
3298
- const selectWidth = params.hideSelectColumn ? 0 : selectable && params.onRowDragEnd ? 76 : 48;
3319
+ const selectWidth = params.onRowDragEnd ? 76 : 48;
3299
3320
  return {
3300
3321
  suppressNavigable: params.hideSelectColumn,
3301
3322
  rowDrag: !!params.onRowDragEnd,
@@ -3305,6 +3326,8 @@ const Grid = ({ 'data-testid': dataTestId, defaultPostSort = true, rowSelection
3305
3326
  headerComponentParams: {
3306
3327
  exportable: false,
3307
3328
  },
3329
+ suppressAutoSize: true,
3330
+ suppressSizeToFit: true,
3308
3331
  headerClass: clsx('ag-header-hide-default-select', params.onRowDragEnd && 'ag-header-select-draggable'),
3309
3332
  headerComponent: rowSelection == 'multiple' ? GridHeaderSelect : undefined,
3310
3333
  suppressHeaderKeyboardEvent: (e) => {
@@ -3334,13 +3357,22 @@ const Grid = ({ 'data-testid': dataTestId, defaultPostSort = true, rowSelection
3334
3357
  selectColumnPinned,
3335
3358
  selectable,
3336
3359
  ]);
3360
+ const onGridSizeChanged = useCallback((event) => {
3361
+ if (sizeColumns === 'fit' || (['auto', 'auto-skip-headers'].includes(sizeColumns) && hasSetContentSize.current)) {
3362
+ event.api.sizeColumnsToFit();
3363
+ }
3364
+ }, [sizeColumns]);
3337
3365
  return (jsxs("div", { "data-testid": dataTestId, className: clsx('Grid-container', theme, 'theme-specific', staleGrid && 'Grid-sortIsStale', gridReady && rowData && autoSized && 'Grid-ready'), children: [gridContextMenu.component, jsx("div", { style: { flex: 1 }, ref: gridDivRef, children: jsx(AgGridReact, { theme: 'legacy', rowSelection: selectable
3338
3366
  ? {
3339
3367
  enableSelectionWithoutKeys: params.enableSelectionWithoutKeys ?? false,
3340
3368
  enableClickSelection: params.enableClickSelection ?? false,
3341
3369
  mode: rowSelection === 'single' ? 'singleRow' : 'multiRow',
3370
+ ...(params.hideSelectColumn && {
3371
+ checkboxes: false,
3372
+ headerCheckbox: false,
3373
+ }),
3342
3374
  }
3343
- : undefined, rowHeight: rowHeight, animateRows: params.animateRows ?? false, rowClassRules: params.rowClassRules, getRowId: getRowId, suppressColumnVirtualisation: suppressColumnVirtualization, suppressClickEdit: true, onColumnVisible: setInitialContentSize, onRowDataUpdated: onRowDataUpdated, onCellFocused: onCellFocused, onCellKeyDown: onCellKeyPress, onCellClicked: onCellClicked, onCellDoubleClicked: onCellDoubleClick, onCellEditingStopped: onCellEditingStopped, domLayout: params.domLayout, onColumnResized: onColumnResized, defaultColDef: defaultColDef, columnDefs: columnDefsAdjusted, selectionColumnDef: selectionColumnDef, rowData: rowData, postSortRows: params.onRowDragEnd || !defaultPostSort ? undefined : postSortRows, onModelUpdated: onModelUpdated, onGridReady: onGridReady, onSortChanged: ensureSelectedRowIsVisible, quickFilterParser: quickFilterParser, onSelectionChanged: synchroniseExternalStateToGridSelection, onColumnMoved: params.onColumnMoved, noRowsOverlayComponent: noRowsOverlayComponent, alwaysShowVerticalScroll: params.alwaysShowVerticalScroll, isExternalFilterPresent: isExternalFilterPresent, doesExternalFilterPass: doesExternalFilterPass, maintainColumnOrder: true, preventDefaultOnContextMenu: true, onCellContextMenu: gridContextMenu.cellContextMenu, rowDragText: params.rowDragText, onRowDragCancel: clearHighlightRowClasses, onRowDragMove: onRowDragMove, onRowDragEnd: onRowDragEnd, suppressCellFocus: params.suppressCellFocus, pinnedTopRowData: params.pinnedTopRowData, pinnedBottomRowData: params.pinnedBottomRowData, onRowClicked: params.onRowClicked, onRowDoubleClicked: params.onRowDoubleClicked, suppressStartEditOnTab: true }) })] }));
3375
+ : undefined, selectionColumnDef: selectionColumnDef, rowHeight: rowHeight, animateRows: params.animateRows ?? false, rowClassRules: params.rowClassRules, getRowId: getRowId, suppressColumnVirtualisation: suppressColumnVirtualization, suppressClickEdit: true, onGridSizeChanged: onGridSizeChanged, onColumnVisible: () => void setInitialContentSize(), onRowDataUpdated: onRowDataUpdated, onCellFocused: onCellFocused, onCellKeyDown: onCellKeyPress, onCellClicked: onCellClicked, onCellDoubleClicked: onCellDoubleClick, onCellEditingStopped: onCellEditingStopped, domLayout: params.domLayout, onColumnResized: onColumnResized, defaultColDef: defaultColDef, columnDefs: columnDefsAdjusted, rowData: rowData, postSortRows: params.onRowDragEnd || !defaultPostSort ? undefined : postSortRows, onModelUpdated: onModelUpdated, onGridReady: onGridReady, onSortChanged: ensureSelectedRowIsVisible, quickFilterParser: quickFilterParser, onSelectionChanged: synchroniseExternalStateToGridSelection, onColumnMoved: params.onColumnMoved, noRowsOverlayComponent: noRowsOverlayComponent, alwaysShowVerticalScroll: params.alwaysShowVerticalScroll, isExternalFilterPresent: isExternalFilterPresent, doesExternalFilterPass: doesExternalFilterPass, maintainColumnOrder: true, preventDefaultOnContextMenu: true, onCellContextMenu: gridContextMenu.cellContextMenu, rowDragText: params.rowDragText, onRowDragCancel: clearHighlightRowClasses, onRowDragMove: onRowDragMove, onRowDragEnd: onRowDragEnd, suppressCellFocus: params.suppressCellFocus, pinnedTopRowData: params.pinnedTopRowData, pinnedBottomRowData: params.pinnedBottomRowData, onRowClicked: params.onRowClicked, onRowDoubleClicked: params.onRowDoubleClicked, suppressStartEditOnTab: true }) })] }));
3344
3376
  };
3345
3377
  const quickFilterParser = (filterStr) => {
3346
3378
  // filter is exact matches exactly groups separated by commas
@@ -5604,7 +5636,7 @@ const GridContextProvider = (props) => {
5604
5636
  * If you don't clear flex column widths ag-grid gets confused and does random sizing's.
5605
5637
  * Then we size the flexed columns.
5606
5638
  */
5607
- const autoSizeColumns = useCallback(({ skipHeader, colIds, userSizedColIds } = {}) => {
5639
+ const autoSizeColumns = useCallback(async ({ skipHeader, colIds, userSizedColIds } = {}) => {
5608
5640
  if (!gridApi || !gridApi.getColumnState()) {
5609
5641
  return null;
5610
5642
  }
@@ -5618,23 +5650,34 @@ const GridContextProvider = (props) => {
5618
5650
  };
5619
5651
  const getFlexColStates = () => getVisibleColStates().filter(colStateFlexed);
5620
5652
  const getNonFlexColStates = () => getVisibleColStates().filter(colStateNotFlexed);
5621
- // If we don't reset the flex columns auto size it causes issues with random resizing of flex columns
5622
- let flexColumns = getFlexColStates();
5653
+ // You cannot autosize flex columns it will break layout randomly
5654
+ // So, a flex column is assumed to be 150 wide, unless width is provided
5655
+ const flexColumns = getFlexColStates().map(colStateId);
5623
5656
  let width = 0;
5624
- if (!isEmpty(flexColumns)) {
5625
- gridApi.autoSizeColumns(flexColumns.map(colStateId), skipHeader);
5626
- const flexColumnIds = flexColumns.map(colStateId);
5627
- flexColumns = getVisibleColStates().filter((colState) => flexColumnIds.includes(colState.colId));
5628
- width += sumBy(flexColumns.filter((col) => !col.hide), 'width');
5629
- gridApi.resetColumnState();
5630
- }
5631
- let nonFlexColumns = getNonFlexColStates();
5632
- if (!isEmpty(nonFlexColumns)) {
5633
- gridApi.autoSizeColumns(nonFlexColumns.map(colStateId), skipHeader);
5634
- const nonFlexColumnIds = nonFlexColumns.map(colStateId);
5635
- nonFlexColumns = getVisibleColStates().filter((colState) => nonFlexColumnIds.includes(colState.colId));
5636
- width += sumBy(nonFlexColumns.filter((col) => !col.hide), 'width');
5657
+ flexColumns.forEach((colId) => {
5658
+ const colDef = gridApi.getColumnDef(colId);
5659
+ width += colDef?.flexAutoSizeWidth ?? 200;
5660
+ });
5661
+ const nonFlexColumns = getNonFlexColStates();
5662
+ const nonFlexColumnIds = nonFlexColumns.map(colStateId);
5663
+ gridApi.autoSizeColumns({ colIds: nonFlexColumnIds, skipHeader });
5664
+ const calcSubWidth = () => {
5665
+ const updatedFlexColumns = getVisibleColStates().filter((colState) => nonFlexColumnIds.includes(colState.colId));
5666
+ return sumBy(updatedFlexColumns.filter((col) => !col.hide), 'width');
5667
+ };
5668
+ // ag-grid updates widths asynchronously, so we wait here for the default calculated width to change
5669
+ let lastSubWidth = calcSubWidth();
5670
+ const endTime = Date.now() + 1000;
5671
+ while (Date.now() < endTime) {
5672
+ await wait(40);
5673
+ const newSubWidth = calcSubWidth();
5674
+ if (lastSubWidth !== newSubWidth) {
5675
+ lastSubWidth = newSubWidth;
5676
+ break;
5677
+ }
5637
5678
  }
5679
+ width += lastSubWidth;
5680
+ gridApi.sizeColumnsToFit();
5638
5681
  return {
5639
5682
  width,
5640
5683
  };