@linzjs/step-ag-grid 14.1.2 → 14.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/README.md +9 -0
- package/dist/src/components/Grid.d.ts +10 -1
- package/dist/src/components/GridCell.d.ts +1 -0
- package/dist/src/contexts/GridContext.d.ts +11 -5
- package/dist/src/contexts/GridUpdatingContext.d.ts +1 -0
- package/dist/src/lui/timeoutHook.d.ts +6 -0
- package/dist/step-ag-grid.esm.js +371 -134
- package/dist/step-ag-grid.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/components/Grid.tsx +219 -34
- package/src/components/GridCell.tsx +6 -2
- package/src/components/GridPopoverHook.tsx +4 -4
- package/src/components/gridForm/GridFormDropDown.tsx +1 -8
- package/src/components/gridPopoverEdit/GridPopoverMenu.tsx +1 -0
- package/src/contexts/GridContext.tsx +19 -3
- package/src/contexts/GridContextProvider.tsx +107 -43
- package/src/contexts/GridUpdatingContext.tsx +5 -0
- package/src/contexts/GridUpdatingContextProvider.tsx +8 -3
- package/src/lui/timeoutHook.tsx +13 -0
- package/src/react-menu3/components/MenuList.tsx +21 -1
- package/src/stories/grid/GridPopoutEditGenericTextArea.stories.tsx +7 -1
- package/src/stories/grid/GridPopoverEditDropDown.stories.tsx +5 -0
- package/src/stories/grid/interactions/GridKeyboardInteractions.stories.tsx +3 -1
|
@@ -8,7 +8,7 @@ import { ReactElement, ReactNode, useCallback, useContext, useEffect, useMemo, u
|
|
|
8
8
|
|
|
9
9
|
import { ColDefT, GridBaseRow } from "../components";
|
|
10
10
|
import { isNotEmpty, sanitiseFileName, wait } from "../utils/util";
|
|
11
|
-
import { GridContext, GridFilterExternal } from "./GridContext";
|
|
11
|
+
import { AutoSizeColumnsProps, AutoSizeColumnsResult, GridContext, GridFilterExternal } from "./GridContext";
|
|
12
12
|
import { GridUpdatingContext } from "./GridUpdatingContext";
|
|
13
13
|
|
|
14
14
|
interface GridContextProps {
|
|
@@ -64,14 +64,13 @@ export const GridContextProvider = <RowType extends GridBaseRow>(props: GridCont
|
|
|
64
64
|
*/
|
|
65
65
|
const ensureRowVisible = useCallback(
|
|
66
66
|
(id: number | string): boolean => {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
});
|
|
67
|
+
if (!gridApi) return false;
|
|
68
|
+
const node = gridApi?.getRowNode(`${id}`);
|
|
69
|
+
if (!node) return false;
|
|
70
|
+
defer(() => gridApi.ensureNodeVisible(node));
|
|
71
|
+
return true;
|
|
73
72
|
},
|
|
74
|
-
[
|
|
73
|
+
[gridApi],
|
|
75
74
|
);
|
|
76
75
|
|
|
77
76
|
const getFirstRowId = useCallback((): number => {
|
|
@@ -211,17 +210,16 @@ export const GridContextProvider = <RowType extends GridBaseRow>(props: GridCont
|
|
|
211
210
|
);
|
|
212
211
|
const firstNode = rowsThatNeedSelecting[0];
|
|
213
212
|
if (firstNode) {
|
|
214
|
-
gridApi.ensureNodeVisible(firstNode);
|
|
213
|
+
defer(() => gridApi.ensureNodeVisible(firstNode));
|
|
215
214
|
const colDefs = gridApi.getColumnDefs();
|
|
216
|
-
if (colDefs
|
|
215
|
+
if (colDefs?.length) {
|
|
217
216
|
const col = colDefs[0] as ColDef; // We don't support ColGroupDef
|
|
218
217
|
const rowIndex = firstNode.rowIndex;
|
|
219
218
|
if (rowIndex != null && col != null) {
|
|
220
219
|
const colId = col.colId;
|
|
221
220
|
// We need to make sure we aren't currently editing a cell otherwise tests will fail
|
|
222
221
|
// as they will start to edit the cell before this stuff has a chance to run
|
|
223
|
-
colId
|
|
224
|
-
defer(() => isEmpty(gridApi.getEditingCells()) && gridApi.setFocusedCell(rowIndex, colId));
|
|
222
|
+
colId && defer(() => isEmpty(gridApi.getEditingCells()) && gridApi.setFocusedCell(rowIndex, colId));
|
|
225
223
|
}
|
|
226
224
|
}
|
|
227
225
|
}
|
|
@@ -337,25 +335,29 @@ export const GridContextProvider = <RowType extends GridBaseRow>(props: GridCont
|
|
|
337
335
|
gridApiOp((gridApi) => {
|
|
338
336
|
const selectedNodes = gridApi.getSelectedNodes();
|
|
339
337
|
if (isEmpty(selectedNodes)) return;
|
|
340
|
-
gridApi.ensureNodeVisible(last(selectedNodes));
|
|
338
|
+
defer(() => gridApi.ensureNodeVisible(last(selectedNodes)));
|
|
341
339
|
});
|
|
342
340
|
}, [gridApiOp]);
|
|
343
341
|
|
|
344
342
|
/**
|
|
345
343
|
* Resize columns to fit container
|
|
346
344
|
*/
|
|
347
|
-
const
|
|
348
|
-
({ skipHeader }
|
|
349
|
-
if (columnApi)
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
345
|
+
const autoSizeColumns = useCallback(
|
|
346
|
+
({ skipHeader, colIds, userSizedColIds }: AutoSizeColumnsProps = {}): AutoSizeColumnsResult => {
|
|
347
|
+
if (!columnApi) return null;
|
|
348
|
+
const colIdsSet = colIds instanceof Set ? colIds : new Set<string>(colIds ?? []);
|
|
349
|
+
columnApi.getColumnState().forEach((col) => {
|
|
350
|
+
const colId = col.colId;
|
|
351
|
+
if ((isEmpty(colIdsSet) || colIdsSet.has(colId)) && !userSizedColIds?.has(colId)) {
|
|
352
|
+
columnApi.autoSizeColumn(colId, skipHeader);
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
return {
|
|
356
|
+
width: sumBy(
|
|
357
|
+
columnApi.getColumnState().filter((col) => !col.hide),
|
|
358
|
+
"width",
|
|
359
|
+
),
|
|
360
|
+
};
|
|
359
361
|
},
|
|
360
362
|
[columnApi],
|
|
361
363
|
);
|
|
@@ -364,26 +366,83 @@ export const GridContextProvider = <RowType extends GridBaseRow>(props: GridCont
|
|
|
364
366
|
* Resize columns to fit container
|
|
365
367
|
*/
|
|
366
368
|
const sizeColumnsToFit = useCallback((): void => {
|
|
367
|
-
|
|
368
|
-
gridApi.sizeColumnsToFit();
|
|
369
|
-
}
|
|
369
|
+
gridApi && gridApi.sizeColumnsToFit();
|
|
370
370
|
}, [gridApi]);
|
|
371
371
|
|
|
372
372
|
const stopEditing = useCallback((): void => {
|
|
373
|
+
if (!gridApi) return;
|
|
373
374
|
if (prePopupFocusedCell.current) {
|
|
374
375
|
gridApi?.setFocusedCell(prePopupFocusedCell.current.rowIndex, prePopupFocusedCell.current.column);
|
|
375
376
|
}
|
|
376
|
-
|
|
377
|
-
}, [gridApi
|
|
377
|
+
gridApi.stopEditing();
|
|
378
|
+
}, [gridApi]);
|
|
378
379
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
380
|
+
/**
|
|
381
|
+
* This differs from stopEdit in that it will also invoke cellEditingCompleteCallback
|
|
382
|
+
*/
|
|
383
|
+
const cancelEdit = useCallback((): void => {
|
|
384
|
+
stopEditing();
|
|
385
|
+
cellEditingCompleteCallbackRef.current && cellEditingCompleteCallbackRef.current();
|
|
386
|
+
}, [stopEditing]);
|
|
387
|
+
|
|
388
|
+
const cellEditingCompleteCallbackRef = useRef<() => void>();
|
|
389
|
+
const setOnCellEditingComplete = useCallback((cellEditingCompleteCallback: (() => void) | undefined) => {
|
|
390
|
+
cellEditingCompleteCallbackRef.current = cellEditingCompleteCallback;
|
|
391
|
+
}, []);
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Returns true if an editable cell on same row was selected, else false.
|
|
395
|
+
*/
|
|
396
|
+
const selectNextEditableCell = useCallback(
|
|
397
|
+
(tabDirection: -1 | 1): boolean => {
|
|
398
|
+
// Pretend it succeeded to prevent unwanted cellEditingCompleteCallback
|
|
399
|
+
if (!gridApi) return true;
|
|
400
|
+
|
|
401
|
+
const focusedCellIsEditable = () => {
|
|
402
|
+
const focusedCell = gridApi.getFocusedCell();
|
|
403
|
+
const nextColumn = focusedCell?.column;
|
|
404
|
+
const nextColDef = nextColumn?.getColDef();
|
|
405
|
+
const rowNode = focusedCell && gridApi.getDisplayedRowAtIndex(focusedCell?.rowIndex);
|
|
406
|
+
return (
|
|
407
|
+
!!(rowNode && nextColumn && nextColDef) &&
|
|
408
|
+
nextColumn.isCellEditable(rowNode) &&
|
|
409
|
+
!nextColDef.cellEditorParams?.preventAutoEdit &&
|
|
410
|
+
!nextColDef.cellRendererParams?.editAction
|
|
411
|
+
);
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
let foundEditableCell = false;
|
|
415
|
+
|
|
416
|
+
// Just in case I've missed something, we don't want the loop to hang everything
|
|
417
|
+
let maxIterations = 50;
|
|
418
|
+
let preRow: CellPosition | null = null;
|
|
419
|
+
let postRow: CellPosition | null = null;
|
|
420
|
+
do {
|
|
421
|
+
preRow = gridApi.getFocusedCell();
|
|
422
|
+
tabDirection === 1 ? gridApi.tabToNextCell() : gridApi.tabToPreviousCell();
|
|
423
|
+
postRow = gridApi.getFocusedCell();
|
|
424
|
+
foundEditableCell = focusedCellIsEditable();
|
|
425
|
+
} while (
|
|
426
|
+
preRow?.rowIndex === postRow?.rowIndex &&
|
|
427
|
+
preRow?.column !== postRow?.column &&
|
|
428
|
+
!foundEditableCell &&
|
|
429
|
+
maxIterations-- > 0
|
|
430
|
+
);
|
|
431
|
+
|
|
432
|
+
if (foundEditableCell) {
|
|
433
|
+
prePopupOps();
|
|
434
|
+
const focusedCell = gridApi?.getFocusedCell();
|
|
435
|
+
if (focusedCell) {
|
|
436
|
+
gridApi.startEditingCell({
|
|
437
|
+
rowIndex: focusedCell.rowIndex,
|
|
438
|
+
colKey: focusedCell.column.getColId(),
|
|
439
|
+
});
|
|
440
|
+
return false;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
return true;
|
|
385
444
|
},
|
|
386
|
-
[
|
|
445
|
+
[gridApi, prePopupOps],
|
|
387
446
|
);
|
|
388
447
|
|
|
389
448
|
const updatingCells = useCallback(
|
|
@@ -398,6 +457,7 @@ export const GridContextProvider = <RowType extends GridBaseRow>(props: GridCont
|
|
|
398
457
|
const selectedRows = props.selectedRows;
|
|
399
458
|
|
|
400
459
|
let ok = false;
|
|
460
|
+
|
|
401
461
|
await modifyUpdating(
|
|
402
462
|
props.field ?? "",
|
|
403
463
|
selectedRows.map((data) => data.id),
|
|
@@ -429,19 +489,20 @@ export const GridContextProvider = <RowType extends GridBaseRow>(props: GridCont
|
|
|
429
489
|
// Only focus next cell if user hasn't already manually changed focus
|
|
430
490
|
const postPopupFocusedCell = gridApi.getFocusedCell();
|
|
431
491
|
if (
|
|
432
|
-
tabDirection &&
|
|
433
492
|
prePopupFocusedCell.current &&
|
|
434
493
|
postPopupFocusedCell &&
|
|
435
494
|
prePopupFocusedCell.current.rowIndex == postPopupFocusedCell.rowIndex &&
|
|
436
495
|
prePopupFocusedCell.current.column.getColId() == postPopupFocusedCell.column.getColId()
|
|
437
496
|
) {
|
|
438
|
-
|
|
497
|
+
if (!tabDirection || selectNextEditableCell(tabDirection)) {
|
|
498
|
+
cellEditingCompleteCallbackRef.current && cellEditingCompleteCallbackRef.current();
|
|
499
|
+
}
|
|
439
500
|
}
|
|
440
501
|
|
|
441
502
|
return ok;
|
|
442
503
|
});
|
|
443
504
|
},
|
|
444
|
-
[gridApiOp, modifyUpdating,
|
|
505
|
+
[gridApiOp, modifyUpdating, selectNextEditableCell],
|
|
445
506
|
);
|
|
446
507
|
|
|
447
508
|
const redrawRows = useCallback(
|
|
@@ -476,12 +537,12 @@ export const GridContextProvider = <RowType extends GridBaseRow>(props: GridCont
|
|
|
476
537
|
|
|
477
538
|
const addExternalFilter = (filter: GridFilterExternal<RowType>) => {
|
|
478
539
|
externalFilters.current.push(filter);
|
|
479
|
-
onFilterChanged();
|
|
540
|
+
onFilterChanged().then();
|
|
480
541
|
};
|
|
481
542
|
|
|
482
543
|
const removeExternalFilter = (filter: GridFilterExternal<RowType>) => {
|
|
483
544
|
remove(externalFilters.current, (v) => v === filter);
|
|
484
|
-
onFilterChanged();
|
|
545
|
+
onFilterChanged().then();
|
|
485
546
|
};
|
|
486
547
|
|
|
487
548
|
const isExternalFilterPresent = (): boolean => externalFilters.current.length > 0;
|
|
@@ -557,8 +618,9 @@ export const GridContextProvider = <RowType extends GridBaseRow>(props: GridCont
|
|
|
557
618
|
ensureRowVisible,
|
|
558
619
|
ensureSelectedRowIsVisible,
|
|
559
620
|
sizeColumnsToFit,
|
|
560
|
-
|
|
621
|
+
autoSizeColumns,
|
|
561
622
|
stopEditing,
|
|
623
|
+
cancelEdit,
|
|
562
624
|
updatingCells,
|
|
563
625
|
redrawRows,
|
|
564
626
|
externallySelectedItemsAreInSync,
|
|
@@ -569,6 +631,7 @@ export const GridContextProvider = <RowType extends GridBaseRow>(props: GridCont
|
|
|
569
631
|
isExternalFilterPresent,
|
|
570
632
|
doesExternalFilterPass,
|
|
571
633
|
downloadCsv,
|
|
634
|
+
setOnCellEditingComplete,
|
|
572
635
|
}}
|
|
573
636
|
>
|
|
574
637
|
{props.children}
|
|
@@ -617,6 +680,7 @@ export const downloadCsvUseValueFormattersProcessCellCallback = (params: Process
|
|
|
617
680
|
}
|
|
618
681
|
|
|
619
682
|
const result = valueFormatter({ ...params, data: params.node?.data, colDef } as ValueFormatterParams);
|
|
683
|
+
// type may not be string due to casting, leave the type check in
|
|
620
684
|
if (params.value != null && typeof result !== "string") {
|
|
621
685
|
console.error(`downloadCsv: valueFormatter is returning non string values, colDef:", colId: ${colDef.colId}`);
|
|
622
686
|
}
|
|
@@ -2,6 +2,7 @@ import { createContext } from "react";
|
|
|
2
2
|
|
|
3
3
|
export type GridUpdatingContextType = {
|
|
4
4
|
checkUpdating: (fields: string | string[], id: number | string) => boolean;
|
|
5
|
+
isUpdating: () => boolean;
|
|
5
6
|
modifyUpdating: (
|
|
6
7
|
fields: string | string[],
|
|
7
8
|
ids: (number | string)[],
|
|
@@ -15,6 +16,10 @@ export const GridUpdatingContext = createContext<GridUpdatingContextType>({
|
|
|
15
16
|
console.error("Missing GridUpdatingContext");
|
|
16
17
|
return false;
|
|
17
18
|
},
|
|
19
|
+
isUpdating: () => {
|
|
20
|
+
console.error("Missing GridUpdatingContext");
|
|
21
|
+
return false;
|
|
22
|
+
},
|
|
18
23
|
modifyUpdating: async () => {
|
|
19
24
|
console.error("Missing GridUpdatingContext");
|
|
20
25
|
},
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { castArray, flatten, remove } from "lodash-es";
|
|
1
|
+
import { castArray, flatten, isEmpty, remove } from "lodash-es";
|
|
2
2
|
import { ReactNode, useRef, useState } from "react";
|
|
3
3
|
|
|
4
4
|
import { GridUpdatingContext } from "./GridUpdatingContext";
|
|
@@ -21,12 +21,17 @@ export const GridUpdatingContextProvider = (props: UpdatingContextProviderProps)
|
|
|
21
21
|
const resetUpdating = () => {
|
|
22
22
|
const mergedUpdatingBlocks: GridUpdatingContextStatus = {};
|
|
23
23
|
for (const key in updatingBlocks.current) {
|
|
24
|
-
|
|
24
|
+
const arr = flatten(updatingBlocks.current[key]);
|
|
25
|
+
if (arr.length) {
|
|
26
|
+
mergedUpdatingBlocks[key] = arr;
|
|
27
|
+
}
|
|
25
28
|
}
|
|
26
29
|
updating.current = mergedUpdatingBlocks;
|
|
27
30
|
setUpdatedDep((updatedDep) => updatedDep + 1);
|
|
28
31
|
};
|
|
29
32
|
|
|
33
|
+
const isUpdating = () => !isEmpty(updating.current);
|
|
34
|
+
|
|
30
35
|
const modifyUpdating = async (
|
|
31
36
|
fields: string | string[],
|
|
32
37
|
ids: (number | string)[],
|
|
@@ -50,7 +55,7 @@ export const GridUpdatingContextProvider = (props: UpdatingContextProviderProps)
|
|
|
50
55
|
castArray(fields).some((f) => updating.current[f]?.includes(id));
|
|
51
56
|
|
|
52
57
|
return (
|
|
53
|
-
<GridUpdatingContext.Provider value={{ modifyUpdating, checkUpdating, updatedDep }}>
|
|
58
|
+
<GridUpdatingContext.Provider value={{ modifyUpdating, checkUpdating, isUpdating, updatedDep }}>
|
|
54
59
|
{props.children}
|
|
55
60
|
</GridUpdatingContext.Provider>
|
|
56
61
|
);
|
package/src/lui/timeoutHook.tsx
CHANGED
|
@@ -38,3 +38,16 @@ export const useTimeoutHook = () => {
|
|
|
38
38
|
|
|
39
39
|
return invoke;
|
|
40
40
|
};
|
|
41
|
+
|
|
42
|
+
interface IntervalHookProps {
|
|
43
|
+
timeoutMs: number;
|
|
44
|
+
callback: () => void;
|
|
45
|
+
}
|
|
46
|
+
export const useIntervalHook = ({ callback, timeoutMs }: IntervalHookProps) => {
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
const interval = setInterval(callback, timeoutMs);
|
|
49
|
+
return () => {
|
|
50
|
+
clearInterval(interval);
|
|
51
|
+
};
|
|
52
|
+
});
|
|
53
|
+
};
|
|
@@ -477,7 +477,27 @@ export const MenuList = ({
|
|
|
477
477
|
top: menuPosition.y,
|
|
478
478
|
}}
|
|
479
479
|
>
|
|
480
|
-
<div
|
|
480
|
+
<div
|
|
481
|
+
ref={focusRef}
|
|
482
|
+
tabIndex={-1}
|
|
483
|
+
style={{ position: "absolute", left: 0, top: 0 }}
|
|
484
|
+
onKeyDown={(event) => {
|
|
485
|
+
if (event.key == "Tab") {
|
|
486
|
+
event.preventDefault();
|
|
487
|
+
event.stopPropagation();
|
|
488
|
+
safeCall(onClose, {
|
|
489
|
+
key: event.key,
|
|
490
|
+
shiftKey: event.shiftKey,
|
|
491
|
+
reason:
|
|
492
|
+
event.key === "Tab"
|
|
493
|
+
? event.shiftKey
|
|
494
|
+
? CloseReason.TAB_BACKWARD
|
|
495
|
+
: CloseReason.TAB_FORWARD
|
|
496
|
+
: CloseReason.CLICK,
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
}}
|
|
500
|
+
/>
|
|
481
501
|
{arrow && (
|
|
482
502
|
<div
|
|
483
503
|
className={_arrowClass}
|
|
@@ -192,7 +192,7 @@ const GridPopoutEditGenericTemplate: ComponentStory<typeof Grid> = (props: GridP
|
|
|
192
192
|
setRowData([
|
|
193
193
|
...rowData,
|
|
194
194
|
{
|
|
195
|
-
id: lastRow
|
|
195
|
+
id: (lastRow?.id ?? 0) + 1,
|
|
196
196
|
name: "?",
|
|
197
197
|
nameType: "?",
|
|
198
198
|
numba: "?",
|
|
@@ -212,6 +212,12 @@ const GridPopoutEditGenericTemplate: ComponentStory<typeof Grid> = (props: GridP
|
|
|
212
212
|
columnDefs={columnDefs}
|
|
213
213
|
rowData={rowData}
|
|
214
214
|
domLayout={"autoHeight"}
|
|
215
|
+
defaultColDef={{ minWidth: 70 }}
|
|
216
|
+
sizeColumns={"auto"}
|
|
217
|
+
onCellEditingComplete={() => {
|
|
218
|
+
/* eslint-disable-next-line no-console */
|
|
219
|
+
console.log("Cell editing complete");
|
|
220
|
+
}}
|
|
215
221
|
/>
|
|
216
222
|
<ActionButton icon={"ic_add"} name={"Add new row"} inProgressName={"Adding..."} onClick={addRowAction} />
|
|
217
223
|
</>
|
|
@@ -155,6 +155,7 @@ const GridEditDropDownTemplate: ComponentStory<typeof Grid> = (props: GridProps)
|
|
|
155
155
|
{
|
|
156
156
|
field: "position3",
|
|
157
157
|
headerName: "Filtered",
|
|
158
|
+
editable: false,
|
|
158
159
|
},
|
|
159
160
|
{
|
|
160
161
|
multiEdit: true,
|
|
@@ -302,6 +303,10 @@ const GridEditDropDownTemplate: ComponentStory<typeof Grid> = (props: GridProps)
|
|
|
302
303
|
columnDefs={columnDefs}
|
|
303
304
|
rowData={rowData}
|
|
304
305
|
domLayout={"autoHeight"}
|
|
306
|
+
onCellEditingComplete={() => {
|
|
307
|
+
/* eslint-disable-next-line no-console */
|
|
308
|
+
console.log("Cell editing complete");
|
|
309
|
+
}}
|
|
305
310
|
/>
|
|
306
311
|
</GridWrapper>
|
|
307
312
|
);
|
|
@@ -248,7 +248,9 @@ GridKeyboardInteractions.play = async ({ canvasElement }) => {
|
|
|
248
248
|
await test(() => userEvent.keyboard("{Enter}"), "8", "2");
|
|
249
249
|
await test(() => userEvent.tab(), "9", "2");
|
|
250
250
|
userEvent.tab({ shift: true });
|
|
251
|
-
await test(() => userEvent.tab({ shift: true }), "
|
|
251
|
+
await test(() => userEvent.tab({ shift: true }), "6", "2");
|
|
252
|
+
userEvent.keyboard("{Esc}");
|
|
253
|
+
userEvent.tab();
|
|
252
254
|
|
|
253
255
|
userEvent.keyboard("{Enter}");
|
|
254
256
|
await wait(250);
|