@linzjs/step-ag-grid 1.5.4 → 2.0.1

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 (128) hide show
  1. package/README.md +117 -2
  2. package/{src/components → dist}/GridTheme.scss +37 -23
  3. package/dist/index.css +351 -0
  4. package/dist/index.js +625 -332
  5. package/dist/index.js.map +1 -1
  6. package/dist/src/components/ComponentLoadingWrapper.d.ts +1 -0
  7. package/dist/src/components/Grid.d.ts +0 -2
  8. package/dist/src/components/GridCell.d.ts +21 -27
  9. package/dist/src/components/GridPopoverHook.d.ts +5 -2
  10. package/dist/src/components/gridForm/GridFormDropDown.d.ts +10 -4
  11. package/dist/src/components/gridForm/GridFormEditBearing.d.ts +5 -5
  12. package/dist/src/components/gridForm/GridFormMessage.d.ts +4 -5
  13. package/dist/src/components/gridForm/GridFormMultiSelect.d.ts +5 -4
  14. package/dist/src/components/gridForm/GridFormPopoutMenu.d.ts +3 -3
  15. package/dist/src/components/gridForm/GridFormTextArea.d.ts +3 -3
  16. package/dist/src/components/gridForm/GridFormTextInput.d.ts +3 -3
  17. package/dist/src/components/gridPopoverEdit/GridPopoutEditMultiSelect.d.ts +3 -2
  18. package/dist/src/components/gridPopoverEdit/GridPopoverEditBearing.d.ts +5 -270
  19. package/dist/src/components/gridPopoverEdit/GridPopoverEditDropDown.d.ts +3 -2
  20. package/dist/src/components/gridPopoverEdit/GridPopoverMenu.d.ts +3 -4
  21. package/dist/src/components/gridPopoverEdit/GridPopoverMessage.d.ts +3 -2
  22. package/dist/src/components/gridPopoverEdit/GridPopoverTextArea.d.ts +3 -2
  23. package/dist/src/components/gridPopoverEdit/GridPopoverTextInput.d.ts +3 -2
  24. package/dist/src/components/gridRender/GridRenderGenericCell.d.ts +4 -5
  25. package/dist/src/contexts/GridContext.d.ts +1 -1
  26. package/dist/src/contexts/GridPopoverContext.d.ts +17 -0
  27. package/dist/src/contexts/GridPopoverContextProvider.d.ts +6 -0
  28. package/dist/src/contexts/{UpdatingContext.d.ts → GridUpdatingContext.d.ts} +2 -2
  29. package/dist/src/contexts/GridUpdatingContextProvider.d.ts +7 -0
  30. package/dist/src/index.d.ts +31 -0
  31. package/dist/src/react-menu3/components/MenuRadioGroup.d.ts +2 -21
  32. package/dist/src/react-menu3/contexts/EventHandlersContext.d.ts +7 -0
  33. package/dist/src/react-menu3/contexts/HoverItemContext.d.ts +2 -0
  34. package/dist/src/react-menu3/contexts/ItemSettingsContext.d.ts +5 -0
  35. package/dist/src/react-menu3/contexts/MenuListContext.d.ts +9 -0
  36. package/dist/src/react-menu3/contexts/MenuListItemContext.d.ts +11 -0
  37. package/dist/src/react-menu3/contexts/RadioGroupContext.d.ts +7 -0
  38. package/dist/src/react-menu3/contexts/SettingsContext.d.ts +20 -0
  39. package/dist/src/react-menu3/index.d.ts +0 -1
  40. package/dist/src/react-menu3/utils/constants.d.ts +1 -50
  41. package/dist/step-ag-grid.esm.js +622 -312
  42. package/dist/step-ag-grid.esm.js.map +1 -1
  43. package/package.json +39 -26
  44. package/src/components/ComponentLoadingWrapper.tsx +2 -1
  45. package/src/components/Grid.tsx +3 -8
  46. package/src/components/GridCell.tsx +62 -79
  47. package/src/components/GridLoadableCell.tsx +0 -1
  48. package/src/components/GridPopoverHook.tsx +18 -16
  49. package/src/components/gridForm/GridFormDropDown.tsx +47 -32
  50. package/src/components/gridForm/GridFormEditBearing.tsx +14 -14
  51. package/src/components/gridForm/GridFormMessage.tsx +11 -17
  52. package/src/components/gridForm/GridFormMultiSelect.tsx +89 -79
  53. package/src/components/gridForm/GridFormPopoutMenu.tsx +10 -11
  54. package/src/components/gridForm/GridFormTextArea.tsx +16 -17
  55. package/src/components/gridForm/GridFormTextInput.tsx +17 -17
  56. package/src/components/gridPopoverEdit/GridPopoutEditMultiSelect.ts +20 -15
  57. package/src/components/gridPopoverEdit/GridPopoverEditBearing.ts +53 -45
  58. package/src/components/gridPopoverEdit/GridPopoverEditDropDown.ts +21 -15
  59. package/src/components/gridPopoverEdit/GridPopoverMenu.scss +4 -4
  60. package/src/components/gridPopoverEdit/GridPopoverMenu.tsx +21 -23
  61. package/src/components/gridPopoverEdit/GridPopoverMessage.ts +18 -16
  62. package/src/components/gridPopoverEdit/GridPopoverTextArea.ts +12 -16
  63. package/src/components/gridPopoverEdit/GridPopoverTextInput.ts +15 -15
  64. package/src/components/gridRender/GridRenderGenericCell.tsx +5 -6
  65. package/src/components/gridRender/GridRenderPopoutMenuCell.tsx +2 -2
  66. package/src/contexts/GridContext.tsx +1 -1
  67. package/src/contexts/GridContextProvider.tsx +3 -5
  68. package/src/contexts/GridPopoverContext.tsx +26 -0
  69. package/src/contexts/GridPopoverContextProvider.tsx +54 -0
  70. package/src/contexts/{UpdatingContext.tsx → GridUpdatingContext.tsx} +2 -2
  71. package/src/contexts/{UpdatingContextProvider.tsx → GridUpdatingContextProvider.tsx} +8 -6
  72. package/src/index.ts +38 -0
  73. package/src/lui/TextInputFormatted.scss +1 -1
  74. package/src/react-menu3/README.md +66 -0
  75. package/src/react-menu3/components/ControlledMenu.tsx +9 -17
  76. package/src/react-menu3/components/FocusableItem.tsx +2 -9
  77. package/src/react-menu3/components/MenuGroup.tsx +2 -1
  78. package/src/react-menu3/components/MenuItem.tsx +3 -12
  79. package/src/react-menu3/components/MenuList.tsx +4 -4
  80. package/src/react-menu3/components/MenuRadioGroup.tsx +3 -22
  81. package/src/react-menu3/components/SubMenu.tsx +4 -4
  82. package/src/react-menu3/contexts/EventHandlersContext.ts +11 -0
  83. package/src/react-menu3/contexts/HoverItemContext.ts +3 -0
  84. package/src/react-menu3/contexts/ItemSettingsContext.ts +6 -0
  85. package/src/react-menu3/contexts/MenuListContext.ts +10 -0
  86. package/src/react-menu3/contexts/MenuListItemContext.ts +16 -0
  87. package/src/react-menu3/contexts/RadioGroupContext.ts +8 -0
  88. package/src/react-menu3/contexts/SettingsContext.ts +20 -0
  89. package/src/react-menu3/hooks/useItemState.ts +3 -1
  90. package/src/react-menu3/index.ts +0 -1
  91. package/src/react-menu3/styles/_var.scss +4 -4
  92. package/src/react-menu3/styles/core.scss +6 -6
  93. package/src/react-menu3/styles/index.scss +10 -7
  94. package/src/react-menu3/styles/theme-dark.scss +4 -2
  95. package/src/react-menu3/styles/transitions/slide.scss +8 -8
  96. package/src/react-menu3/utils/constants.ts +1 -74
  97. package/src/react-menu3/utils/withHovering.tsx +1 -1
  98. package/src/stories/components/FormTest.scss +1 -2
  99. package/src/stories/components/FormTest.tsx +4 -3
  100. package/src/stories/components/GridPopoutBearing.stories.tsx +30 -26
  101. package/src/stories/components/GridPopoutEditDropDown.stories.tsx +94 -51
  102. package/src/stories/components/GridPopoutEditGeneric.stories.tsx +18 -14
  103. package/src/stories/components/GridPopoutEditGenericTextArea.stories.tsx +78 -62
  104. package/src/stories/components/GridPopoutEditMultiSelect.stories.tsx +60 -52
  105. package/src/stories/components/GridReadOnly.stories.tsx +77 -64
  106. package/src/stories/components/ReactMenu.stories.tsx +0 -4
  107. package/src/{components → styles}/Grid.scss +9 -6
  108. package/src/styles/GridFormDropDown.scss +18 -0
  109. package/src/{components/gridForm → styles}/GridFormEditBearing.scss +0 -0
  110. package/src/styles/GridFormMultiSelect.scss +18 -0
  111. package/src/styles/GridRenderGenericCell.scss +15 -0
  112. package/src/styles/GridTheme.scss +108 -0
  113. package/src/styles/index.scss +2 -0
  114. package/src/styles/lui-overrides.scss +49 -0
  115. package/src/styles/react-menu-customisations.scss +135 -0
  116. package/dist/index.d.ts +0 -38
  117. package/dist/src/contexts/UpdatingContextProvider.d.ts +0 -7
  118. package/dist/src/stories/components/FormTest.d.ts +0 -13
  119. package/dist/src/stories/components/GridPopoutBearing.stories.d.ts +0 -9
  120. package/dist/src/stories/components/GridPopoutEditDropDown.stories.d.ts +0 -9
  121. package/dist/src/stories/components/GridPopoutEditGeneric.stories.d.ts +0 -9
  122. package/dist/src/stories/components/GridPopoutEditGenericTextArea.stories.d.ts +0 -9
  123. package/dist/src/stories/components/GridPopoutEditMultiSelect.stories.d.ts +0 -9
  124. package/dist/src/stories/components/GridReadOnly.stories.d.ts +0 -9
  125. package/dist/src/stories/components/ReactMenu.stories.d.ts +0 -8
  126. package/src/components/gridRender/GridRenderGenericCell.scss +0 -15
  127. package/src/lui-overrides.scss +0 -163
  128. package/src/react-menu3/style-utils.d.ts +0 -110
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": "1.5.4",
5
+ "version": "2.0.1",
6
6
  "main": "dist/index.js",
7
7
  "typings": "dist/index.d.ts",
8
8
  "module": "dist/step-ag-grid.esm.js",
@@ -20,27 +20,32 @@
20
20
  "@linzjs/lui": ">=17",
21
21
  "ag-grid-community": ">=27",
22
22
  "ag-grid-react": ">=27",
23
+ "lodash-es": ">=4",
23
24
  "react": ">=17",
24
25
  "react-dom": ">=17"
25
26
  },
26
27
  "dependencies": {
27
28
  "@linzjs/lui": ">=17",
28
- "ag-grid-community": ">=27",
29
- "ag-grid-react": ">=27",
29
+ "ag-grid-community": "^27",
30
+ "ag-grid-react": "^27",
30
31
  "debounce-promise": "^3.1.2",
31
32
  "lodash-es": "^4.17.21",
32
- "react": ">=17",
33
- "react-dom": ">=17",
33
+ "react": "^17",
34
+ "react-dom": "^17",
34
35
  "react-transition-state": "^1.1.5",
35
36
  "uuid": "^9.0.0"
36
37
  },
37
38
  "scripts": {
38
- "build": "rollup -c && npm run",
39
- "test": "react-scripts test --passWithNoTests",
39
+ "build": "run-s clean stylelint lint css bundle",
40
+ "clean": "rimraf dist && mkdirp ./dist",
41
+ "bundle": "rollup -c",
42
+ "stylelint": "stylelint src/**/*.scss src/**/*.css --fix",
43
+ "css": "sass ./src/styles/index.scss:dist/index.css --no-source-map",
44
+ "test": "react-scripts test",
40
45
  "eject": "react-scripts eject",
41
46
  "lint": "eslint ./src --ext .js,.ts,.tsx --fix --cache",
42
- "storybook": "start-storybook -p 6006 -s public",
43
- "build-storybook": "build-storybook -s public",
47
+ "storybook": "start-storybook -p 6006",
48
+ "build-storybook": "build-storybook",
44
49
  "deploy-storybook": "npx --yes -p @storybook/storybook-deployer storybook-to-ghpages",
45
50
  "chromatic": "chromatic --exit-zero-on-changes",
46
51
  "semantic-release": "semantic-release"
@@ -78,46 +83,54 @@
78
83
  "@storybook/test-runner": "^0.9.0",
79
84
  "@storybook/testing-library": "^0.0.13",
80
85
  "@testing-library/jest-dom": "^5.16.5",
81
- "@testing-library/react": "^12.1.5",
86
+ "@testing-library/react": "^13.4.0",
82
87
  "@testing-library/user-event": "^14.4.3",
83
88
  "@types/debounce-promise": "^3.1.5",
84
- "@types/jest": "^29.2.0",
89
+ "@types/jest": "^29.2.2",
85
90
  "@types/lodash-es": "^4.17.6",
86
- "@types/node": "^18.11.7",
91
+ "@types/node": "^18.11.9",
87
92
  "@types/react": "^17.0.52",
88
93
  "@types/react-dom": "^17.0.18",
89
94
  "@types/uuid": "^8.3.4",
90
- "@typescript-eslint/parser": "^5.41.0",
91
- "babel-jest": "^26.6.3",
92
- "babel-preset-react-app": "10.0.0",
93
- "chromatic": "^6.11.2",
94
- "css-loader": "3.6.0",
95
- "eslint": "8.22.0",
95
+ "@typescript-eslint/parser": "^5.42.0",
96
+ "babel-jest": "^29.2.2",
97
+ "babel-preset-react-app": "^10.0.1",
98
+ "chromatic": "^6.11.4",
99
+ "eslint": "^8.26.0",
96
100
  "eslint-config-prettier": "^8.5.0",
97
101
  "eslint-config-react-app": "^7.0.1",
98
102
  "eslint-plugin-deprecation": "^1.3.2",
99
103
  "eslint-plugin-import": "^2.26.0",
100
- "eslint-plugin-jest": "^27.1.3",
104
+ "eslint-plugin-jest": "^27.1.4",
101
105
  "eslint-plugin-jsx-a11y": "^6.6.1",
102
106
  "eslint-plugin-prettier": "^4.2.1",
103
107
  "eslint-plugin-react": "^7.31.10",
104
108
  "eslint-plugin-react-hooks": "^4.6.0",
105
109
  "eslint-plugin-testing-library": "^5.9.1",
106
- "postcss": "^8.1.7",
107
- "postcss-loader": "^4.0.4",
110
+ "mkdirp": "^1.0.4",
111
+ "npm-run-all": "^4.1.5",
112
+ "postcss": "^8.4.18",
113
+ "postcss-scss": "^4.0.5",
114
+ "postcss-loader": "^7.0.1",
108
115
  "prettier": "^2.7.1",
109
116
  "react-scripts": "^5.0.1",
110
- "rollup": "^2.56.3",
117
+ "rollup": "^3.2.5",
111
118
  "rollup-plugin-copy": "^3.4.0",
112
119
  "rollup-plugin-peer-deps-external": "^2.2.4",
113
120
  "rollup-plugin-postcss": "^4.0.2",
114
- "rollup-plugin-typescript2": "^0.31.2",
115
- "sass": "^1.55.0",
116
- "sass-loader": "10.1.1",
121
+ "rollup-plugin-typescript2": "^0.34.1",
122
+ "sass": "^1.56.0",
123
+ "sass-loader": "10.3.1",
117
124
  "semantic-release": "^19.0.5",
118
125
  "storybook-addon-mock": "^2.4.1",
119
126
  "style-loader": "^2.0.0",
120
- "tsconfig-paths-webpack-plugin": "^3.5.2",
127
+ "stylelint": "^14.14.1",
128
+ "stylelint-config-prettier": "^9.0.3",
129
+ "stylelint-config-standard": "^29.0.0",
130
+ "stylelint-config-recommended-scss": "^8.0.0",
131
+ "stylelint-prettier": "^2.0.0",
132
+ "stylelint-scss": "^4.3.0",
133
+ "tsconfig-paths-webpack-plugin": "^4.0.0",
121
134
  "typescript": "^4.8.4"
122
135
  },
123
136
  "babel": {
@@ -7,11 +7,12 @@ export const ComponentLoadingWrapper = (props: {
7
7
  loading?: boolean;
8
8
  saving?: boolean;
9
9
  children: JSX.Element | undefined;
10
+ className: string | undefined;
10
11
  }): JSX.Element => {
11
12
  return props.loading ? (
12
13
  <LuiMiniSpinner size={22} divProps={{ role: "status", ["aria-label"]: "Loading", style: { padding: 16 } }} />
13
14
  ) : (
14
- <div style={{ maxHeight: 400, overflowY: "auto", pointerEvents: props.saving ? "none" : "inherit" }}>
15
+ <div style={{ pointerEvents: props.saving ? "none" : "inherit" }} className={props.className}>
15
16
  {props.saving && (
16
17
  <div
17
18
  style={{
@@ -1,6 +1,3 @@
1
- import "./Grid.scss";
2
- import "./GridTheme.scss";
3
-
4
1
  import clsx from "clsx";
5
2
  import { useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
6
3
  import { AgGridReact } from "ag-grid-react";
@@ -12,7 +9,7 @@ import { GridContext } from "@contexts/GridContext";
12
9
  import { usePostSortRowsHook } from "./PostSortRowsHook";
13
10
  import { isNotEmpty } from "@utils/util";
14
11
  import { GridHeaderSelect } from "./gridHeader/GridHeaderSelect";
15
- import { UpdatingContext } from "@contexts/UpdatingContext";
12
+ import { GridUpdatingContext } from "@contexts/GridUpdatingContext";
16
13
 
17
14
  export interface GridBaseRow {
18
15
  id: string | number;
@@ -47,7 +44,7 @@ export const Grid = (params: GridProps): JSX.Element => {
47
44
  ensureSelectedRowIsVisible,
48
45
  sizeColumnsToFit,
49
46
  } = useContext(GridContext);
50
- const { checkUpdating } = useContext(UpdatingContext);
47
+ const { checkUpdating } = useContext(GridUpdatingContext);
51
48
 
52
49
  const [internalQuickFilter, setInternalQuickFilter] = useState("");
53
50
  const lastSelectedIds = useRef<number[]>([]);
@@ -157,9 +154,7 @@ export const Grid = (params: GridProps): JSX.Element => {
157
154
  );
158
155
 
159
156
  const noRowsOverlayComponent = useCallback(
160
- () => (
161
- <span className="ag-overlay-no-rows-center">{params.noRowsOverlayText ?? "There are currently no rows"}</span>
162
- ),
157
+ () => <span>{params.noRowsOverlayText ?? "There are currently no rows"}</span>,
163
158
  [params.noRowsOverlayText],
164
159
  );
165
160
 
@@ -1,40 +1,27 @@
1
- import { ForwardedRef, forwardRef, useCallback, useContext, useMemo, useState } from "react";
1
+ import { forwardRef, useContext } from "react";
2
2
  import { GridBaseRow } from "./Grid";
3
- import { UpdatingContext } from "@contexts/UpdatingContext";
4
- import { GridContext } from "@contexts/GridContext";
3
+ import { GridUpdatingContext } from "@contexts/GridUpdatingContext";
5
4
  import { GenericMultiEditCellClass } from "./GenericCellClass";
6
- import { GenericCellRendererParams, GridRendererGenericCell } from "./gridRender/GridRenderGenericCell";
5
+ import {
6
+ GenericCellColDef,
7
+ GenericCellRendererParams,
8
+ GridRendererGenericCell,
9
+ } from "./gridRender/GridRenderGenericCell";
7
10
  import { ColDef, ICellEditorParams, ICellRendererParams } from "ag-grid-community";
8
11
  import { GridLoadableCell } from "./GridLoadableCell";
9
12
  import { GridIcon } from "@components/GridIcon";
10
13
  import { ValueFormatterParams } from "ag-grid-community/dist/lib/entities/colDef";
14
+ import { GridPopoverContext } from "@contexts/GridPopoverContext";
15
+ import { GridPopoverContextProvider } from "@contexts/GridPopoverContextProvider";
11
16
 
12
- export interface GridFormProps<RowType extends GridBaseRow> {
13
- cellEditorParams: ICellEditorParams;
14
- updateValue: (saveFn: (selectedRows: RowType[]) => Promise<boolean>) => Promise<boolean>;
15
- saving: boolean;
16
- data: RowType;
17
- value: any;
18
- field: string | undefined;
19
- selectedRows: RowType[];
20
- formProps: Record<string, any>;
21
- }
22
-
23
- export interface GenericCellEditorParams<RowType extends GridBaseRow> {
17
+ export interface GenericCellEditorProps<E> {
24
18
  multiEdit?: boolean;
25
- form?: (props: GridFormProps<RowType>) => JSX.Element;
26
- }
27
-
28
- export interface GenericCellEditorColDef<
29
- RowType extends GridBaseRow,
30
- FormProps extends GenericCellEditorParams<RowType>,
31
- > extends ColDef {
32
- cellEditorParams?: FormProps;
33
- cellRendererParams?: GenericCellRendererParams<RowType>;
19
+ editor?: (editorProps: E) => JSX.Element;
20
+ editorParams?: E; // Omit<E, keyof CellParams<IFormTestRow>>
34
21
  }
35
22
 
36
23
  export const GridCellRenderer = (props: ICellRendererParams) => {
37
- const { checkUpdating } = useContext(UpdatingContext);
24
+ const { checkUpdating } = useContext(GridUpdatingContext);
38
25
  const colDef = props.colDef as ColDef;
39
26
 
40
27
  const rendererParams = colDef.cellRendererParams as GenericCellRendererParams<any> | undefined;
@@ -56,19 +43,33 @@ export const GridCellRenderer = (props: ICellRendererParams) => {
56
43
  );
57
44
  };
58
45
 
59
- /**
46
+ // This is so that typescript retains the row type to pass to the GridCells
47
+ export interface ColDefT<RowType extends GridBaseRow> extends ColDef {
48
+ _?: RowType;
49
+ }
50
+
51
+ /*
60
52
  * For editing a text area.
61
53
  */
62
- export const GridCell = <RowType extends GridBaseRow, FormProps extends GenericCellEditorParams<RowType>>(
63
- props: GenericCellEditorColDef<RowType, FormProps>,
64
- ): ColDef => {
54
+ export const GridCell = <RowType extends GridBaseRow, Props>(
55
+ props: GenericCellColDef<RowType>,
56
+ custom?: {
57
+ multiEdit?: boolean;
58
+ editor?: (editorProps: Props) => JSX.Element;
59
+ editorParams?: Props;
60
+ },
61
+ ): ColDefT<RowType> => {
65
62
  return {
63
+ colId: props.field,
66
64
  sortable: !!(props?.field || props?.valueGetter),
67
65
  resizable: true,
68
- ...(props.cellEditorParams && {
69
- cellClass: props?.cellEditorParams?.multiEdit ? GenericMultiEditCellClass : undefined,
70
- editable: true,
71
- cellEditor: GenericCellEditorComponent,
66
+ ...(custom?.editor && {
67
+ cellClass: custom?.multiEdit ? GenericMultiEditCellClass : undefined,
68
+ editable: props.editable ?? true,
69
+ cellEditor: GenericCellEditorComponent(custom.editor),
70
+ }),
71
+ ...(custom?.editorParams && {
72
+ cellEditorParams: { ...custom.editorParams, multiEdit: custom.multiEdit },
72
73
  }),
73
74
  // Default value formatter, otherwise react freaks out on objects
74
75
  valueFormatter: (params: ValueFormatterParams) => {
@@ -86,59 +87,41 @@ export const GridCell = <RowType extends GridBaseRow, FormProps extends GenericC
86
87
  };
87
88
  };
88
89
 
89
- interface GenericCellEditorICellEditorParams<RowType extends GridBaseRow, FormProps extends Record<string, any>>
90
- extends ICellEditorParams {
91
- data: RowType;
92
- colDef: GenericCellEditorColDef<RowType, FormProps>;
90
+ export interface CellEditorCommon {
91
+ className?: string | undefined;
93
92
  }
94
93
 
95
- export const GenericCellEditorComponentFr = <RowType extends GridBaseRow, FormProps extends Record<string, any>>(
96
- props: GenericCellEditorICellEditorParams<RowType, FormProps>,
97
- _: ForwardedRef<any>, // We don't forward the ref, as that's for generic aggrid cell editing
98
- ) => {
99
- const { updatingCells, getSelectedRows } = useContext(GridContext);
94
+ export interface CellParams<RowType extends GridBaseRow> {
95
+ value: any;
96
+ data: RowType;
97
+ field: string | undefined;
98
+ selectedRows: RowType[];
99
+ }
100
100
 
101
- const { colDef, data } = props;
102
- const { cellEditorParams } = props.colDef;
101
+ // TODO memo?
102
+ export const GenericCellEditorComponent = (editor: (props: any) => JSX.Element) =>
103
+ forwardRef(function GenericCellEditorComponent2(props: ICellEditorParams, _) {
104
+ return (
105
+ <GridPopoverContextProvider>
106
+ <GenericCellEditorComponent3 {...{ ...props, editor }} />
107
+ </GridPopoverContextProvider>
108
+ );
109
+ });
110
+
111
+ const GenericCellEditorComponent3 = (props: ICellEditorParams & { editor: (props: any) => JSX.Element }) => {
112
+ const { setProps, propsRef } = useContext(GridPopoverContext);
113
+
114
+ const { colDef } = props;
115
+ const { cellEditorParams } = colDef;
103
116
  const multiEdit = cellEditorParams?.multiEdit ?? false;
104
- const field = props.colDef.field ?? "";
105
-
106
- const formProps = colDef.cellEditorParams ?? {};
107
- const value = props.value;
108
-
109
- const selectedRows = useMemo(
110
- () => (multiEdit ? getSelectedRows<RowType>() : [data]),
111
- [data, getSelectedRows, multiEdit],
112
- );
113
-
114
- const [saving, setSaving] = useState(false);
115
-
116
- const updateValue = useCallback(
117
- async (saveFn: (selectedRows: any[]) => Promise<boolean>): Promise<boolean> => {
118
- return !saving && (await updatingCells({ selectedRows, field }, saveFn, setSaving));
119
- },
120
- [field, saving, selectedRows, updatingCells],
121
- );
122
117
 
123
- if (cellEditorParams == null) return <></>;
118
+ // TODO don't need all these props in context
119
+ setProps(props, multiEdit);
124
120
 
125
121
  return (
126
122
  <>
127
- <div>{colDef.cellRenderer ? <colDef.cellRenderer {...props} saving={saving} /> : props.value}</div>
128
- {cellEditorParams?.form && (
129
- <cellEditorParams.form
130
- cellEditorParams={props}
131
- updateValue={updateValue}
132
- saving={saving}
133
- formProps={formProps}
134
- data={data}
135
- value={value}
136
- field={field}
137
- selectedRows={selectedRows}
138
- />
139
- )}
123
+ <div>{colDef.cellRenderer ? <colDef.cellRenderer {...props} /> : props.value}</div>
124
+ {props?.editor && <props.editor {...cellEditorParams} {...propsRef.current} />}
140
125
  </>
141
126
  );
142
127
  };
143
-
144
- export const GenericCellEditorComponent = forwardRef(GenericCellEditorComponentFr);
@@ -9,7 +9,6 @@ export const GridLoadableCell = (props: {
9
9
  children: JSX.Element | string;
10
10
  className?: string;
11
11
  }): JSX.Element => {
12
- // console.log(`Rendering LoadableCell - loading: ${props.isLoading}`);
13
12
  if (props.isLoading) {
14
13
  return (
15
14
  <div style={{ display: "flex", alignItems: "center" }}>
@@ -1,20 +1,18 @@
1
- import { ICellEditorParams } from "ag-grid-community";
2
1
  import { useCallback, useContext, useEffect, useRef, useState } from "react";
3
2
  import { GridContext } from "@contexts/GridContext";
4
- import { GridFormProps } from "./GridCell";
5
3
  import { GridBaseRow } from "./Grid";
6
4
  import { ControlledMenu } from "@react-menu3";
5
+ import { GridPopoverContext } from "@contexts/GridPopoverContext";
7
6
 
8
- export const useGridPopoverHook = <RowType extends GridBaseRow>(
9
- props: GridFormProps<RowType>,
10
- save?: (selectedRows: any[]) => Promise<boolean>,
11
- ) => {
12
- const { cellEditorParams, saving, updateValue } = props;
13
- const { eGridCell } = cellEditorParams as ICellEditorParams;
7
+ export interface GridPopoverHookProps<RowType> {
8
+ className: string | undefined;
9
+ save?: (selectedRows: RowType[]) => Promise<boolean>;
10
+ }
11
+
12
+ export const useGridPopoverHook = <RowType extends GridBaseRow>(props: GridPopoverHookProps<RowType>) => {
14
13
  const { stopEditing } = useContext(GridContext);
14
+ const { anchorRef, saving, propsRef } = useContext(GridPopoverContext);
15
15
  const saveButtonRef = useRef<HTMLButtonElement>(null);
16
- const anchorRef = useRef(eGridCell);
17
- anchorRef.current = eGridCell;
18
16
  const [isOpen, setOpen] = useState(false);
19
17
 
20
18
  useEffect(() => {
@@ -23,12 +21,16 @@ export const useGridPopoverHook = <RowType extends GridBaseRow>(
23
21
 
24
22
  const triggerSave = useCallback(
25
23
  async (reason?: string) => {
26
- if (reason == "cancel" || !save || (await updateValue(save))) {
24
+ if (
25
+ reason == "cancel" ||
26
+ !props.save ||
27
+ (propsRef.current?.updateValue && (await propsRef.current?.updateValue(props.save)))
28
+ ) {
27
29
  setOpen(false);
28
30
  stopEditing();
29
31
  }
30
32
  },
31
- [save, stopEditing, updateValue],
33
+ [props, stopEditing, propsRef],
32
34
  );
33
35
 
34
36
  const popoverWrapper = useCallback(
@@ -42,13 +44,13 @@ export const useGridPopoverHook = <RowType extends GridBaseRow>(
42
44
  unmountOnClose={true}
43
45
  anchorRef={anchorRef}
44
46
  saveButtonRef={saveButtonRef}
45
- menuClassName={"lui-menu"}
47
+ menuClassName={"step-ag-grid-react-menu"}
46
48
  onClose={(event: { reason: string }) => triggerSave(event.reason).then()}
47
- reposition={"initial"}
48
49
  viewScroll={"auto"}
49
50
  dontShrinkIfDirectionIsTop={true}
51
+ className={props.className}
50
52
  >
51
- {saving && (
53
+ {saving && ( // This is the overlay that prevents editing when the editor is saving
52
54
  <div
53
55
  style={{
54
56
  position: "absolute",
@@ -68,7 +70,7 @@ export const useGridPopoverHook = <RowType extends GridBaseRow>(
68
70
  </>
69
71
  );
70
72
  },
71
- [isOpen, saving, triggerSave],
73
+ [anchorRef, isOpen, props.className, saving, triggerSave],
72
74
  );
73
75
 
74
76
  return {
@@ -1,16 +1,17 @@
1
- import "../../react-menu3/styles/index.scss";
1
+ import "../../styles/GridFormDropDown.scss";
2
2
 
3
- import { MenuItem, MenuDivider, FocusableItem } from "@react-menu3";
3
+ import { MenuItem, MenuDivider, FocusableItem, MenuHeader } from "@react-menu3";
4
4
  import { useCallback, useContext, useEffect, useRef, useState, KeyboardEvent } from "react";
5
5
  import { GridBaseRow } from "../Grid";
6
6
  import { ComponentLoadingWrapper } from "../ComponentLoadingWrapper";
7
7
  import { GridContext } from "@contexts/GridContext";
8
8
  import { delay } from "lodash-es";
9
9
  import debounce from "debounce-promise";
10
- import { GenericCellEditorParams, GridFormProps } from "../GridCell";
10
+ import { CellEditorCommon, CellParams } from "../GridCell";
11
11
  import { useGridPopoverHook } from "../GridPopoverHook";
12
12
 
13
13
  export interface GridPopoutEditDropDownSelectedItem<RowType, ValueType> {
14
+ // Note the row that was clicked on will be first
14
15
  selectedRows: RowType[];
15
16
  value: ValueType;
16
17
  }
@@ -24,10 +25,21 @@ interface FinalSelectOption<ValueType> {
24
25
  export const MenuSeparatorString = "_____MENU_SEPARATOR_____";
25
26
  export const MenuSeparator = Object.freeze({ value: MenuSeparatorString });
26
27
 
28
+ export const MenuHeaderString = "_____MENU_HEADER_____";
29
+ export const MenuHeaderItem = (title: string) => {
30
+ return { label: title, value: MenuHeaderString };
31
+ };
32
+
27
33
  export type SelectOption<ValueType> = ValueType | FinalSelectOption<ValueType>;
28
34
 
29
- export interface GridFormPopoutDropDownProps<RowType extends GridBaseRow, ValueType>
30
- extends GenericCellEditorParams<RowType> {
35
+ export interface GridFormPopoutDropDownProps<RowType extends GridBaseRow, ValueType> extends CellEditorCommon {
36
+ // This overrides CellEditorCommon to provide some common class options
37
+ className?:
38
+ | "GridPopoverEditDropDown-containerSmall"
39
+ | "GridPopoverEditDropDown-containerMedium"
40
+ | "GridPopoverEditDropDown-containerLarge"
41
+ | string
42
+ | undefined;
31
43
  filtered?: "local" | "reload";
32
44
  filterPlaceholder?: string;
33
45
  onSelectedItem?: (props: GridPopoutEditDropDownSelectedItem<RowType, ValueType>) => Promise<void>;
@@ -38,10 +50,10 @@ export interface GridFormPopoutDropDownProps<RowType extends GridBaseRow, ValueT
38
50
  optionsRequestCancel?: () => void;
39
51
  }
40
52
 
41
- export const GridFormDropDown = <RowType extends GridBaseRow, ValueType>(props: GridFormProps<RowType>) => {
42
- const { popoverWrapper } = useGridPopoverHook(props);
43
- const formProps = props.formProps as GridFormPopoutDropDownProps<RowType, ValueType>;
44
-
53
+ export const GridFormDropDown = <RowType extends GridBaseRow, ValueType>(
54
+ _props: GridFormPopoutDropDownProps<RowType, ValueType>,
55
+ ) => {
56
+ const props = _props as GridFormPopoutDropDownProps<RowType, ValueType> & CellParams<RowType>;
45
57
  const { updatingCells, stopEditing } = useContext(GridContext);
46
58
 
47
59
  const [filter, setFilter] = useState("");
@@ -55,8 +67,8 @@ export const GridFormDropDown = <RowType extends GridBaseRow, ValueType>(props:
55
67
  return await updatingCells({ selectedRows: props.selectedRows, field }, async (selectedRows) => {
56
68
  const hasChanged = selectedRows.some((row) => row[field as keyof RowType] !== value);
57
69
  if (hasChanged) {
58
- if (formProps.onSelectedItem) {
59
- await formProps.onSelectedItem({ selectedRows, value });
70
+ if (props.onSelectedItem) {
71
+ await props.onSelectedItem({ selectedRows, value });
60
72
  } else {
61
73
  selectedRows.forEach((row) => (row[field as keyof RowType] = value));
62
74
  }
@@ -64,27 +76,27 @@ export const GridFormDropDown = <RowType extends GridBaseRow, ValueType>(props:
64
76
  return true;
65
77
  });
66
78
  },
67
- [formProps, props.field, props.selectedRows, updatingCells],
79
+ [props, updatingCells],
68
80
  );
69
81
 
70
82
  const selectFilterHandler = useCallback(
71
83
  async (value: string): Promise<boolean> => {
72
84
  const field = props.field;
73
85
  return await updatingCells({ selectedRows: props.selectedRows, field }, async (selectedRows) => {
74
- if (formProps.onSelectFilter) {
75
- await formProps.onSelectFilter({ selectedRows, value });
86
+ if (props.onSelectFilter) {
87
+ await props.onSelectFilter({ selectedRows, value });
76
88
  }
77
89
  return true;
78
90
  });
79
91
  },
80
- [formProps, props.field, props.selectedRows, updatingCells],
92
+ [props, updatingCells],
81
93
  );
82
94
 
83
95
  // Load up options list if it's async function
84
96
  useEffect(() => {
85
97
  if (options || optionsInitialising.current) return;
86
98
  optionsInitialising.current = true;
87
- let optionsConf = formProps.options ?? [];
99
+ let optionsConf = props.options ?? [];
88
100
 
89
101
  (async () => {
90
102
  if (typeof optionsConf == "function") {
@@ -98,7 +110,7 @@ export const GridFormDropDown = <RowType extends GridBaseRow, ValueType>(props:
98
110
  return item;
99
111
  }) as any as FinalSelectOption<ValueType>[];
100
112
 
101
- if (formProps.filtered) {
113
+ if (props.filtered) {
102
114
  // This is needed otherwise when filter input is rendered and sets autofocus
103
115
  // the mouse up of the double click edit triggers the cell to cancel editing
104
116
  delay(() => setOptions(optionsList), 100);
@@ -107,11 +119,11 @@ export const GridFormDropDown = <RowType extends GridBaseRow, ValueType>(props:
107
119
  }
108
120
  optionsInitialising.current = false;
109
121
  })();
110
- }, [filter, options, formProps.filtered, formProps.options, props.selectedRows]);
122
+ }, [filter, options, props]);
111
123
 
112
- // Local filtering
124
+ // Local filtering.
113
125
  useEffect(() => {
114
- if (formProps.filtered == "local") {
126
+ if (props.filtered == "local") {
115
127
  if (options == null) return;
116
128
  setFilteredValues(
117
129
  options
@@ -126,7 +138,7 @@ export const GridFormDropDown = <RowType extends GridBaseRow, ValueType>(props:
126
138
  .filter((r) => r !== undefined),
127
139
  );
128
140
  }
129
- }, [formProps.filtered, filter, options]);
141
+ }, [props.filtered, filter, options]);
130
142
 
131
143
  const researchOnFilterChange = debounce(
132
144
  useCallback(() => {
@@ -137,14 +149,14 @@ export const GridFormDropDown = <RowType extends GridBaseRow, ValueType>(props:
137
149
 
138
150
  const previousFilter = useRef<string>(filter);
139
151
 
140
- // Reload filtering
152
+ // Reload filtering.
141
153
  useEffect(() => {
142
- if (previousFilter.current != filter && formProps.filtered == "reload") {
154
+ if (previousFilter.current != filter && props.filtered == "reload") {
143
155
  previousFilter.current = filter;
144
- formProps.optionsRequestCancel && formProps.optionsRequestCancel();
156
+ props.optionsRequestCancel && props.optionsRequestCancel();
145
157
  researchOnFilterChange().then();
146
158
  }
147
- }, [filter, formProps, props, researchOnFilterChange]);
159
+ }, [filter, props, researchOnFilterChange]);
148
160
 
149
161
  const onFilterKeyDown = useCallback(
150
162
  async (e: KeyboardEvent) => {
@@ -154,7 +166,7 @@ export const GridFormDropDown = <RowType extends GridBaseRow, ValueType>(props:
154
166
  if (activeOptions.length == 1) {
155
167
  await selectItemHandler(activeOptions[0].value);
156
168
  stopEditing();
157
- } else if (formProps.onSelectFilter) {
169
+ } else if (props.onSelectFilter) {
158
170
  await selectFilterHandler(filter);
159
171
  stopEditing();
160
172
  } else {
@@ -163,13 +175,14 @@ export const GridFormDropDown = <RowType extends GridBaseRow, ValueType>(props:
163
175
  }
164
176
  }
165
177
  },
166
- [filteredValues, options, selectItemHandler, selectFilterHandler, stopEditing, filter, formProps],
178
+ [filteredValues, options, selectItemHandler, selectFilterHandler, stopEditing, filter, props],
167
179
  );
168
180
 
181
+ const { popoverWrapper } = useGridPopoverHook({ className: props.className });
169
182
  return popoverWrapper(
170
183
  <>
171
- {formProps.filtered && (
172
- <>
184
+ {props.filtered && (
185
+ <div className={"GridFormDropDown-filter"}>
173
186
  <FocusableItem className={"filter-item"}>
174
187
  {({ ref }: any) => (
175
188
  <div style={{ display: "flex", width: "100%" }}>
@@ -179,7 +192,7 @@ export const GridFormDropDown = <RowType extends GridBaseRow, ValueType>(props:
179
192
  style={{ border: "0px" }}
180
193
  ref={ref}
181
194
  type="text"
182
- placeholder={formProps.filterPlaceholder ?? "Placeholder"}
195
+ placeholder={props.filterPlaceholder ?? "Placeholder"}
183
196
  data-testid={"filteredMenu-free-text-input"}
184
197
  defaultValue={filter}
185
198
  onChange={(e) => setFilter(e.target.value.toLowerCase())}
@@ -189,14 +202,16 @@ export const GridFormDropDown = <RowType extends GridBaseRow, ValueType>(props:
189
202
  )}
190
203
  </FocusableItem>
191
204
  <MenuDivider key={`$$divider_filter`} />
192
- </>
205
+ </div>
193
206
  )}
194
- <ComponentLoadingWrapper loading={!options}>
207
+ <ComponentLoadingWrapper loading={!options} className={"GridFormDropDown-options"}>
195
208
  <>
196
209
  {options && options.length == filteredValues?.length && <MenuItem>[Empty]</MenuItem>}
197
210
  {options?.map((item, index) =>
198
211
  item.value === MenuSeparatorString ? (
199
212
  <MenuDivider key={`$$divider_${index}`} />
213
+ ) : item.value === MenuHeaderString ? (
214
+ <MenuHeader>{item.label}</MenuHeader>
200
215
  ) : filteredValues.includes(item.value) ? null : (
201
216
  <MenuItem
202
217
  key={`${props.field}-${index}`}