@linzjs/step-ag-grid 8.4.3 → 10.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 (35) hide show
  1. package/README.md +4 -4
  2. package/dist/index.css +3 -0
  3. package/dist/src/components/GridCell.d.ts +1 -1
  4. package/dist/src/components/gridForm/GridFormMultiSelect.d.ts +5 -4
  5. package/dist/src/utils/textMatcher.d.ts +1 -1
  6. package/dist/src/utils/textMatcher.test.d.ts +1 -0
  7. package/dist/step-ag-grid.esm.js +58858 -1100
  8. package/dist/step-ag-grid.esm.js.map +1 -1
  9. package/package.json +45 -47
  10. package/src/components/Grid.tsx +29 -27
  11. package/src/components/GridCell.tsx +1 -1
  12. package/src/components/gridForm/GridFormDropDown.tsx +2 -2
  13. package/src/components/gridForm/GridFormMultiSelect.tsx +12 -6
  14. package/src/components/gridForm/GridFormSubComponentTextArea.tsx +0 -1
  15. package/src/components/gridForm/GridFormSubComponentTextInput.tsx +0 -1
  16. package/src/lui/TextAreaInput.tsx +1 -1
  17. package/src/lui/TextInputFormatted.tsx +1 -1
  18. package/src/react-menu3/components/ControlledMenu.tsx +19 -6
  19. package/src/react-menu3/hooks/useMenuState.ts +1 -1
  20. package/src/stories/grid/GridKeyboardInteractions.stories.tsx +261 -0
  21. package/src/stories/grid/{GridPopoutBearing.stories.tsx → GridPopoverEditBearing.stories.tsx} +4 -4
  22. package/src/stories/grid/{GridPopoutEditDropDown.stories.tsx → GridPopoverEditDropDown.stories.tsx} +0 -0
  23. package/src/stories/grid/{GridPopoutEditMultiSelect.stories.tsx → GridPopoverEditMultiSelect.stories.tsx} +0 -0
  24. package/src/stories/grid/gridFormInteraction/GridFormDropDownInteraction.stories.tsx +10 -1
  25. package/src/stories/grid/gridFormInteraction/GridFormEditBearingCorrectionInteraction.stories.tsx +1 -1
  26. package/src/stories/grid/gridFormInteraction/GridFormEditBearingInteraction.stories.tsx +1 -1
  27. package/src/stories/grid/gridFormInteraction/GridFormMultiSelectInteraction.stories.tsx +153 -0
  28. package/src/stories/grid/gridFormInteraction/GridFormPopoverMenuInteraction.stories.tsx +1 -1
  29. package/src/stories/grid/gridFormInteraction/GridFormTextAreaInteraction.stories.tsx +1 -1
  30. package/src/stories/grid/gridFormInteraction/GridFormTextInputInteraction.stories.tsx +1 -1
  31. package/src/stories/react-menu/ReactMenu.stories.tsx +66 -3
  32. package/src/styles/Grid.scss +3 -0
  33. package/src/utils/testUtil.ts +1 -0
  34. package/src/utils/textMatcher.test.ts +38 -0
  35. package/src/utils/textMatcher.ts +9 -2
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": "8.4.3",
5
+ "version": "10.0.0",
6
6
  "keywords": [
7
7
  "aggrid",
8
8
  "ag-grid",
@@ -28,22 +28,20 @@
28
28
  },
29
29
  "peerDependencies": {
30
30
  "@linzjs/lui": ">=17",
31
- "ag-grid-community": ">=27",
32
- "ag-grid-react": ">=27",
33
31
  "lodash-es": ">=4",
34
32
  "react": ">=17",
35
33
  "react-dom": ">=17"
36
34
  },
37
35
  "dependencies": {
38
36
  "@linzjs/lui": ">=17",
39
- "ag-grid-community": ">=27",
40
- "ag-grid-react": ">=27",
37
+ "ag-grid-community": "^28.2.1",
38
+ "ag-grid-react": "^28.2.1",
41
39
  "debounce-promise": "^3.1.2",
42
40
  "lodash-es": ">=4",
43
41
  "matcher": "^5.0.0",
44
42
  "react": ">=17",
45
43
  "react-dom": ">=17",
46
- "react-transition-state": "^1.1.5",
44
+ "react-transition-state": "^2.0.2",
47
45
  "uuid": "^9.0.0"
48
46
  },
49
47
  "scripts": {
@@ -81,76 +79,76 @@
81
79
  ]
82
80
  },
83
81
  "devDependencies": {
84
- "@rollup/plugin-commonjs": "^23.0.2",
85
- "@rollup/plugin-json": "^5.0.1",
82
+ "@rollup/plugin-commonjs": "^24.0.1",
83
+ "@rollup/plugin-json": "^6.0.0",
86
84
  "@rollup/plugin-node-resolve": "^15.0.1",
87
- "@semantic-release/changelog": "^6.0.1",
85
+ "@semantic-release/changelog": "^6.0.2",
88
86
  "@semantic-release/git": "^10.0.1",
89
- "@storybook/addon-actions": "^6.5.13",
90
- "@storybook/addon-essentials": "^6.5.13",
91
- "@storybook/addon-interactions": "^6.5.13",
92
- "@storybook/addon-links": "^6.5.13",
87
+ "@storybook/addon-interactions": "^6.5.16",
88
+ "@storybook/addon-essentials": "^6.5.16",
89
+ "@storybook/builder-webpack5": "^6.5.16",
93
90
  "@storybook/jest": "^0.0.10",
94
- "@storybook/react": "6.5.13",
95
- "@storybook/test-runner": "^0.9.0",
91
+ "@storybook/manager-webpack5": "^6.5.16",
92
+ "@storybook/preset-create-react-app": "^4.1.2",
93
+ "@storybook/react": "^6.5.16",
94
+ "@storybook/test-runner": "^0.9.4",
96
95
  "@storybook/testing-library": "^0.0.13",
97
- "@testing-library/dom": "^8.19.0",
96
+ "@testing-library/dom": "^8.20.0",
98
97
  "@testing-library/jest-dom": "^5.16.5",
99
98
  "@testing-library/react": "^12.1.5",
100
99
  "@testing-library/user-event": "^13.5.0",
101
- "@types/debounce-promise": "^3.1.5",
102
- "@types/jest": "^29.2.2",
100
+ "@types/debounce-promise": "^3.1.6",
101
+ "@types/jest": "^29.4.0",
103
102
  "@types/lodash-es": "^4.17.6",
104
- "@types/node": "^18.11.9",
105
- "@types/react": "^17.0.52",
103
+ "@types/node": "^18.13.0",
104
+ "@types/react": "^17.0.53",
106
105
  "@types/react-dom": "^17.0.18",
107
- "@types/uuid": "^8.3.4",
108
- "@typescript-eslint/parser": "^5.42.0",
109
- "babel-jest": "^29.2.2",
106
+ "@types/uuid": "^9.0.0",
107
+ "@typescript-eslint/parser": "^5.51.0",
108
+ "babel-jest": "^29.4.2",
110
109
  "babel-preset-react-app": "^10.0.1",
111
- "chromatic": "^6.11.4",
110
+ "chromatic": "^6.17.0",
112
111
  "conventional-changelog-conventionalcommits": "^5.0.0",
113
- "eslint": "^8.27.0",
114
- "eslint-config-prettier": "^8.5.0",
112
+ "eslint": "^8.33.0",
113
+ "eslint-config-prettier": "^8.6.0",
115
114
  "eslint-config-react-app": "^7.0.1",
116
- "eslint-plugin-deprecation": "^1.3.2",
117
- "eslint-plugin-import": "^2.26.0",
118
- "eslint-plugin-jest": "^27.1.4",
119
- "eslint-plugin-jsx-a11y": "^6.6.1",
115
+ "eslint-plugin-deprecation": "^1.3.3",
116
+ "eslint-plugin-import": "^2.27.5",
117
+ "eslint-plugin-jest": "^27.2.1",
118
+ "eslint-plugin-jsx-a11y": "^6.7.1",
120
119
  "eslint-plugin-prettier": "^4.2.1",
121
- "eslint-plugin-react": "^7.31.10",
120
+ "eslint-plugin-react": "^7.32.2",
122
121
  "eslint-plugin-react-hooks": "^4.6.0",
123
- "eslint-plugin-testing-library": "^5.9.1",
124
- "jest": "^29.3.1",
122
+ "eslint-plugin-testing-library": "^5.10.1",
123
+ "jest": "^29.4.2",
125
124
  "jest-canvas-mock": "^2.4.0",
126
- "jest-environment-jsdom": "^29.3.1",
125
+ "jest-environment-jsdom": "^29.4.2",
127
126
  "jest-expect-message": "^1.1.3",
128
- "mkdirp": "^1.0.4",
127
+ "mkdirp": "^2.1.3",
129
128
  "npm-run-all": "^4.1.5",
130
- "postcss": "^8.4.18",
131
- "postcss-loader": "^7.0.1",
132
- "postcss-scss": "^4.0.5",
133
- "prettier": "^2.7.1",
129
+ "postcss": "^8.4.21",
130
+ "postcss-loader": "^7.0.2",
131
+ "postcss-scss": "^4.0.6",
132
+ "prettier": "^2.8.4",
134
133
  "react-app-polyfill": "^3.0.0",
135
134
  "react-scripts": "^5.0.1",
136
- "rollup": "^3.2.5",
135
+ "rollup": "^3.14.0",
137
136
  "rollup-plugin-copy": "^3.4.0",
138
137
  "rollup-plugin-peer-deps-external": "^2.2.4",
139
138
  "rollup-plugin-postcss": "^4.0.2",
140
139
  "rollup-plugin-typescript2": "^0.34.1",
141
- "sass": "^1.56.0",
142
- "sass-loader": "10.3.1",
140
+ "sass": "^1.58.0",
141
+ "sass-loader": "^13.2.0",
143
142
  "semantic-release": "^19.0.5",
144
- "storybook-addon-mock": "^2.4.1",
145
- "style-loader": "2.0.0",
146
- "stylelint": "^14.14.1",
147
- "stylelint-config-prettier": "^9.0.3",
143
+ "style-loader": "^3.3.1",
144
+ "stylelint": "^14.16.1",
145
+ "stylelint-config-prettier": "^9.0.4",
148
146
  "stylelint-config-recommended-scss": "^8.0.0",
149
147
  "stylelint-config-standard": "^29.0.0",
150
148
  "stylelint-prettier": "^2.0.0",
151
149
  "stylelint-scss": "^4.3.0",
152
150
  "tsconfig-paths-webpack-plugin": "^4.0.0",
153
- "typescript": "^4.8.4"
151
+ "typescript": "^4.9.5"
154
152
  },
155
153
  "babel": {
156
154
  "presets": [
@@ -340,33 +340,35 @@ export const Grid = (params: GridProps): JSX.Element => {
340
340
  />
341
341
  </div>
342
342
  )}
343
- <AgGridReact
344
- animateRows={params.animateRows}
345
- rowClassRules={params.rowClassRules}
346
- defaultColDef={params.defaultColDef}
347
- getRowId={(params) => `${params.data.id}`}
348
- suppressRowClickSelection={true}
349
- rowSelection={params.rowSelection ?? "multiple"}
350
- suppressBrowserResizeObserver={true}
351
- colResizeDefault={"shift"}
352
- onFirstDataRendered={sizeColumnsToFit}
353
- onGridSizeChanged={sizeColumnsToFit}
354
- suppressClickEdit={true}
355
- onCellKeyPress={onCellKeyPress}
356
- onCellClicked={onCellClicked}
357
- onCellDoubleClicked={onCellDoubleClick}
358
- onCellEditingStarted={refreshSelectedRows}
359
- domLayout={params.domLayout}
360
- columnDefs={columnDefs}
361
- rowData={params.rowData}
362
- noRowsOverlayComponent={noRowsOverlayComponent}
363
- onGridReady={onGridReady}
364
- onSortChanged={ensureSelectedRowIsVisible}
365
- postSortRows={params.postSortRows ?? postSortRows}
366
- onSelectionChanged={synchroniseExternalStateToGridSelection}
367
- onColumnMoved={params.onColumnMoved}
368
- alwaysShowVerticalScroll={params.alwaysShowVerticalScroll}
369
- />
343
+ <div style={{ flex: 1 }}>
344
+ <AgGridReact
345
+ animateRows={params.animateRows}
346
+ rowClassRules={params.rowClassRules}
347
+ defaultColDef={params.defaultColDef}
348
+ getRowId={(params) => `${params.data.id}`}
349
+ suppressRowClickSelection={true}
350
+ rowSelection={params.rowSelection ?? "multiple"}
351
+ suppressBrowserResizeObserver={true}
352
+ colResizeDefault={"shift"}
353
+ onFirstDataRendered={sizeColumnsToFit}
354
+ onGridSizeChanged={sizeColumnsToFit}
355
+ suppressClickEdit={true}
356
+ onCellKeyPress={onCellKeyPress}
357
+ onCellClicked={onCellClicked}
358
+ onCellDoubleClicked={onCellDoubleClick}
359
+ onCellEditingStarted={refreshSelectedRows}
360
+ domLayout={params.domLayout}
361
+ columnDefs={columnDefs}
362
+ rowData={params.rowData}
363
+ noRowsOverlayComponent={noRowsOverlayComponent}
364
+ onGridReady={onGridReady}
365
+ onSortChanged={ensureSelectedRowIsVisible}
366
+ postSortRows={params.postSortRows ?? postSortRows}
367
+ onSelectionChanged={synchroniseExternalStateToGridSelection}
368
+ onColumnMoved={params.onColumnMoved}
369
+ alwaysShowVerticalScroll={params.alwaysShowVerticalScroll}
370
+ />
371
+ </div>
370
372
  </div>
371
373
  );
372
374
  };
@@ -44,7 +44,7 @@ export const GridCellRenderer = (props: ICellRendererParams) => {
44
44
  {colDef.cellRendererParams?.originalCellRenderer ? (
45
45
  <colDef.cellRendererParams.originalCellRenderer {...props} />
46
46
  ) : (
47
- <span title={props.valueFormatted}>{props.valueFormatted}</span>
47
+ <span title={props.valueFormatted ?? undefined}>{props.valueFormatted}</span>
48
48
  )}
49
49
  </div>
50
50
  {fnOrVar(colDef.editable, props) && rendererParams?.rightHoverElement && (
@@ -11,6 +11,7 @@ import { GridSubComponentContext } from "../../contexts/GridSubComponentContext"
11
11
  import { ClickEvent } from "../../react-menu3/types";
12
12
  import { FormError } from "../../lui/FormError";
13
13
  import { isNotEmpty } from "../../utils/util";
14
+ import { textMatch } from "../../utils/textMatcher";
14
15
 
15
16
  export interface GridPopoutEditDropDownSelectedItem<RowType> {
16
17
  // Note the row that was clicked on will be first
@@ -136,8 +137,7 @@ export const GridFormDropDown = <RowType extends GridBaseRow>(props: GridFormDro
136
137
  console.error("Cannot filter non-string labels", option);
137
138
  return undefined;
138
139
  }
139
- const str = (option.label as string) || "";
140
- return str.toLowerCase().indexOf(filter.toLowerCase()) !== -1 ? option : undefined;
140
+ return textMatch((option.label as string) || "", filter) ? option : undefined;
141
141
  })
142
142
  .filter((r) => r !== undefined),
143
143
  );
@@ -41,6 +41,11 @@ export interface GridFormMultiSelectGroup {
41
41
  filter?: string;
42
42
  }
43
43
 
44
+ export interface GridFormMultiSelectSaveProps<RowType extends GridBaseRow> {
45
+ selectedRows: RowType[];
46
+ selectedOptions: MultiSelectOption[];
47
+ }
48
+
44
49
  export interface GridFormMultiSelectProps<RowType extends GridBaseRow> extends CellEditorCommon {
45
50
  className?:
46
51
  | "GridMultiSelect-containerSmall"
@@ -54,7 +59,7 @@ export interface GridFormMultiSelectProps<RowType extends GridBaseRow> extends C
54
59
  filterHelpText?: string | ((filter: string, options: MultiSelectOption[]) => string | undefined);
55
60
  noOptionsMessage?: string;
56
61
  onSelectFilter?: (props: { filter: string; options: MultiSelectOption[] }) => void;
57
- onSave?: (props: { selectedRows: RowType[]; selectedOptions: MultiSelectOption[] }) => Promise<boolean>;
62
+ onSave?: (props: GridFormMultiSelectSaveProps<RowType>) => Promise<boolean>;
58
63
  headers?: GridFormMultiSelectGroup[];
59
64
  options: MultiSelectOption[] | ((selectedRows: RowType[]) => Promise<MultiSelectOption[]> | MultiSelectOption[]);
60
65
  invalid?: (selectedRows: RowType[], selectedOptions: MultiSelectOption[]) => boolean;
@@ -164,11 +169,12 @@ export const GridFormMultiSelect = <RowType extends GridBaseRow>(props: GridForm
164
169
  filterPlaceholder={props.filterPlaceholder}
165
170
  />
166
171
  )}
167
- {headerGroups && (isEmpty(headerGroups) || !toPairs(headerGroups).some(([_, options]) => !isEmpty(options))) && (
168
- <MenuItem key={"noOptions"} className={"GridMultiSelect-noOptions"} disabled={true}>
169
- {props.noOptionsMessage ?? "No Options"}
170
- </MenuItem>
171
- )}
172
+ {headerGroups &&
173
+ (isEmpty(headerGroups) || !toPairs(headerGroups).some(([_, options]) => !isEmpty(options))) && (
174
+ <MenuItem key={"noOptions"} className={"GridMultiSelect-noOptions"} disabled={true}>
175
+ {props.noOptionsMessage ?? "No Options"}
176
+ </MenuItem>
177
+ )}
172
178
  {headerGroups && !isEmpty(headerGroups) && (
173
179
  <div className={"GridFormMultiSelect-options"}>
174
180
  {headers.map((header, index) => {
@@ -42,7 +42,6 @@ export const GridFormSubComponentTextArea = <RowType extends GridBaseRow>(
42
42
  onChange={(e) => setValue(e.target.value)}
43
43
  error={invalid()}
44
44
  helpText={helpText}
45
- autoFocus={true}
46
45
  placeholder={props.placeholder}
47
46
  allowTabToSave={true}
48
47
  />
@@ -38,7 +38,6 @@ export const GridFormSubComponentTextInput = <RowType extends GridBaseRow>(
38
38
  error={invalid()}
39
39
  onChange={(e) => setValue(e.target.value)}
40
40
  helpText={helpText}
41
- autoFocus={true}
42
41
  placeholder={props.placeholder}
43
42
  style={{ width: "100%" }}
44
43
  allowTabToSave={true}
@@ -40,7 +40,7 @@ export const TextAreaInput = (props: LuiTextAreaInputProps) => {
40
40
  {/* wrapper div used for error styling */}
41
41
  <textarea
42
42
  rows={5}
43
- {...omit(props, ["error", "value", "helpText", "formatted", "className"])}
43
+ {...omit(props, ["error", "value", "helpText", "formatted", "className", "allowTabToSave"])}
44
44
  id={id}
45
45
  value={props.value ?? ""}
46
46
  spellCheck={true}
@@ -26,7 +26,7 @@ export const TextInputFormatted = (props: LuiTextInputProps): JSX.Element => {
26
26
  type={"text"}
27
27
  spellCheck={true}
28
28
  defaultValue={props.value}
29
- {...omit(props, ["error", "value", "helpText", "formatted", "className"])}
29
+ {...omit(props, ["error", "value", "helpText", "formatted", "className", "allowTabToSave"])}
30
30
  className={"LuiTextInput-input"}
31
31
  onMouseEnter={(e) => {
32
32
  e.currentTarget.focus();
@@ -127,6 +127,25 @@ export const ControlledMenuFr = (
127
127
  return;
128
128
  }
129
129
 
130
+ const invokeSave = (reason: string) => {
131
+ if (!saveButtonRef?.current) return;
132
+ saveButtonRef.current?.setAttribute("data-reason", reason);
133
+ saveButtonRef?.current?.click();
134
+ };
135
+
136
+ const allowTabToSave = activeElement.getAttribute("data-allowtabtosave") == "true";
137
+ if (allowTabToSave) {
138
+ if (isDown) {
139
+ ev.preventDefault();
140
+ ev.stopPropagation();
141
+ lastTabDownEl.current = activeElement;
142
+ } else {
143
+ lastTabDownEl.current == activeElement &&
144
+ invokeSave(ev.shiftKey ? CloseReason.TAB_BACKWARD : CloseReason.TAB_FORWARD);
145
+ }
146
+ return;
147
+ }
148
+
130
149
  const inputElsIterator = thisDocument.querySelectorAll<HTMLElement>(".szh-menu--state-open input,textarea");
131
150
  let inputEls: HTMLElement[] = [];
132
151
  inputElsIterator.forEach((el) => inputEls.push(el));
@@ -138,12 +157,6 @@ export const ControlledMenuFr = (
138
157
 
139
158
  const isTextArea = activeElement.nodeName === "TEXTAREA";
140
159
  const suppressEnterAutoSave = activeElement.getAttribute("data-disableenterautosave") == "true" || isTextArea;
141
- const allowTabToSave = activeElement.getAttribute("data-allowtabtosave") == "true";
142
- const invokeSave = (reason: string) => {
143
- if (!saveButtonRef?.current) return;
144
- saveButtonRef.current?.setAttribute("data-reason", reason);
145
- saveButtonRef?.current?.click();
146
- };
147
160
 
148
161
  switch (activeElement.nodeName) {
149
162
  case "TEXTAREA":
@@ -38,5 +38,5 @@ export const useMenuState = (
38
38
  exit: getTransition(transition, "close"),
39
39
  });
40
40
 
41
- return [{ state: MenuStateMap[state], endTransition }, toggleMenu];
41
+ return [{ state: MenuStateMap[state.status], endTransition }, toggleMenu];
42
42
  };
@@ -0,0 +1,261 @@
1
+ import "@linzjs/lui/dist/scss/base.scss";
2
+ import "@linzjs/lui/dist/fonts";
3
+ import "../../styles/index.scss";
4
+ import "../../styles/GridTheme.scss";
5
+
6
+ import { ComponentMeta, ComponentStory } from "@storybook/react/dist/ts3.9/client/preview/types-6-3";
7
+ import { GridUpdatingContextProvider } from "../../contexts/GridUpdatingContextProvider";
8
+ import { GridContextProvider } from "../../contexts/GridContextProvider";
9
+ import { Grid, GridProps } from "../../components/Grid";
10
+ import { useMemo, useState } from "react";
11
+ import { wait } from "../../utils/util";
12
+ import { GridPopoverMenu } from "../../components/gridPopoverEdit/GridPopoverMenu";
13
+ import { ColDefT, GridCell } from "../../components/GridCell";
14
+ import { GridPopoverMessage } from "../../components/gridPopoverEdit/GridPopoverMessage";
15
+ import { MenuOption } from "../../components/gridForm/GridFormPopoverMenu";
16
+ import { GridFormSubComponentTextInput } from "../../components/gridForm/GridFormSubComponentTextInput";
17
+ import { GridFormSubComponentTextArea } from "../../components/gridForm/GridFormSubComponentTextArea";
18
+ import { GridIcon } from "../../components/GridIcon";
19
+ import { userEvent, waitFor } from "@storybook/testing-library";
20
+ import { expect, jest } from "@storybook/jest";
21
+
22
+ export default {
23
+ title: "Components / Grids",
24
+ component: Grid,
25
+ args: {
26
+ quickFilter: true,
27
+ quickFilterValue: "",
28
+ quickFilterPlaceholder: "Quick filter...",
29
+ selectable: false,
30
+ rowSelection: "single",
31
+ },
32
+ decorators: [
33
+ (Story) => (
34
+ <div style={{ width: 1024, height: 400 }}>
35
+ <GridUpdatingContextProvider>
36
+ <GridContextProvider>
37
+ <Story />
38
+ </GridContextProvider>
39
+ </GridUpdatingContextProvider>
40
+ </div>
41
+ ),
42
+ ],
43
+ } as ComponentMeta<typeof Grid>;
44
+
45
+ interface ITestRow {
46
+ id: number;
47
+ position: string;
48
+ age: number;
49
+ desc: string;
50
+ dd: string;
51
+ }
52
+
53
+ const multiEditAction = jest.fn().mockImplementation(async () => {
54
+ await wait(500);
55
+ });
56
+
57
+ const eAction = jest.fn<boolean, []>().mockReturnValue(true);
58
+
59
+ const GridKeyboardInteractionsTemplate: ComponentStory<typeof Grid> = (props: GridProps) => {
60
+ const [externalSelectedItems, setExternalSelectedItems] = useState<any[]>([]);
61
+ const columnDefs: ColDefT<ITestRow>[] = useMemo(
62
+ () => [
63
+ GridCell({
64
+ field: "id",
65
+ headerName: "Id",
66
+ initialWidth: 65,
67
+ maxWidth: 85,
68
+ }),
69
+ GridCell({
70
+ field: "position",
71
+ headerName: "Position",
72
+ initialWidth: 65,
73
+ maxWidth: 150,
74
+ cellRendererParams: {
75
+ warning: (props) => props.value === "Tester" && "Testers are testing",
76
+ info: (props) => props.value === "Developer" && "Developers are awesome",
77
+ },
78
+ }),
79
+ GridCell({
80
+ field: "age",
81
+ headerName: "Age",
82
+ initialWidth: 65,
83
+ maxWidth: 85,
84
+ }),
85
+ GridCell({
86
+ field: "desc",
87
+ headerName: "Description",
88
+ initialWidth: 150,
89
+ maxWidth: 200,
90
+ }),
91
+ GridPopoverMessage(
92
+ {
93
+ headerName: "Popout message",
94
+ maxWidth: 150,
95
+ cellRenderer: () => <>Single Click me!</>,
96
+ },
97
+ {
98
+ multiEdit: true,
99
+ editorParams: {
100
+ message: async (selectedRows): Promise<string> => {
101
+ await wait(1000);
102
+ return `There are ${selectedRows.length} row(s) selected`;
103
+ },
104
+ },
105
+ },
106
+ ),
107
+ GridCell({
108
+ headerName: "Custom edit",
109
+ maxWidth: 100,
110
+ editable: true,
111
+ valueFormatter: () => "Press E",
112
+ cellRendererParams: {
113
+ rightHoverElement: (
114
+ <GridIcon icon={"ic_launch_modal"} title={"Title text"} className={"GridCell-editableIcon"} />
115
+ ),
116
+ editAction: () => {
117
+ //
118
+ },
119
+ shortcutKeys: {
120
+ e: eAction,
121
+ },
122
+ },
123
+ }),
124
+ GridPopoverMenu(
125
+ {},
126
+ {
127
+ multiEdit: true,
128
+ editorParams: {
129
+ defaultAction: async ({ menuOption }) => {
130
+ // eslint-disable-next-line no-console
131
+ console.log("clicked", { menuOption });
132
+ },
133
+ options: async (selectedItems) => {
134
+ // Just doing a timeout here to demonstrate deferred loading
135
+ await wait(500);
136
+ return [
137
+ {
138
+ label: "Single edit only",
139
+ action: async () => {
140
+ //
141
+ },
142
+ disabled: selectedItems.length > 1,
143
+ },
144
+ {
145
+ label: "Multi-edit",
146
+ action: multiEditAction,
147
+ },
148
+ {
149
+ label: "Disabled item",
150
+ disabled: "Disabled for test",
151
+ },
152
+ {
153
+ label: "Developer Only",
154
+ hidden: selectedItems.some((x) => x.position != "Developer"),
155
+ },
156
+ {
157
+ label: "Other (TextInput)",
158
+ action: async () => {
159
+ //
160
+ },
161
+ subComponent: () => (
162
+ <GridFormSubComponentTextInput placeholder={"Other"} maxLength={5} required defaultValue={""} />
163
+ ),
164
+ },
165
+ {
166
+ label: "Other (TextArea)",
167
+ action: async ({ menuOption }) => {
168
+ // eslint-disable-next-line no-console
169
+ console.log(`Sub selected value was ${JSON.stringify(menuOption.subValue)}`);
170
+ await wait(500);
171
+ },
172
+ subComponent: () => (
173
+ <GridFormSubComponentTextArea placeholder={"Other"} maxLength={5} required defaultValue={""} />
174
+ ),
175
+ },
176
+ ] as MenuOption<ITestRow>[];
177
+ },
178
+ },
179
+ },
180
+ ),
181
+ GridPopoverMenu(
182
+ {
183
+ editable: () => false,
184
+ },
185
+ {
186
+ editorParams: {
187
+ options: async () => {
188
+ return [];
189
+ },
190
+ },
191
+ },
192
+ ),
193
+ ],
194
+ [],
195
+ );
196
+
197
+ const [rowData] = useState([
198
+ { id: 1000, position: "Tester", age: 30, desc: "Tests application", dd: "1" },
199
+ { id: 1001, position: "Developer", age: 12, desc: "Develops application", dd: "2" },
200
+ { id: 1002, position: "Manager", age: 65, desc: "Manages", dd: "3" },
201
+ ]);
202
+
203
+ return (
204
+ <Grid
205
+ {...props}
206
+ selectable={true}
207
+ externalSelectedItems={externalSelectedItems}
208
+ setExternalSelectedItems={setExternalSelectedItems}
209
+ columnDefs={columnDefs}
210
+ rowData={rowData}
211
+ domLayout={"autoHeight"}
212
+ autoSelectFirstRow={true}
213
+ />
214
+ );
215
+ };
216
+
217
+ export const GridKeyboardInteractions = GridKeyboardInteractionsTemplate.bind({});
218
+ GridKeyboardInteractions.play = async ({ canvasElement }) => {
219
+ // Ensure first row/cell is selected on render
220
+ await waitFor(async () => {
221
+ const activeCell = canvasElement.ownerDocument.activeElement;
222
+ expect(activeCell).toHaveClass("ag-cell-focus");
223
+ expect(activeCell).toHaveAttribute("aria-colindex", "1");
224
+ expect(activeCell?.parentElement).toHaveAttribute("row-index", "0");
225
+ });
226
+ userEvent.keyboard("{arrowdown}{arrowdown}");
227
+ userEvent.keyboard("{arrowright}{arrowright}{arrowright}{arrowright}{arrowright}{arrowright}{arrowright}");
228
+
229
+ // Test enter post focus
230
+ const test = async (fn: () => any, colId: string, rowId: string) => {
231
+ userEvent.keyboard("{Enter}");
232
+ await wait(1000);
233
+ userEvent.keyboard("{arrowdown}{arrowdown}");
234
+ fn();
235
+ await waitFor(async () => {
236
+ expect(multiEditAction).toHaveBeenCalled();
237
+ });
238
+
239
+ await waitFor(async () => {
240
+ const activeCell = canvasElement.ownerDocument.activeElement;
241
+ expect(activeCell).toHaveClass("ag-cell-focus");
242
+ expect(activeCell).toHaveAttribute("aria-colindex", colId);
243
+ expect(activeCell?.parentElement).toHaveAttribute("row-index", rowId);
244
+ });
245
+ await wait(1000);
246
+ };
247
+
248
+ await test(() => userEvent.keyboard("{Enter}"), "8", "2");
249
+ await test(() => userEvent.tab(), "9", "2");
250
+ userEvent.tab({ shift: true });
251
+ await test(() => userEvent.tab({ shift: true }), "7", "2");
252
+
253
+ userEvent.keyboard("{Enter}");
254
+ await wait(250);
255
+ expect(eAction).not.toHaveBeenCalled();
256
+
257
+ userEvent.keyboard("e");
258
+ await waitFor(async () => {
259
+ expect(eAction).toHaveBeenCalled();
260
+ });
261
+ };
@@ -42,7 +42,7 @@ interface ITestRow {
42
42
  bearing: string | number | null;
43
43
  }
44
44
 
45
- const GridReadOnlyTemplate: ComponentStory<typeof Grid> = (props: GridProps) => {
45
+ const GridPopoverEditBearingTemplate: ComponentStory<typeof Grid> = (props: GridProps) => {
46
46
  const [externalSelectedItems, setExternalSelectedItems] = useState<any[]>([]);
47
47
  const columnDefs: ColDefT<ITestRow>[] = useMemo(
48
48
  () => [
@@ -57,8 +57,8 @@ const GridReadOnlyTemplate: ComponentStory<typeof Grid> = (props: GridProps) =>
57
57
  field: "bearingCorrection",
58
58
  headerName: "Bearing correction",
59
59
  cellRendererParams: {
60
- warning: (props) => props.data.id == 1002 && "Testers are testing",
61
- info: (props) => props.data.id == 1001 && "Developers are developing",
60
+ warning: ({ data }) => data.id == 1002 && "Testers are testing",
61
+ info: ({ data }) => data.id == 1001 && "Developers are developing",
62
62
  },
63
63
  },
64
64
  {
@@ -108,4 +108,4 @@ const GridReadOnlyTemplate: ComponentStory<typeof Grid> = (props: GridProps) =>
108
108
  );
109
109
  };
110
110
 
111
- export const Bearings = GridReadOnlyTemplate.bind({});
111
+ export const _GridPopoverEditBearing = GridPopoverEditBearingTemplate.bind({});