@linzjs/step-ag-grid 1.4.5 → 1.4.7

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 (85) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.js +284 -232
  3. package/dist/index.js.map +1 -1
  4. package/dist/src/components/GridCell.d.ts +4 -3
  5. package/dist/src/components/gridRender/GridRenderGenericCell.d.ts +8 -5
  6. package/dist/src/react-menu3/components/ControlledMenu.d.ts +8 -2
  7. package/dist/src/react-menu3/components/FocusableItem.d.ts +8 -0
  8. package/dist/src/react-menu3/components/Menu.d.ts +16 -2
  9. package/dist/src/react-menu3/components/MenuButton.d.ts +8 -1
  10. package/dist/src/react-menu3/components/MenuDivider.d.ts +2 -1
  11. package/dist/src/react-menu3/components/MenuGroup.d.ts +12 -2
  12. package/dist/src/react-menu3/components/MenuHeader.d.ts +4 -2
  13. package/dist/src/react-menu3/components/MenuItem.d.ts +56 -0
  14. package/dist/src/react-menu3/components/MenuList.d.ts +2 -29
  15. package/dist/src/react-menu3/components/MenuRadioGroup.d.ts +44 -2
  16. package/dist/src/react-menu3/components/SubMenu.d.ts +109 -0
  17. package/dist/src/react-menu3/hooks/useBEM.d.ts +4 -3
  18. package/dist/src/react-menu3/hooks/useCombinedRef.d.ts +2 -2
  19. package/dist/src/react-menu3/hooks/useItemEffect.d.ts +1 -1
  20. package/dist/src/react-menu3/hooks/useItemState.d.ts +4 -3
  21. package/dist/src/react-menu3/hooks/useItems.d.ts +6 -4
  22. package/dist/src/react-menu3/hooks/useMenuChange.d.ts +2 -1
  23. package/dist/src/react-menu3/hooks/useMenuState.d.ts +13 -10
  24. package/dist/src/react-menu3/hooks/useMenuStateAndFocus.d.ts +2 -10
  25. package/dist/src/react-menu3/index.d.ts +1 -0
  26. package/dist/src/react-menu3/positionUtils/getPositionHelpers.d.ts +10 -9
  27. package/dist/src/react-menu3/positionUtils/placeArrowHorizontal.d.ts +7 -6
  28. package/dist/src/react-menu3/positionUtils/placeArrowVertical.d.ts +7 -6
  29. package/dist/src/react-menu3/positionUtils/placeLeftorRight.d.ts +17 -19
  30. package/dist/src/react-menu3/positionUtils/placeToporBottom.d.ts +18 -20
  31. package/dist/src/react-menu3/positionUtils/positionContextMenu.d.ts +11 -6
  32. package/dist/src/react-menu3/positionUtils/positionMenu.d.ts +23 -18
  33. package/dist/src/react-menu3/types.d.ts +389 -0
  34. package/dist/src/react-menu3/utils/constants.d.ts +58 -9
  35. package/dist/src/react-menu3/utils/index.d.ts +0 -1
  36. package/dist/src/react-menu3/utils/{propTypes.d.ts → propTypes2.d.ts} +1 -0
  37. package/dist/src/react-menu3/utils/utils.d.ts +20 -11
  38. package/dist/src/react-menu3/utils/withHovering.d.ts +7 -1
  39. package/dist/src/stories/components/ReactMenu.stories.d.ts +8 -0
  40. package/dist/step-ag-grid.esm.js +276 -235
  41. package/dist/step-ag-grid.esm.js.map +1 -1
  42. package/package.json +11 -11
  43. package/src/components/GridCell.tsx +6 -3
  44. package/src/components/GridPopoverHook.tsx +1 -1
  45. package/src/components/gridForm/GridFormDropDown.tsx +1 -1
  46. package/src/components/gridForm/GridFormMultiSelect.tsx +36 -17
  47. package/src/components/gridRender/GridRenderGenericCell.tsx +11 -7
  48. package/src/components/gridRender/GridRenderPopoutMenuCell.tsx +14 -2
  49. package/src/contexts/GridContextProvider.tsx +3 -2
  50. package/src/react-menu3/components/ControlledMenu.tsx +40 -45
  51. package/src/react-menu3/components/FocusableItem.tsx +58 -53
  52. package/src/react-menu3/components/Menu.tsx +40 -28
  53. package/src/react-menu3/components/MenuButton.tsx +30 -29
  54. package/src/react-menu3/components/MenuDivider.tsx +14 -18
  55. package/src/react-menu3/components/MenuGroup.tsx +25 -16
  56. package/src/react-menu3/components/MenuHeader.tsx +14 -18
  57. package/src/react-menu3/components/MenuItem.tsx +158 -106
  58. package/src/react-menu3/components/MenuList.tsx +61 -36
  59. package/src/react-menu3/components/MenuRadioGroup.tsx +54 -15
  60. package/src/react-menu3/components/SubMenu.tsx +317 -202
  61. package/src/react-menu3/hooks/useBEM.ts +4 -3
  62. package/src/react-menu3/hooks/useCombinedRef.ts +6 -12
  63. package/src/react-menu3/hooks/useItemEffect.ts +6 -5
  64. package/src/react-menu3/hooks/useItemState.ts +16 -12
  65. package/src/react-menu3/hooks/useItems.ts +11 -10
  66. package/src/react-menu3/hooks/useMenuChange.ts +3 -3
  67. package/src/react-menu3/hooks/useMenuState.ts +25 -7
  68. package/src/react-menu3/hooks/useMenuStateAndFocus.ts +6 -4
  69. package/src/react-menu3/index.ts +1 -0
  70. package/src/react-menu3/positionUtils/getPositionHelpers.ts +19 -12
  71. package/src/react-menu3/positionUtils/placeArrowHorizontal.ts +12 -5
  72. package/src/react-menu3/positionUtils/placeArrowVertical.ts +12 -5
  73. package/src/react-menu3/positionUtils/placeLeftorRight.ts +33 -17
  74. package/src/react-menu3/positionUtils/placeToporBottom.ts +34 -18
  75. package/src/react-menu3/positionUtils/positionContextMenu.ts +15 -3
  76. package/src/react-menu3/positionUtils/positionMenu.ts +21 -14
  77. package/src/react-menu3/style-utils/index.ts +10 -7
  78. package/src/react-menu3/{index.d.ts → types.ts} +106 -358
  79. package/src/react-menu3/utils/constants.ts +82 -10
  80. package/src/react-menu3/utils/index.ts +1 -1
  81. package/src/react-menu3/utils/{propTypes.ts → propTypes2.ts} +3 -1
  82. package/src/react-menu3/utils/utils.ts +41 -24
  83. package/src/react-menu3/utils/withHovering.tsx +11 -6
  84. package/src/stories/components/GridReadOnly.stories.tsx +3 -4
  85. package/src/stories/components/ReactMenu.stories.tsx +37 -0
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.4.5",
5
+ "version": "1.4.7",
6
6
  "main": "dist/index.js",
7
7
  "typings": "dist/index.d.ts",
8
8
  "module": "dist/step-ag-grid.esm.js",
@@ -17,23 +17,23 @@
17
17
  "node": ">=14"
18
18
  },
19
19
  "peerDependencies": {
20
- "react": ">=17",
21
- "react-dom": ">=17",
20
+ "@linzjs/lui": ">=17",
22
21
  "ag-grid-community": ">=27",
23
22
  "ag-grid-react": ">=27",
24
- "@linzjs/lui": ">=17"
23
+ "react": ">=17",
24
+ "react-dom": ">=17"
25
25
  },
26
26
  "dependencies": {
27
- "@linzjs/lui": "^17.18.2",
28
- "ag-grid-community": "^27.3.0",
29
- "ag-grid-react": "^27.3.0",
27
+ "@linzjs/lui": ">=17",
28
+ "ag-grid-community": ">=27",
29
+ "ag-grid-react": ">=27",
30
30
  "debounce-promise": "^3.1.2",
31
31
  "lodash-es": "^4.17.21",
32
- "react": "^17.0.2",
33
- "react-dom": "^17.0.2",
34
- "uuid": "^9.0.0",
35
32
  "prop-types": "^15.8.1",
36
- "react-transition-state": "^1.1.5"
33
+ "react": ">=17",
34
+ "react-dom": ">=17",
35
+ "react-transition-state": "^1.1.5",
36
+ "uuid": "^9.0.0"
37
37
  },
38
38
  "scripts": {
39
39
  "build": "rollup -c && npm run",
@@ -1,4 +1,4 @@
1
- import { useCallback, useContext, useMemo, useState } from "react";
1
+ import { ForwardedRef, forwardRef, useCallback, useContext, useMemo, useState } from "react";
2
2
  import { GridBaseRow } from "./Grid";
3
3
  import { UpdatingContext } from "@contexts/UpdatingContext";
4
4
  import { GridContext } from "@contexts/GridContext";
@@ -27,7 +27,7 @@ export interface GenericCellEditorColDef<
27
27
  FormProps extends GenericCellEditorParams<RowType>,
28
28
  > extends ColDef {
29
29
  cellEditorParams?: FormProps;
30
- cellRendererParams?: GenericCellRendererParams;
30
+ cellRendererParams?: GenericCellRendererParams<RowType>;
31
31
  }
32
32
 
33
33
  export const GridCellRenderer = (cellRendererParams: ICellRendererParams) => {
@@ -77,8 +77,9 @@ interface GenericCellEditorICellEditorParams<RowType extends GridBaseRow, FormPr
77
77
  colDef: GenericCellEditorColDef<RowType, FormProps>;
78
78
  }
79
79
 
80
- export const GenericCellEditorComponent = <RowType extends GridBaseRow, FormProps extends Record<string, any>>(
80
+ export const GenericCellEditorComponentFr = <RowType extends GridBaseRow, FormProps extends Record<string, any>>(
81
81
  props: GenericCellEditorICellEditorParams<RowType, FormProps>,
82
+ _: ForwardedRef<any>, // We don't forward the ref, as that's for generic aggrid cell editing
82
83
  ) => {
83
84
  const { updatingCells, getSelectedRows } = useContext(GridContext);
84
85
 
@@ -123,3 +124,5 @@ export const GenericCellEditorComponent = <RowType extends GridBaseRow, FormProp
123
124
  </>
124
125
  );
125
126
  };
127
+
128
+ export const GenericCellEditorComponent = forwardRef(GenericCellEditorComponentFr);
@@ -3,7 +3,7 @@ import { useCallback, useContext, useEffect, useRef, useState } from "react";
3
3
  import { GridContext } from "@contexts/GridContext";
4
4
  import { GridFormProps } from "./GridCell";
5
5
  import { GridBaseRow } from "./Grid";
6
- import { ControlledMenu } from "../react-menu3";
6
+ import { ControlledMenu } from "@react-menu3";
7
7
 
8
8
  export const useGridPopoverHook = <RowType extends GridBaseRow>(
9
9
  props: GridFormProps<RowType>,
@@ -153,7 +153,7 @@ export const GridFormDropDown = <RowType extends GridBaseRow, ValueType>(props:
153
153
  <>
154
154
  {formProps.filtered && (
155
155
  <>
156
- <FocusableItem className={"filter-item"} index={-1}>
156
+ <FocusableItem className={"filter-item"}>
157
157
  {({ ref }: any) => (
158
158
  <div style={{ display: "flex", width: "100%" }}>
159
159
  <input
@@ -1,7 +1,7 @@
1
1
  import "../../react-menu3/styles/index.scss";
2
2
 
3
- import { MenuItem, MenuDivider, FocusableItem } from "@react-menu3";
4
- import { useCallback, useEffect, useRef, useState } from "react";
3
+ import { MenuItem, MenuDivider, FocusableItem, ClickEvent } from "@react-menu3";
4
+ import { Fragment, useCallback, useEffect, useRef, useState, KeyboardEvent } from "react";
5
5
  import { GridBaseRow } from "../Grid";
6
6
  import { ComponentLoadingWrapper } from "../ComponentLoadingWrapper";
7
7
  import { delay } from "lodash-es";
@@ -58,7 +58,7 @@ export const GridFormMultiSelect = <RowType extends GridBaseRow, ValueType>(prop
58
58
  },
59
59
  [formProps, selectedValues],
60
60
  );
61
- const { popoverWrapper } = useGridPopoverHook(props, save);
61
+ const { popoverWrapper, triggerSave } = useGridPopoverHook(props, save);
62
62
 
63
63
  // Load up options list if it's async function
64
64
  useEffect(() => {
@@ -99,7 +99,7 @@ export const GridFormMultiSelect = <RowType extends GridBaseRow, ValueType>(prop
99
99
  return undefined;
100
100
  }
101
101
  const str = (option.label as string) || "";
102
- return str.toLowerCase().indexOf(filter) === -1 ? option.value : undefined;
102
+ return str.toLowerCase().indexOf(filter.trim()) === -1 ? option.value : undefined;
103
103
  })
104
104
  .filter((r) => r !== undefined),
105
105
  );
@@ -110,7 +110,7 @@ export const GridFormMultiSelect = <RowType extends GridBaseRow, ValueType>(prop
110
110
  <div className={"Grid-popoverContainerList"}>
111
111
  {options && formProps.filtered && (
112
112
  <>
113
- <FocusableItem className={"filter-item"}>
113
+ <FocusableItem className={"filter-item"} key={"filter"}>
114
114
  {({ ref }: any) => (
115
115
  <div style={{ display: "flex", width: "100%" }}>
116
116
  <input
@@ -134,28 +134,47 @@ export const GridFormMultiSelect = <RowType extends GridBaseRow, ValueType>(prop
134
134
  item.value === MenuSeparatorString ? (
135
135
  <MenuDivider key={`$$divider_${index}`} />
136
136
  ) : filteredValues.includes(item.value) ? null : (
137
- <>
137
+ <Fragment key={`${index}`}>
138
138
  <MenuItem
139
- key={`${item.value}`}
140
- onClick={(e: { keepOpen: boolean }) => {
139
+ key={`${index}`}
140
+ onClick={(e: ClickEvent) => {
141
141
  e.keepOpen = true;
142
- // onSelectMenuOption(itemIndex, e.value);
143
- return false;
142
+ if (selectedValues.includes(item.value)) {
143
+ setSelectedValues(selectedValues.filter((value) => value != item.value));
144
+ } else {
145
+ setSelectedValues([...selectedValues, item.value]);
146
+ }
147
+ }}
148
+ onKeyDown={async (e: KeyboardEvent) => {
149
+ if (e.key === "Enter") triggerSave().then();
150
+ else if (e.key === " ") {
151
+ if (selectedValues.includes(item.value)) {
152
+ setSelectedValues(selectedValues.filter((value) => value != item.value));
153
+ } else {
154
+ setSelectedValues([...selectedValues, item.value]);
155
+ }
156
+ e.preventDefault();
157
+ e.stopPropagation();
158
+ }
144
159
  }}
145
160
  >
146
161
  <LuiCheckboxInput
147
162
  isChecked={selectedValues.includes(item.value)}
148
163
  value={`${item.value}`}
149
164
  label={item.label ?? (item.value == null ? `<${item.value}>` : `${item.value}`)}
150
- onChange={(e) => {
151
- if (e.target.checked) {
152
- setSelectedValues([...selectedValues, item.value as string]);
153
- } else {
154
- setSelectedValues(selectedValues.filter((value) => value != item.value));
155
- }
165
+ inputProps={{
166
+ onClick: (e) => {
167
+ e.preventDefault();
168
+ e.stopPropagation();
169
+ return false;
170
+ },
171
+ }}
172
+ onChange={() => {
173
+ /*Do nothing, change handled by menuItem*/
156
174
  }}
157
175
  />
158
176
  </MenuItem>
177
+
159
178
  {selectedValues.includes(item.value) && item.subComponent && (
160
179
  <FocusableItem className={"LuiDeprecatedForms"} key={`${item.value}_subcomponent`}>
161
180
  {(ref: any) =>
@@ -171,7 +190,7 @@ export const GridFormMultiSelect = <RowType extends GridBaseRow, ValueType>(prop
171
190
  }
172
191
  </FocusableItem>
173
192
  )}
174
- </>
193
+ </Fragment>
175
194
  ),
176
195
  )}
177
196
  </div>
@@ -1,7 +1,7 @@
1
1
  import "./GridRenderGenericCell.scss";
2
2
 
3
3
  import { useContext } from "react";
4
- import { UpdatingContext } from "../../contexts/UpdatingContext";
4
+ import { UpdatingContext } from "@contexts/UpdatingContext";
5
5
  import { GridLoadableCell } from "../GridLoadableCell";
6
6
  import { GridIcon } from "../GridIcon";
7
7
  import { ColDef, ICellRendererParams } from "ag-grid-community";
@@ -9,21 +9,25 @@ import { ValueFormatterParams } from "ag-grid-community/dist/lib/entities/colDef
9
9
  import { GenericCellEditorParams } from "../GridCell";
10
10
  import { GridBaseRow } from "../Grid";
11
11
 
12
+ export interface RowICellRendererParams<RowType extends GridBaseRow> extends ICellRendererParams {
13
+ data: RowType;
14
+ }
15
+
12
16
  export interface GenericCellColDef<RowType extends GridBaseRow, FormProps extends Record<string, any>> extends ColDef {
13
- cellRendererParams?: GenericCellRendererParams;
17
+ cellRendererParams?: GenericCellRendererParams<RowType>;
14
18
  cellEditorParams?: GenericCellEditorParams<RowType> & FormProps;
15
19
  }
16
20
 
17
- export interface GenericCellRendererParams {
21
+ export interface GenericCellRendererParams<RowType extends GridBaseRow> {
18
22
  singleClickEdit?: boolean;
19
- warning?: (props: ICellRendererParams) => string | boolean | undefined;
20
- info?: (props: ICellRendererParams) => string | boolean | undefined;
23
+ warning?: (props: RowICellRendererParams<RowType>) => string | boolean | undefined;
24
+ info?: (props: RowICellRendererParams<RowType>) => string | boolean | undefined;
21
25
  }
22
26
 
23
- export const GridRendererGenericCell = (props: ICellRendererParams): JSX.Element => {
27
+ export const GridRendererGenericCell = <RowType extends GridBaseRow>(props: ICellRendererParams): JSX.Element => {
24
28
  const { checkUpdating } = useContext(UpdatingContext);
25
29
 
26
- const cellRendererParams = props.colDef?.cellRendererParams as GenericCellRendererParams | undefined;
30
+ const cellRendererParams = props.colDef?.cellRendererParams as GenericCellRendererParams<RowType> | undefined;
27
31
  const warningFn = cellRendererParams?.warning;
28
32
  const warningText = warningFn ? warningFn(props) : undefined;
29
33
  const infoFn = cellRendererParams?.info;
@@ -1,13 +1,25 @@
1
1
  import { useContext } from "react";
2
- import { ICellRendererParams } from "ag-grid-community";
2
+ import { ColDef, ICellRendererParams } from "ag-grid-community";
3
3
  import { UpdatingContext } from "@contexts/UpdatingContext";
4
4
  import { GridLoadableCell } from "../GridLoadableCell";
5
5
  import { LuiIcon } from "@linzjs/lui";
6
+ import { Column } from "ag-grid-community/dist/lib/entities/column";
6
7
 
7
8
  export const GridRenderPopoutMenuCell = (props: ICellRendererParams) => {
8
9
  const { checkUpdating } = useContext(UpdatingContext);
9
10
  const isLoading = checkUpdating(props.colDef?.field ?? "", props.data.id);
10
- const disabled = !props.colDef?.editable;
11
+ const editable = props.colDef?.editable;
12
+ const disabled = !(typeof editable === "function"
13
+ ? editable({
14
+ node: props.node,
15
+ data: props.data,
16
+ column: props.column as Column,
17
+ colDef: props.colDef as ColDef,
18
+ api: props.api,
19
+ columnApi: props.columnApi,
20
+ context: props.context,
21
+ })
22
+ : editable);
11
23
 
12
24
  return (
13
25
  <GridLoadableCell
@@ -258,9 +258,10 @@ export const GridContextProvider = (props: GridContextProps): ReactElement => {
258
258
  }
259
259
  // This is needed to trigger postSortRowsHook
260
260
  gridApi.refreshClientSideRowModel();
261
- stopEditing();
261
+ } else {
262
+ // Don't set saving if ok as the form has already closed
263
+ setSaving && setSaving(false);
262
264
  }
263
- setSaving && setSaving(false);
264
265
  return ok;
265
266
  });
266
267
  };
@@ -1,27 +1,33 @@
1
- // @ts-nocheck
2
- import { forwardRef, useRef, useMemo, useCallback, useEffect } from "react";
1
+ import {
2
+ forwardRef,
3
+ useRef,
4
+ useMemo,
5
+ useCallback,
6
+ useEffect,
7
+ KeyboardEvent,
8
+ FocusEvent,
9
+ MutableRefObject,
10
+ ForwardedRef,
11
+ } from "react";
3
12
  import { createPortal } from "react-dom";
4
- import { string, number, bool, func, object, oneOf, oneOfType, exact } from "prop-types";
5
13
  import { MenuList } from "./MenuList";
6
14
  import { useBEM } from "../hooks";
7
15
  import {
8
- rootMenuPropTypes,
9
16
  menuContainerClass,
10
17
  mergeProps,
11
18
  safeCall,
12
19
  isMenuOpen,
13
20
  getTransition,
14
- values,
15
21
  CloseReason,
16
22
  Keys,
17
- MenuStateMap,
18
23
  EventHandlersContext,
19
24
  SettingsContext,
20
25
  ItemSettingsContext,
21
26
  } from "../utils";
22
27
  import { hasParentClass } from "@utils/util";
28
+ import { ControlledMenuProps, PortalFieldType, RadioChangeEvent } from "../types";
23
29
 
24
- export const ControlledMenu = forwardRef(function ControlledMenu(
30
+ export const ControlledMenuFr = (
25
31
  {
26
32
  "aria-label": ariaLabel,
27
33
  className,
@@ -43,11 +49,11 @@ export const ControlledMenu = forwardRef(function ControlledMenu(
43
49
  onClose,
44
50
  saveButtonRef,
45
51
  ...restProps
46
- }: any,
47
- externalRef,
48
- ) {
49
- const containerRef = useRef(null);
50
- const scrollNodesRef = useRef({});
52
+ }: ControlledMenuProps & { saveButtonRef?: MutableRefObject<HTMLButtonElement | null> },
53
+ externalRef: ForwardedRef<HTMLUListElement>,
54
+ ) => {
55
+ const containerRef = useRef<HTMLElement>();
56
+ const scrollNodesRef = useRef<{ anchors?: HTMLDivElement[] }>({});
51
57
  const { anchorRef, state } = restProps;
52
58
 
53
59
  const settings = useMemo(
@@ -91,7 +97,7 @@ export const ControlledMenu = forwardRef(function ControlledMenu(
91
97
  // the cell doesn't refresh during update if save is invoked from a native event
92
98
  // This doesn't happen in React18
93
99
  // To work around it, I invoke the save by clicking on a passed in invisible button ref
94
- if (saveButtonRef.current) saveButtonRef.current.click();
100
+ if (saveButtonRef?.current) saveButtonRef.current.click();
95
101
  else safeCall(onClose, { reason: CloseReason.BLUR });
96
102
 
97
103
  // If a user clicks on the menu button when a menu is open, we need to close the menu.
@@ -106,7 +112,7 @@ export const ControlledMenu = forwardRef(function ControlledMenu(
106
112
  }
107
113
  }
108
114
  },
109
- [clickIsWithinMenu, onClose],
115
+ [clickIsWithinMenu, onClose, saveButtonRef, skipOpen],
110
116
  );
111
117
 
112
118
  const handleScreenEventForCancel = useCallback(
@@ -121,7 +127,7 @@ export const ControlledMenu = forwardRef(function ControlledMenu(
121
127
 
122
128
  useEffect(() => {
123
129
  if (isMenuOpen(state)) {
124
- const thisDocument = anchorRef.current ? anchorRef.current.ownerDocument : document;
130
+ const thisDocument = anchorRef?.current ? anchorRef?.current.ownerDocument : document;
125
131
  thisDocument.addEventListener("mousedown", handleScreenEventForCancel, true);
126
132
  thisDocument.addEventListener("mouseup", handleScreenEventForSave, true);
127
133
  thisDocument.addEventListener("click", handleScreenEventForCancel, true);
@@ -134,7 +140,7 @@ export const ControlledMenu = forwardRef(function ControlledMenu(
134
140
  };
135
141
  }
136
142
  return () => {};
137
- }, [handleScreenEventForSave, handleScreenEventForCancel, state]);
143
+ }, [handleScreenEventForSave, handleScreenEventForCancel, state, anchorRef]);
138
144
 
139
145
  const itemSettings = useMemo(
140
146
  () => ({
@@ -146,7 +152,7 @@ export const ControlledMenu = forwardRef(function ControlledMenu(
146
152
 
147
153
  const eventHandlers = useMemo(
148
154
  () => ({
149
- handleClick(event, isCheckorRadio) {
155
+ handleClick(event: RadioChangeEvent, isCheckOrRadio: boolean) {
150
156
  if (!event.stopPropagation) safeCall(onItemClick, event);
151
157
 
152
158
  let keepOpen = event.keepOpen;
@@ -154,7 +160,7 @@ export const ControlledMenu = forwardRef(function ControlledMenu(
154
160
  // if event.keepOpen is undefined, the following default behaviour is used
155
161
  // According to WAI-ARIA Authoring Practices 1.1
156
162
  // Keep menu open when check or radio is invoked by SPACE key
157
- keepOpen = isCheckorRadio && event.key === Keys.SPACE;
163
+ keepOpen = isCheckOrRadio && event.key === Keys.SPACE;
158
164
  }
159
165
 
160
166
  if (!keepOpen) {
@@ -166,14 +172,14 @@ export const ControlledMenu = forwardRef(function ControlledMenu(
166
172
  }
167
173
  },
168
174
 
169
- handleClose(key) {
175
+ handleClose(key?: string) {
170
176
  safeCall(onClose, { key, reason: CloseReason.CLICK });
171
177
  },
172
178
  }),
173
179
  [onItemClick, onClose],
174
180
  );
175
181
 
176
- const onKeyDown = ({ key }) => {
182
+ const onKeyDown = ({ key }: KeyboardEvent) => {
177
183
  switch (key) {
178
184
  case Keys.ESC:
179
185
  safeCall(onClose, { key, reason: CloseReason.CANCEL });
@@ -181,14 +187,14 @@ export const ControlledMenu = forwardRef(function ControlledMenu(
181
187
  }
182
188
  };
183
189
 
184
- const onBlur = (e) => {
190
+ const onBlur = (e: FocusEvent) => {
185
191
  if (isMenuOpen(state) && !e.currentTarget.contains(e.relatedTarget || document.activeElement)) {
186
192
  safeCall(onClose, { reason: CloseReason.BLUR });
187
193
 
188
194
  // If a user clicks on the menu button when a menu is open, we need to close the menu.
189
195
  // However, a blur event will be fired prior to the click event on menu button,
190
196
  // which makes the menu first close and then open again.
191
- // If this happen, e.relatedTarget is incorrectly set to null instead of the button in Safari and Firefox,
197
+ // If this happens, e.relatedTarget is incorrectly set to null instead of the button in Safari and Firefox,
192
198
  // and makes it difficult to determine whether onBlur is fired because of clicking on menu button.
193
199
  // This is a workaround approach which sets a flag to skip a following click event.
194
200
  if (skipOpen) {
@@ -230,31 +236,20 @@ export const ControlledMenu = forwardRef(function ControlledMenu(
230
236
  </div>
231
237
  );
232
238
 
233
- if (portal === true && anchorRef.current !== undefined) {
234
- portal = { target: anchorRef.current.ownerDocument.body };
239
+ if (portal === true && anchorRef?.current !== undefined) {
240
+ portal = { target: anchorRef.current.ownerDocument.body } as PortalFieldType;
235
241
  }
236
242
 
237
- if (portal === true && typeof document !== "undefined") {
238
- return createPortal(menuList, document.body);
239
- } else if (portal) {
240
- return portal.target ? createPortal(menuList, portal.target) : portal.stablePosition ? null : menuList;
243
+ if (portal) {
244
+ if (typeof portal === "boolean") {
245
+ if (portal && typeof document !== "undefined") {
246
+ return createPortal(menuList, document.body);
247
+ }
248
+ } else {
249
+ return portal.target ? createPortal(menuList, portal.target) : portal.stablePosition ? null : menuList;
250
+ }
241
251
  }
242
252
  return menuList;
243
- });
244
-
245
- ControlledMenu.propTypes /* remove-proptypes */ = {
246
- ...rootMenuPropTypes,
247
- state: oneOf(values(MenuStateMap)),
248
- anchorPoint: exact({
249
- x: number,
250
- y: number,
251
- }),
252
- anchorRef: object,
253
- skipOpen: object,
254
- captureFocus: bool,
255
- menuItemFocus: exact({
256
- position: oneOfType([string, number]),
257
- alwaysUpdate: bool,
258
- }),
259
- onClose: func,
260
253
  };
254
+
255
+ export const ControlledMenu = forwardRef(ControlledMenuFr);
@@ -1,6 +1,4 @@
1
- // @ts-nocheck
2
- import { useContext, useMemo, useRef } from "react";
3
- import { bool, func } from "prop-types";
1
+ import { LegacyRef, useContext, useMemo, useRef } from "react";
4
2
  import { useBEM, useCombinedRef, useItemState } from "../hooks";
5
3
  import {
6
4
  mergeProps,
@@ -8,63 +6,70 @@ import {
8
6
  safeCall,
9
7
  menuClass,
10
8
  menuItemClass,
11
- stylePropTypes,
12
9
  withHovering,
13
10
  EventHandlersContext,
14
11
  } from "../utils";
12
+ import { BaseProps } from "../types";
13
+ import { withHoveringResultProps } from "../utils/withHovering";
15
14
 
16
- export const FocusableItem = withHovering(
17
- "FocusableItem",
18
- function FocusableItem({ className, disabled, children, isHovering, itemRef, externalRef, ...restProps }) {
19
- const isDisabled = !!disabled;
20
- const ref = useRef(null);
21
- const { setHover, onPointerLeave, ...restStateProps } = useItemState(itemRef, ref, isHovering, isDisabled);
22
- const { handleClose } = useContext(EventHandlersContext);
15
+ export interface FocusableItemProps extends BaseProps, withHoveringResultProps {
16
+ disabled?: boolean;
17
+ children: (ref: LegacyRef<any>) => JSX.Element;
18
+ }
23
19
 
24
- const modifiers = useMemo(
25
- () => ({
26
- disabled: isDisabled,
27
- hover: isHovering,
28
- focusable: true,
29
- }),
30
- [isDisabled, isHovering],
31
- );
20
+ export const FocusableItemFr = ({
21
+ className,
22
+ disabled,
23
+ children,
24
+ isHovering,
25
+ menuItemRef,
26
+ externalRef,
27
+ ...restProps
28
+ }: FocusableItemProps) => {
29
+ const isDisabled = !!disabled;
30
+ const ref = useRef(null);
31
+ const { setHover, onPointerLeave, ...restStateProps } = useItemState(menuItemRef, ref, isHovering, isDisabled);
32
+ const { handleClose } = useContext(EventHandlersContext);
32
33
 
33
- const renderChildren = useMemo(
34
- () =>
35
- safeCall(children, {
36
- ...modifiers,
37
- ref,
38
- closeMenu: handleClose,
39
- }),
40
- [children, modifiers, handleClose],
41
- );
34
+ const modifiers = useMemo(
35
+ () => ({
36
+ disabled: isDisabled,
37
+ hover: isHovering,
38
+ focusable: true,
39
+ }),
40
+ [isDisabled, isHovering],
41
+ );
42
42
 
43
- const mergedProps = mergeProps(
44
- {
45
- ...restStateProps,
46
- onPointerLeave: (e) => onPointerLeave(e, true),
47
- onFocus: setHover,
48
- },
49
- restProps,
50
- );
43
+ const renderChildren = useMemo(
44
+ () =>
45
+ safeCall(children, {
46
+ ...modifiers,
47
+ ref,
48
+ closeMenu: handleClose,
49
+ }),
50
+ [children, modifiers, handleClose],
51
+ );
51
52
 
52
- return (
53
- <li
54
- role="menuitem"
55
- {...mergedProps}
56
- {...commonProps(isDisabled)}
57
- ref={useCombinedRef(externalRef, itemRef)}
58
- className={useBEM({ block: menuClass, element: menuItemClass, modifiers, className })}
59
- >
60
- {renderChildren}
61
- </li>
62
- );
63
- },
64
- );
53
+ const mergedProps = mergeProps(
54
+ {
55
+ ...restStateProps,
56
+ onPointerLeave: (e: PointerEvent) => onPointerLeave(e, true),
57
+ onFocus: setHover,
58
+ },
59
+ restProps,
60
+ );
65
61
 
66
- FocusableItem.propTypes = {
67
- ...stylePropTypes(),
68
- disabled: bool,
69
- children: func,
62
+ return (
63
+ <li
64
+ role="menuitem"
65
+ {...mergedProps}
66
+ {...commonProps(isDisabled)}
67
+ ref={useCombinedRef(externalRef, menuItemRef)}
68
+ className={useBEM({ block: menuClass, element: menuItemClass, modifiers, className })}
69
+ >
70
+ {renderChildren}
71
+ </li>
72
+ );
70
73
  };
74
+
75
+ export const FocusableItem = withHovering("FocusableItem", FocusableItemFr);