@linzjs/step-ag-grid 24.0.0 → 25.0.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.
Files changed (53) hide show
  1. package/dist/GridTheme.scss +1 -1
  2. package/dist/index.css +0 -13
  3. package/dist/src/index.d.ts +2 -0
  4. package/{src/utils → dist/src/utils/__tests__}/testQuick.ts +1 -1
  5. package/{src/utils → dist/src/utils/__tests__}/testUtil.ts +1 -1
  6. package/dist/src/utils/__tests__/vitestUtil.ts +295 -0
  7. package/dist/{step-ag-grid.cjs.js → step-ag-grid.cjs} +4 -4
  8. package/dist/step-ag-grid.cjs.map +1 -0
  9. package/dist/step-ag-grid.esm.js +4 -6
  10. package/dist/step-ag-grid.esm.js.map +1 -1
  11. package/dist/vite.config.d.ts +1 -1
  12. package/package.json +23 -27
  13. package/src/components/GridCell.test.tsx +2 -0
  14. package/src/contexts/GridContextProvider.test.tsx +1 -0
  15. package/src/contexts/GridContextProvider.tsx +1 -2
  16. package/src/index.ts +2 -0
  17. package/src/lui/ActionButton.scss +2 -2
  18. package/src/lui/FormError.scss +3 -4
  19. package/src/lui/TextInputFormatted.scss +1 -1
  20. package/src/lui/reactUtils.test.tsx +1 -0
  21. package/src/lui/timeoutHook.test.tsx +7 -6
  22. package/src/stories/grid/GridDragRow.stories.tsx +1 -1
  23. package/src/stories/grid/GridFilterButtons.stories.tsx +1 -1
  24. package/src/stories/grid/GridNonEditableRow.stories.tsx +1 -1
  25. package/src/stories/grid/GridPinnedRow.stories.tsx +1 -1
  26. package/src/stories/grid/GridPopoutContextMenu.stories.tsx +1 -1
  27. package/src/stories/grid/GridPopoutEditBoolean.stories.tsx +1 -1
  28. package/src/stories/grid/GridPopoutEditGeneric.stories.tsx +1 -1
  29. package/src/stories/grid/GridPopoutEditGenericTextArea.stories.tsx +1 -1
  30. package/src/stories/grid/GridPopoverEditBearing.stories.tsx +1 -1
  31. package/src/stories/grid/GridPopoverEditDropDown.stories.tsx +1 -1
  32. package/src/stories/grid/GridPopoverEditMultiSelect.stories.tsx +1 -1
  33. package/src/stories/grid/GridPopoverEditMultiSelectGrid.stories.tsx +1 -1
  34. package/src/stories/grid/GridReadOnly.stories.tsx +1 -1
  35. package/src/stories/grid/interactions/GridKeyboardInteractions.stories.tsx +1 -1
  36. package/src/styles/Grid.scss +9 -9
  37. package/src/styles/GridIcon.scss +6 -6
  38. package/src/styles/GridPopoverMenu.scss +3 -3
  39. package/src/styles/GridTheme.scss +1 -1
  40. package/src/styles/react-menu-customisations.scss +26 -41
  41. package/src/utils/__tests__/storybookTestUtil.ts +4 -0
  42. package/src/utils/__tests__/testQuick.ts +157 -0
  43. package/src/utils/__tests__/testUtil.ts +294 -0
  44. package/src/utils/__tests__/vitestUtil.ts +295 -0
  45. package/src/utils/bearing.test.ts +3 -1
  46. package/src/utils/textMatcher.test.ts +2 -1
  47. package/src/utils/textValidator.test.ts +5 -6
  48. package/src/utils/util.test.ts +2 -1
  49. package/dist/src/utils/storybookTestUtil.d.ts +0 -3
  50. package/dist/src/utils/testQuick.d.ts +0 -62
  51. package/dist/src/utils/testUtil.d.ts +0 -46
  52. package/dist/step-ag-grid.cjs.js.map +0 -1
  53. /package/{src/utils → dist/src/utils/__tests__}/storybookTestUtil.ts +0 -0
@@ -1,4 +1,4 @@
1
- @use "@linzjs/lui/dist/scss/Core" as lui;
1
+ @use "../../node_modules/@linzjs/lui/dist/scss/Core" as lui;
2
2
  @use "ag-grid-community/styles" as ag;
3
3
 
4
4
  // ag-grid likes to add 1px to this, so we subtract to compensate
package/dist/index.css CHANGED
@@ -78,12 +78,6 @@
78
78
  /**
79
79
  * Here are styles for lui select menu
80
80
  */
81
- @media screen and (min-width: 480px) {
82
- .lui-select-menu.szh-menu-container {
83
- position: absolute;
84
- }
85
- }
86
-
87
81
  .lui-select-menu.szh-menu {
88
82
  z-index: 900;
89
83
  width: 92vw;
@@ -93,13 +87,6 @@
93
87
  font-style: normal;
94
88
  font-weight: 300;
95
89
  }
96
- @media screen and (min-width: 480px) {
97
- .lui-select-menu.szh-menu {
98
- overflow: visible;
99
- height: auto;
100
- width: 240px;
101
- }
102
- }
103
90
 
104
91
  .lui-select-menuItem {
105
92
  padding: 0.5rem 0.75rem 0.5rem 0.5rem;
@@ -14,4 +14,6 @@ export * from './react-menu3/index';
14
14
  export * from './react-menu3/types';
15
15
  export * from './utils/bearing';
16
16
  export * from './utils/deferredPromise';
17
+ export * from './utils/textMatcher';
18
+ export * from './utils/textValidator';
17
19
  export * from './utils/util';
@@ -7,7 +7,7 @@
7
7
  */
8
8
  import { IconName } from '@linzjs/lui/dist/components/LuiIcon/LuiIcon';
9
9
 
10
- import { wait } from './util';
10
+ import { wait } from '../util';
11
11
 
12
12
  const queryAllBySelector = <T extends HTMLElement>(selector: string, container: HTMLElement = document.body): T[] =>
13
13
  Array.from(container.querySelectorAll<T>(selector));
@@ -284,7 +284,7 @@ export const clickActionButton = async (text: string, container?: HTMLElement):
284
284
  };
285
285
 
286
286
  export const waitForGridReady = async (props?: { grid?: HTMLElement; timeout?: number }) =>
287
- waitFor(() => expect(getAllQuick({ classes: '.Grid-ready' }, props?.grid)).toBeInTheDocument(), {
287
+ waitFor(() => expect(getAllQuick({ classes: '.Grid-ready' }, props?.grid)).toBeDefined(), {
288
288
  timeout: props?.timeout ?? 5000,
289
289
  });
290
290
 
@@ -0,0 +1,295 @@
1
+ import { act, waitFor, within } from '@testing-library/react';
2
+ import userEvent from '@testing-library/user-event';
3
+ import { isEqual } from 'lodash-es';
4
+ import { expect } from 'vitest';
5
+
6
+ import { findQuick, getAllQuick, getMatcher, getQuick, IQueryQuick, queryQuick } from './testQuick';
7
+
8
+ let user = userEvent;
9
+ /**
10
+ * allow external userEvent to be used
11
+ * @param customisedUserEvent
12
+ */
13
+ export const setUpUserEvent = (customisedUserEvent: any) => {
14
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
15
+ user = customisedUserEvent;
16
+ };
17
+
18
+ export const countRows = (within?: HTMLElement): number => {
19
+ return getAllQuick({ tagName: `div[row-id]:not(:empty)` }, within).length;
20
+ };
21
+
22
+ export const findRowByIndex = async (rowIndex: number | string, within?: HTMLElement): Promise<HTMLDivElement> => {
23
+ await waitFor(() => {
24
+ expect(getAllQuick({ classes: '.ag-row' }).length > 0).toBe(true);
25
+ });
26
+ //if this is not wrapped in an act console errors are logged during testing
27
+ let row!: HTMLDivElement;
28
+ await act(async () => {
29
+ row = await findQuick<HTMLDivElement>(
30
+ { tagName: `.ag-center-cols-container div[row-index='${rowIndex}']:not(:empty)` },
31
+ within,
32
+ );
33
+ let combineChildren = [...Array.from(row.children)];
34
+
35
+ const leftCols = queryQuick<HTMLDivElement>(
36
+ { tagName: `.ag-pinned-left-cols-container div[row-index='${rowIndex}']` },
37
+ within,
38
+ );
39
+ if (leftCols) {
40
+ combineChildren = [...Array.from(leftCols.children), ...combineChildren];
41
+ }
42
+
43
+ const rightCols = queryQuick<HTMLDivElement>(
44
+ { tagName: `.ag-pinned-right-cols-container div[row-index='${rowIndex}']` },
45
+ within,
46
+ );
47
+ if (rightCols) {
48
+ combineChildren = [...Array.from(rightCols.children), ...combineChildren];
49
+ }
50
+
51
+ row.replaceChildren(...combineChildren);
52
+ });
53
+ return row;
54
+ };
55
+
56
+ export const findRow = async (rowId: number | string, within?: HTMLElement): Promise<HTMLDivElement> => {
57
+ await waitFor(() => {
58
+ expect(getAllQuick({ classes: '.ag-row' }).length > 0).toBe(true);
59
+ });
60
+ //if this is not wrapped in an act console errors are logged during testing
61
+ let row!: HTMLDivElement;
62
+ await act(async () => {
63
+ row = await findQuick<HTMLDivElement>(
64
+ { tagName: `.ag-center-cols-container div[row-id='${rowId}']:not(:empty)` },
65
+ within,
66
+ );
67
+ let combineChildren = [...Array.from(row.children)];
68
+
69
+ const leftCols = queryQuick<HTMLDivElement>(
70
+ { tagName: `.ag-pinned-left-cols-container div[row-id='${rowId}']` },
71
+ within,
72
+ );
73
+ if (leftCols) {
74
+ combineChildren = [...Array.from(leftCols.children), ...combineChildren];
75
+ }
76
+
77
+ const rightCols = queryQuick<HTMLDivElement>(
78
+ { tagName: `.ag-pinned-right-cols-container div[row-id='${rowId}']` },
79
+ within,
80
+ );
81
+ if (rightCols) {
82
+ combineChildren = [...Array.from(rightCols.children), ...combineChildren];
83
+ }
84
+
85
+ row.replaceChildren(...combineChildren);
86
+ });
87
+ return row;
88
+ };
89
+
90
+ export const queryRow = (rowId: number | string, within?: HTMLElement): HTMLDivElement | null => {
91
+ return queryQuick<HTMLDivElement>({ tagName: `div[row-id='${rowId}']:not(:empty)` }, within);
92
+ };
93
+
94
+ const _selectRow = async (
95
+ select: 'select' | 'deselect' | 'toggle',
96
+ rowId: string | number,
97
+ within?: HTMLElement,
98
+ ): Promise<void> => {
99
+ const row = await findRow(rowId, within);
100
+ const isSelected = row.className.includes('ag-row-selected');
101
+ if (select === 'toggle' || (select === 'select' && !isSelected) || (select === 'deselect' && isSelected)) {
102
+ const cell = await findCell(rowId, 'selection', within);
103
+ await user.click(cell);
104
+ await waitFor(async () => {
105
+ const row = await findRow(rowId, within);
106
+ const nowSelected = row.className.includes('ag-row-selected');
107
+ if (nowSelected === isSelected) throw `Row ${rowId} won't select`;
108
+ });
109
+ }
110
+ };
111
+
112
+ export const selectRow = async (rowId: string | number, within?: HTMLElement): Promise<void> =>
113
+ _selectRow('select', rowId, within);
114
+
115
+ export const deselectRow = async (rowId: string | number, within?: HTMLElement): Promise<void> =>
116
+ _selectRow('deselect', rowId, within);
117
+
118
+ export const findCell = async (rowId: number | string, colId: string, within?: HTMLElement): Promise<HTMLElement> => {
119
+ const row = await findRow(rowId, within);
120
+ return await findQuick({ tagName: `[col-id='${colId}']` }, row);
121
+ };
122
+
123
+ export const findCellContains = async (
124
+ rowId: number | string,
125
+ colId: string,
126
+ text: string | RegExp,
127
+ within?: HTMLElement,
128
+ ) => {
129
+ return await waitFor(
130
+ async () => {
131
+ const row = await findRow(rowId, within);
132
+ return getQuick({ tagName: `[col-id='${colId}']`, text }, row);
133
+ },
134
+ { timeout: 10000 },
135
+ );
136
+ };
137
+
138
+ export const selectCell = async (rowId: string | number, colId: string, within?: HTMLElement): Promise<void> => {
139
+ const cell = await findCell(rowId, colId, within);
140
+ await user.click(cell);
141
+ };
142
+
143
+ export const editCell = async (rowId: number | string, colId: string, within?: HTMLElement): Promise<void> => {
144
+ await waitFor(
145
+ async () => {
146
+ const cell = await findCell(rowId, colId, within);
147
+ await user.dblClick(cell);
148
+ await waitFor(findOpenPopover, { timeout: 1000 });
149
+ },
150
+ { timeout: 10000 },
151
+ );
152
+ };
153
+
154
+ export const isCellReadOnly = async (rowId: number | string, colId: string, within?: HTMLElement): Promise<boolean> => {
155
+ const cell = await findCell(rowId, colId, within);
156
+ return cell.className.includes('GridCell-readonly');
157
+ };
158
+
159
+ export const findOpenPopover = () => findQuick({ classes: '.szh-menu--state-open' });
160
+
161
+ export const queryMenuOption = async (menuOptionText: string | RegExp): Promise<HTMLElement | null> => {
162
+ const openMenu = await findOpenPopover();
163
+ const els = await within(openMenu).findAllByRole('menuitem');
164
+ const matcher = getMatcher(menuOptionText);
165
+ const result = els.find(matcher);
166
+ return result ?? null;
167
+ };
168
+
169
+ export const findMenuOption = async (menuOptionText: string | RegExp): Promise<HTMLElement> => {
170
+ return await waitFor(
171
+ async () => {
172
+ const menuOption = await queryMenuOption(menuOptionText);
173
+ if (menuOption == null) {
174
+ throw Error(`Unable to find menu option ${menuOptionText}`);
175
+ }
176
+ return menuOption;
177
+ },
178
+ { timeout: 5000 },
179
+ );
180
+ };
181
+
182
+ export const validateMenuOptions = async (
183
+ rowId: number | string,
184
+ colId: string,
185
+ expectedMenuOptions: Array<string>,
186
+ ): Promise<boolean> => {
187
+ await editCell(rowId, colId);
188
+ const openMenu = await findOpenPopover();
189
+ const actualOptions = (await within(openMenu).findAllByRole('menuitem')).map((menuItem) => menuItem.textContent);
190
+ return isEqual(actualOptions, expectedMenuOptions);
191
+ };
192
+
193
+ export const clickMenuOption = async (menuOptionText: string | RegExp): Promise<void> => {
194
+ const menuOption = await findMenuOption(menuOptionText);
195
+ await user.click(menuOption);
196
+ };
197
+
198
+ export const openAndClickMenuOption = async (
199
+ rowId: number | string,
200
+ colId: string,
201
+ menuOptionText: string | RegExp,
202
+ within?: HTMLElement,
203
+ ): Promise<void> => {
204
+ await editCell(rowId, colId, within);
205
+ await clickMenuOption(menuOptionText);
206
+ };
207
+
208
+ export const openAndFindMenuOption = async (
209
+ rowId: number | string,
210
+ colId: string,
211
+ menuOptionText: string | RegExp,
212
+ within?: HTMLElement,
213
+ ): Promise<HTMLElement> => {
214
+ await editCell(rowId, colId, within);
215
+ return await findMenuOption(menuOptionText);
216
+ };
217
+
218
+ export const getMultiSelectOptions = async () => {
219
+ const openMenu = await findOpenPopover();
220
+ return getAllQuick<HTMLInputElement>({ role: 'menuitem', child: { tagName: 'input,textarea' } }, openMenu).map(
221
+ (input) => {
222
+ return {
223
+ v: input.value,
224
+ c: input.checked ?? true,
225
+ };
226
+ },
227
+ );
228
+ };
229
+
230
+ export const findMultiSelectOption = async (value: string): Promise<HTMLElement> => {
231
+ const openMenu = await findOpenPopover();
232
+ return getQuick({ role: 'menuitem', child: { tagName: `input[value='${value}']` } }, openMenu);
233
+ };
234
+
235
+ export const clickMultiSelectOption = async (value: string): Promise<void> => {
236
+ const menuItem = await findMultiSelectOption(value);
237
+ menuItem.parentElement && (await user.click(menuItem.parentElement));
238
+ };
239
+
240
+ const typeInput = async (value: string, filter: IQueryQuick): Promise<void> => {
241
+ const openMenu = await findOpenPopover();
242
+ const input = await findQuick(filter, openMenu);
243
+ await user.clear(input);
244
+ //'typing' an empty string will cause a console error, and it's also unnecessary after the previous clear call
245
+ if (value.length > 0) {
246
+ await user.type(input, value);
247
+ }
248
+ };
249
+
250
+ export const typeOnlyInput = async (value: string): Promise<void> =>
251
+ typeInput(value, { child: { tagName: "input[type='text'], textarea" } });
252
+
253
+ export const typeInputByLabel = async (value: string, labelText: string): Promise<void> => {
254
+ const labels = getAllQuick({ child: { tagName: 'label' } }).filter((l) => l.textContent === labelText);
255
+ if (labels.length === 0) {
256
+ throw Error(`Label not found for text: ${labelText}`);
257
+ }
258
+ if (labels.length > 1) {
259
+ throw Error(`Multiple labels found for text: ${labelText}`);
260
+ }
261
+ const inputId = labels[0].getAttribute('for');
262
+ await typeInput(value, { child: { tagName: `input[id='${inputId}'], textarea[id='${inputId}']` } });
263
+ };
264
+
265
+ export const typeInputByPlaceholder = async (value: string, placeholder: string): Promise<void> =>
266
+ typeInput(value, {
267
+ child: { tagName: `input[placeholder='${placeholder}'], textarea[placeholder='${placeholder}']` },
268
+ });
269
+
270
+ export const typeOtherInput = async (value: string): Promise<void> =>
271
+ typeInput(value, { classes: '.subComponent', child: { tagName: "input[type='text']" } });
272
+
273
+ export const typeOtherTextArea = async (value: string): Promise<void> =>
274
+ typeInput(value, { classes: '.subComponent', child: { tagName: 'textarea' } });
275
+
276
+ export const closeMenu = () => user.click(document.body);
277
+ export const closePopover = () => user.click(document.body);
278
+
279
+ export const findActionButton = (text: string, container?: HTMLElement): Promise<HTMLElement> =>
280
+ findQuick({ tagName: 'button', child: { classes: '.ActionButton-minimalAreaDisplay', text: text } }, container);
281
+
282
+ export const clickActionButton = async (text: string, container?: HTMLElement): Promise<void> => {
283
+ const button = await findActionButton(text, container);
284
+ await user.click(button);
285
+ };
286
+
287
+ export const waitForGridReady = async (props?: { grid?: HTMLElement; timeout?: number }) =>
288
+ waitFor(() => expect(getAllQuick({ classes: '.Grid-ready' }, props?.grid)).toBeDefined(), {
289
+ timeout: props?.timeout ?? 5000,
290
+ });
291
+
292
+ export const waitForGridRows = async (props?: { grid?: HTMLElement; timeout?: number }) =>
293
+ waitFor(() => expect(getAllQuick({ classes: '.ag-row' }, props?.grid).length > 0).toBe(true), {
294
+ timeout: props?.timeout ?? 5000,
295
+ });
@@ -5092,9 +5092,7 @@ const GridContextProvider = (props) => {
5092
5092
  gridApi && gridApi.redrawRows(rowNodes ? { rowNodes } : undefined);
5093
5093
  }
5094
5094
  catch (ex) {
5095
- // Hide errors in jest, but log them in browser
5096
- if (typeof jest === 'undefined')
5097
- console.error(ex);
5095
+ console.error(ex);
5098
5096
  }
5099
5097
  }, 50), [gridApi]);
5100
5098
  // waitForExternallySelectedItemsToBeInSync can't use the state as it won't be updated during function execution
@@ -5468,6 +5466,7 @@ exports.PopoutMenuSeparator = PopoutMenuSeparator;
5468
5466
  exports.SubMenu = SubMenu;
5469
5467
  exports.TextAreaInput = TextAreaInput;
5470
5468
  exports.TextInputFormatted = TextInputFormatted;
5469
+ exports.TextInputValidator = TextInputValidator;
5471
5470
  exports.bearingCorrectionRangeValidator = bearingCorrectionRangeValidator;
5472
5471
  exports.bearingCorrectionValueFormatter = bearingCorrectionValueFormatter;
5473
5472
  exports.bearingNumberParser = bearingNumberParser;
@@ -5487,6 +5486,7 @@ exports.isNotEmpty = isNotEmpty;
5487
5486
  exports.sanitiseFileName = sanitiseFileName;
5488
5487
  exports.stringByteLengthIsInvalid = stringByteLengthIsInvalid;
5489
5488
  exports.suppressCellKeyboardEvents = suppressCellKeyboardEvents;
5489
+ exports.textMatch = textMatch;
5490
5490
  exports.useDeferredPromise = useDeferredPromise;
5491
5491
  exports.useGridContext = useGridContext;
5492
5492
  exports.useGridContextMenu = useGridContextMenu;
@@ -5496,4 +5496,4 @@ exports.useGridPopoverHook = useGridPopoverHook;
5496
5496
  exports.useMenuState = useMenuState;
5497
5497
  exports.usePostSortRowsHook = usePostSortRowsHook;
5498
5498
  exports.wait = wait;
5499
- //# sourceMappingURL=step-ag-grid.cjs.js.map
5499
+ //# sourceMappingURL=step-ag-grid.cjs.map