@linzjs/step-ag-grid 30.0.0 → 30.2.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": "30.0.0",
5
+ "version": "30.2.0",
6
6
  "keywords": [
7
7
  "aggrid",
8
8
  "ag-grid",
@@ -45,7 +45,6 @@ const FilterUI: React.FC<FilterUIProps> = ({
45
45
  return (
46
46
  <div className="GridFilterColsMultiSelect">
47
47
  <span className="LuiSelect-label-text">Filter column</span>
48
-
49
48
  <LuiCheckboxInput
50
49
  className="LuiCheckboxInput-selectAll"
51
50
  label={'Select All'}
@@ -75,6 +74,9 @@ export class GridFilterColumnsMultiSelect implements IFilterComp {
75
74
  private gui!: HTMLElement;
76
75
  private labelFormatter?: (value: string) => string;
77
76
  private reactRoot: Root | null = null;
77
+ private filterButtonClickListener: ((e: Event) => void) | null = null;
78
+ private filterButton: Element | null = null;
79
+ private hasOpened = false;
78
80
 
79
81
  private normalizeCellValue(value: unknown): string {
80
82
  if (typeof value === 'string') return value.trim() === '' ? EMPTY_KEY : value;
@@ -123,11 +125,31 @@ export class GridFilterColumnsMultiSelect implements IFilterComp {
123
125
  this.gui = document.createElement('div');
124
126
  this.reactRoot = createRoot(this.gui);
125
127
  this.render();
128
+ this.setupFilterButtonListener();
129
+ }
130
+
131
+ private setupFilterButtonListener(): void {
132
+ const columnId = this.params.column.getColId();
133
+ this.filterButton = document.querySelector(`[col-id="${columnId}"] .ag-header-cell-filter-button`);
134
+
135
+ if (this.filterButton) {
136
+ this.filterButtonClickListener = (e: Event) => {
137
+ if (this.hasOpened) {
138
+ e.stopPropagation();
139
+ e.preventDefault();
140
+ this.params.api.hidePopupMenu();
141
+ this.hasOpened = false;
142
+ } else {
143
+ this.hasOpened = true;
144
+ }
145
+ };
146
+
147
+ this.filterButton.addEventListener('click', this.filterButtonClickListener, true);
148
+ }
126
149
  }
127
150
 
128
151
  private render(): void {
129
152
  if (!this.reactRoot) return;
130
-
131
153
  this.reactRoot.render(
132
154
  <FilterUI
133
155
  allValues={this.allValues}
@@ -196,6 +218,12 @@ export class GridFilterColumnsMultiSelect implements IFilterComp {
196
218
  }
197
219
 
198
220
  destroy(): void {
221
+ if (this.filterButtonClickListener && this.filterButton) {
222
+ this.filterButton.removeEventListener('click', this.filterButtonClickListener, true);
223
+ this.filterButtonClickListener = null;
224
+ this.filterButton = null;
225
+ }
226
+
199
227
  if (this.reactRoot) {
200
228
  this.reactRoot.unmount();
201
229
  this.reactRoot = null;
@@ -2,14 +2,21 @@ import clsx from 'clsx';
2
2
 
3
3
  import { GenericCellEditorProps, GridCell } from '../GridCell';
4
4
  import { GridFormDropDown, GridFormDropDownProps } from '../gridForm/GridFormDropDown';
5
+ import { GridIcon } from '../GridIcon';
5
6
  import { GenericCellColDef } from '../gridRender/GridRenderGenericCell';
6
7
  import { ColDefT, GridBaseRow } from '../types';
7
8
 
8
9
  export const GridPopoverEditDropDown = <TData extends GridBaseRow, TValue = any, TOptionValue = any>(
9
10
  colDef: GenericCellColDef<TData, TValue>,
10
11
  props: GenericCellEditorProps<GridFormDropDownProps<TData, TOptionValue>>,
11
- ): ColDefT<TData, TValue> =>
12
- GridCell<TData, TValue, GridFormDropDownProps<TData, TOptionValue>>(colDef, {
12
+ ): ColDefT<TData, TValue> => {
13
+ colDef.cellRendererParams = {
14
+ rightHoverElement: (
15
+ <GridIcon icon={'ic_arrow_drop_down'} title={''} className={'GridCell-editableIcon GridCell-dropDownIcon'} />
16
+ ),
17
+ ...colDef.cellRendererParams,
18
+ };
19
+ return GridCell<TData, TValue, GridFormDropDownProps<TData, TOptionValue>>(colDef, {
13
20
  editor: GridFormDropDown,
14
21
  ...props,
15
22
  editorParams: {
@@ -24,3 +31,4 @@ export const GridPopoverEditDropDown = <TData extends GridBaseRow, TValue = any,
24
31
  ),
25
32
  },
26
33
  });
34
+ };
@@ -41,9 +41,20 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
41
41
  const enableMultilineBulkEditRef = useRef(false);
42
42
  const idsBeforeUpdate = useRef<TData['id'][]>([]);
43
43
  const prePopupFocusedCell = useRef<CellPosition>();
44
- const [externallySelectedItemsAreInSync, setExternallySelectedItemsAreInSync] = useState(false);
44
+ const [externallySelectedItemsAreInSync, _setExternallySelectedItemsAreInSync] = useState(false);
45
45
  const externalFilters = useRef<GridFilterExternal<TData>[]>([]);
46
46
 
47
+ // waitForExternallySelectedItemsToBeInSync can't use the state as it won't be updated during function execution
48
+ const externallySelectedItemsAreInSyncRef = useRef(false);
49
+
50
+ const setExternallySelectedItemsAreInSync = useCallback(
51
+ (cond: boolean) => {
52
+ _setExternallySelectedItemsAreInSync(cond);
53
+ externallySelectedItemsAreInSyncRef.current = cond;
54
+ },
55
+ [_setExternallySelectedItemsAreInSync],
56
+ );
57
+
47
58
  const setQuickFilter = useCallback(
48
59
  (filter: string) => {
49
60
  // If we don't clear the focused cell focus switches back to grid when typing in the quick filter input
@@ -539,12 +550,6 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
539
550
  }
540
551
  }, [gridApi]);
541
552
 
542
- // waitForExternallySelectedItemsToBeInSync can't use the state as it won't be updated during function execution
543
- const externallySelectedItemsAreInSyncRef = useRef(false);
544
- useEffect(() => {
545
- externallySelectedItemsAreInSyncRef.current = externallySelectedItemsAreInSync;
546
- }, [externallySelectedItemsAreInSync]);
547
-
548
553
  const waitForExternallySelectedItemsToBeInSync = useCallback(async () => {
549
554
  if (!hasExternallySelectedItemsRef.current) {
550
555
  externallySelectedItemsAreInSyncRef.current = true;
@@ -613,7 +618,7 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
613
618
  startCellEditingInProgressRef.current = false;
614
619
  }
615
620
  },
616
- [anyUpdating, gridApi, prePopupOps, waitForExternallySelectedItemsToBeInSync],
621
+ [anyUpdating, gridApi, prePopupOps, setExternallySelectedItemsAreInSync, waitForExternallySelectedItemsToBeInSync],
617
622
  );
618
623
 
619
624
  const bulkEditingCompleteCallbackRef = useRef<() => Promise<void> | void>();
@@ -159,7 +159,11 @@ const filterGridUsingColumnFilter = async (filterString: string): Promise<void>
159
159
  });
160
160
  const headerCellFilterButton = await findQuick({ classes: `.ag-header-cell-filter-button` });
161
161
  await expect(headerCellFilterButton).toBeInTheDocument();
162
- await user.click(headerCellFilterButton);
162
+ // Check if menu is already open
163
+ const existingMenu = document.querySelector('.ag-menu');
164
+ if (!existingMenu) {
165
+ await user.click(headerCellFilterButton);
166
+ }
163
167
  const canvas = within(document.body);
164
168
  const regex = new RegExp(filterString, 'i'); // case‑insensitive
165
169
  const filterCheckbox = await canvas.findByRole('checkbox', { name: regex });
@@ -190,6 +190,18 @@ $grid-base-font-size: calc(#{lui.$base-font-size} - 1px);
190
190
  align-items: center;
191
191
  }
192
192
 
193
+ .ag-cell span.GridCell-dropDownIcon {
194
+ fill: lui.$charcoal;
195
+ max-width: 26px;
196
+ width: 26px;
197
+ visibility: hidden;
198
+ }
199
+
200
+ .ag-cell.ag-cell-inline-editing span.GridCell-dropDownIcon {
201
+ max-width: 24px;
202
+ width: 24px;
203
+ }
204
+
193
205
  .ag-cell .GridCell-editableIcon {
194
206
  fill: lui.$silver;
195
207
  visibility: hidden;