@linzjs/step-ag-grid 1.4.5 → 1.4.6

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 (72) hide show
  1. package/dist/index.js +195 -163
  2. package/dist/index.js.map +1 -1
  3. package/dist/src/react-menu3/components/FocusableItem.d.ts +9 -1
  4. package/dist/src/react-menu3/components/Menu.d.ts +16 -2
  5. package/dist/src/react-menu3/components/MenuButton.d.ts +8 -1
  6. package/dist/src/react-menu3/components/MenuDivider.d.ts +3 -2
  7. package/dist/src/react-menu3/components/MenuGroup.d.ts +12 -2
  8. package/dist/src/react-menu3/components/MenuHeader.d.ts +4 -2
  9. package/dist/src/react-menu3/components/MenuItem.d.ts +59 -1
  10. package/dist/src/react-menu3/components/MenuList.d.ts +57 -30
  11. package/dist/src/react-menu3/components/MenuRadioGroup.d.ts +44 -2
  12. package/dist/src/react-menu3/components/SubMenu.d.ts +110 -1
  13. package/dist/src/react-menu3/hooks/useBEM.d.ts +4 -3
  14. package/dist/src/react-menu3/hooks/useCombinedRef.d.ts +2 -2
  15. package/dist/src/react-menu3/hooks/useItemEffect.d.ts +1 -1
  16. package/dist/src/react-menu3/hooks/useItemState.d.ts +4 -3
  17. package/dist/src/react-menu3/hooks/useItems.d.ts +6 -4
  18. package/dist/src/react-menu3/hooks/useMenuChange.d.ts +2 -1
  19. package/dist/src/react-menu3/hooks/useMenuState.d.ts +13 -10
  20. package/dist/src/react-menu3/hooks/useMenuStateAndFocus.d.ts +2 -10
  21. package/dist/src/react-menu3/index.d.ts +391 -0
  22. package/dist/src/react-menu3/positionUtils/getPositionHelpers.d.ts +10 -9
  23. package/dist/src/react-menu3/positionUtils/placeArrowHorizontal.d.ts +7 -6
  24. package/dist/src/react-menu3/positionUtils/placeArrowVertical.d.ts +7 -6
  25. package/dist/src/react-menu3/positionUtils/placeLeftorRight.d.ts +17 -19
  26. package/dist/src/react-menu3/positionUtils/placeToporBottom.d.ts +18 -20
  27. package/dist/src/react-menu3/positionUtils/positionContextMenu.d.ts +11 -6
  28. package/dist/src/react-menu3/positionUtils/positionMenu.d.ts +23 -18
  29. package/dist/src/react-menu3/utils/constants.d.ts +51 -9
  30. package/dist/src/react-menu3/utils/propTypes.d.ts +1 -0
  31. package/dist/src/react-menu3/utils/utils.d.ts +19 -10
  32. package/dist/src/react-menu3/utils/withHovering.d.ts +7 -1
  33. package/dist/src/stories/components/ReactMenu.stories.d.ts +8 -0
  34. package/dist/step-ag-grid.esm.js +197 -165
  35. package/dist/step-ag-grid.esm.js.map +1 -1
  36. package/package.json +11 -11
  37. package/src/components/gridForm/GridFormDropDown.tsx +1 -1
  38. package/src/components/gridForm/GridFormMultiSelect.tsx +10 -4
  39. package/src/react-menu3/components/ControlledMenu.tsx +2 -1
  40. package/src/react-menu3/components/FocusableItem.tsx +58 -53
  41. package/src/react-menu3/components/Menu.tsx +40 -28
  42. package/src/react-menu3/components/MenuButton.tsx +30 -29
  43. package/src/react-menu3/components/MenuDivider.tsx +14 -18
  44. package/src/react-menu3/components/MenuGroup.tsx +25 -16
  45. package/src/react-menu3/components/MenuHeader.tsx +14 -18
  46. package/src/react-menu3/components/MenuItem.tsx +159 -106
  47. package/src/react-menu3/components/MenuList.tsx +104 -36
  48. package/src/react-menu3/components/MenuRadioGroup.tsx +54 -15
  49. package/src/react-menu3/components/SubMenu.tsx +307 -201
  50. package/src/react-menu3/hooks/useBEM.ts +4 -3
  51. package/src/react-menu3/hooks/useCombinedRef.ts +6 -12
  52. package/src/react-menu3/hooks/useItemEffect.ts +6 -5
  53. package/src/react-menu3/hooks/useItemState.ts +16 -12
  54. package/src/react-menu3/hooks/useItems.ts +11 -10
  55. package/src/react-menu3/hooks/useMenuChange.ts +3 -3
  56. package/src/react-menu3/hooks/useMenuState.ts +25 -7
  57. package/src/react-menu3/hooks/useMenuStateAndFocus.ts +6 -4
  58. package/src/react-menu3/index.d.ts +1 -0
  59. package/src/react-menu3/index.ts +431 -0
  60. package/src/react-menu3/positionUtils/getPositionHelpers.ts +18 -11
  61. package/src/react-menu3/positionUtils/placeArrowHorizontal.ts +12 -5
  62. package/src/react-menu3/positionUtils/placeArrowVertical.ts +12 -5
  63. package/src/react-menu3/positionUtils/placeLeftorRight.ts +33 -17
  64. package/src/react-menu3/positionUtils/placeToporBottom.ts +34 -18
  65. package/src/react-menu3/positionUtils/positionContextMenu.ts +15 -3
  66. package/src/react-menu3/positionUtils/positionMenu.ts +21 -14
  67. package/src/react-menu3/style-utils/index.ts +10 -7
  68. package/src/react-menu3/utils/constants.ts +63 -10
  69. package/src/react-menu3/utils/propTypes.ts +3 -1
  70. package/src/react-menu3/utils/utils.ts +40 -23
  71. package/src/react-menu3/utils/withHovering.tsx +11 -6
  72. package/src/stories/components/ReactMenu.stories.tsx +37 -0
@@ -1,130 +1,183 @@
1
- // @ts-nocheck
2
- import { useContext, useMemo } from "react";
3
- import { any, string, bool, func, node, oneOf, oneOfType } from "prop-types";
1
+ import { Ref, useContext, useMemo } from "react";
4
2
  import { useBEM, useItemState, useCombinedRef } from "../hooks";
5
3
  import {
6
4
  mergeProps,
7
5
  commonProps,
8
6
  safeCall,
9
- stylePropTypes,
10
7
  menuClass,
11
8
  menuItemClass,
12
9
  withHovering,
13
10
  EventHandlersContext,
14
11
  RadioGroupContext,
15
12
  Keys,
13
+ RMEvent,
16
14
  } from "../utils";
15
+ import { BaseProps, ClickEvent, EventHandler, Hoverable, MenuItemTypeProp, RenderProp } from "../index";
16
+ import { withHoveringResultProps } from "../utils/withHovering";
17
17
 
18
- export const MenuItem = withHovering(
19
- "MenuItem",
20
- function MenuItem({
21
- className,
22
- value,
23
- href,
24
- type,
25
- checked,
26
- disabled,
27
- children,
28
- onClick,
29
- isHovering,
30
- itemRef,
31
- externalRef,
32
- ...restProps
33
- }) {
34
- const isDisabled = !!disabled;
35
- const { setHover, ...restStateProps } = useItemState(itemRef, itemRef, isHovering, isDisabled);
36
- const eventHandlers = useContext(EventHandlersContext);
37
- const radioGroup = useContext(RadioGroupContext);
38
- const isRadio = type === "radio";
39
- const isCheckBox = type === "checkbox";
40
- const isAnchor = !!href && !isDisabled && !isRadio && !isCheckBox;
41
- const isChecked = isRadio ? radioGroup.value === value : isCheckBox ? !!checked : false;
18
+ //
19
+ // MenuItem
20
+ // ----------------------------------------------------------------------
21
+ export type MenuItemModifiers = Readonly<{
22
+ /**
23
+ * 'radio' for radio item, 'checkbox' for checkbox item, or `undefined` for other items.
24
+ */
25
+ type?: MenuItemTypeProp;
26
+ /**
27
+ * Indicates if the menu item is disabled.
28
+ */
29
+ disabled: boolean;
30
+ /**
31
+ * Indicates if the menu item is being hovered and has focus.
32
+ */
33
+ hover: boolean;
34
+ /**
35
+ * Indicates if the menu item is checked when it's a radio or checkbox item.
36
+ */
37
+ checked: boolean;
38
+ /**
39
+ * Indicates if the menu item has a URL link.
40
+ */
41
+ anchor: boolean;
42
+ }>;
42
43
 
43
- const handleClick = (e) => {
44
- if (isDisabled) {
45
- e.stopPropagation();
46
- e.preventDefault();
47
- return;
48
- }
44
+ export interface MenuItemProps extends Omit<BaseProps<MenuItemModifiers>, "onClick">, Hoverable {
45
+ /**
46
+ * Any value provided to this prop will be available in the event object of click events.
47
+ *
48
+ * It's useful for helping identify which menu item is clicked when you
49
+ * listen on `onItemClick` event on root menu component.
50
+ */
51
+ value?: any;
52
+ /**
53
+ * If provided, menu item renders an HTML `<a>` element with this `href` attribute.
54
+ */
55
+ href?: string;
56
+ rel?: string;
57
+ target?: string;
58
+ /**
59
+ * Set this prop to make the item a checkbox or radio menu item.
60
+ */
61
+ type?: MenuItemTypeProp;
62
+ /**
63
+ * Set `true` if a checkbox menu item is checked.
64
+ *
65
+ * *Please note radio menu item doesn't use this prop.*
66
+ */
67
+ checked?: boolean;
68
+ /**
69
+ * Event fired when the menu item is clicked.
70
+ */
71
+ onClick?: EventHandler<ClickEvent>;
72
+ /**
73
+ * Any valid React node or a render function that returns one.
74
+ */
75
+ children?: RenderProp<MenuItemModifiers>;
76
+ }
49
77
 
50
- const event = { value, syntheticEvent: e };
51
- if (e.key !== undefined) event.key = e.key;
52
- if (isCheckBox) event.checked = !isChecked;
53
- if (isRadio) event.name = radioGroup.name;
54
- safeCall(onClick, event);
55
- if (isRadio) safeCall(radioGroup.onRadioChange, event);
56
- eventHandlers.handleClick(event, isCheckBox || isRadio);
57
- };
78
+ const MenuItemFr = ({
79
+ className,
80
+ value,
81
+ href,
82
+ type,
83
+ checked,
84
+ disabled,
85
+ children,
86
+ onClick,
87
+ isHovering,
88
+ menuItemRef,
89
+ externalRef,
90
+ ...restProps
91
+ }: MenuItemProps & withHoveringResultProps) => {
92
+ const isDisabled = !!disabled;
93
+ const { setHover, ...restStateProps } = useItemState(menuItemRef, menuItemRef, isHovering, isDisabled);
94
+ const eventHandlers = useContext(EventHandlersContext);
95
+ const radioGroup = useContext(RadioGroupContext);
96
+ const isRadio = type === "radio";
97
+ const isCheckBox = type === "checkbox";
98
+ const isAnchor = !!href && !isDisabled && !isRadio && !isCheckBox;
99
+ const isChecked = isRadio ? radioGroup.value === value : isCheckBox ? !!checked : false;
58
100
 
59
- const handleKeyDown = (e) => {
60
- if (!isHovering) return;
101
+ // FIXME handle click seems to be a combination of multiple event types
102
+ const handleClick = (e: any) => {
103
+ if (isDisabled) {
104
+ e.stopPropagation();
105
+ e.preventDefault();
106
+ return;
107
+ }
61
108
 
62
- switch (e.key) {
63
- case Keys.ENTER:
64
- case Keys.SPACE:
65
- if (isAnchor) {
66
- itemRef.current.click();
67
- } else {
68
- handleClick(e);
69
- }
70
- break;
71
- }
109
+ const event: RMEvent = {
110
+ value,
111
+ syntheticEvent: e,
72
112
  };
113
+ if (e.key !== undefined) event.key = e.key;
114
+ if (isCheckBox) event.checked = !isChecked;
115
+ if (isRadio) event.name = radioGroup.name;
116
+ safeCall(onClick, event);
117
+ if (isRadio) safeCall(radioGroup.onRadioChange, event);
118
+ eventHandlers.handleClick(event, isCheckBox || isRadio);
119
+ };
73
120
 
74
- const modifiers = useMemo(
75
- () => ({
76
- type,
77
- disabled: isDisabled,
78
- hover: isHovering,
79
- checked: isChecked,
80
- anchor: isAnchor,
81
- }),
82
- [type, isDisabled, isHovering, isChecked, isAnchor],
83
- );
121
+ const handleKeyDown = (e: KeyboardEvent) => {
122
+ if (!isHovering) return;
84
123
 
85
- const mergedProps = mergeProps(
86
- {
87
- ...restStateProps,
88
- onPointerDown: setHover,
89
- onKeyDown: handleKeyDown,
90
- onClick: handleClick,
91
- },
92
- restProps,
93
- );
124
+ switch (e.key) {
125
+ case Keys.ENTER:
126
+ case Keys.SPACE:
127
+ if (isAnchor) {
128
+ menuItemRef?.current && menuItemRef.current.click();
129
+ } else {
130
+ handleClick(e);
131
+ }
132
+ break;
133
+ }
134
+ };
94
135
 
95
- // Order of props overriding (same in all components):
96
- // 1. Preset props adhering to WAI-ARIA Authoring Practices.
97
- // 2. Merged outer and local props
98
- // 3. ref, className
99
- const menuItemProps = {
100
- role: isRadio ? "menuitemradio" : isCheckBox ? "menuitemcheckbox" : "menuitem",
101
- "aria-checked": isRadio || isCheckBox ? isChecked : undefined,
102
- ...mergedProps,
103
- ...commonProps(isDisabled, isHovering),
104
- ref: useCombinedRef(externalRef, itemRef),
105
- className: useBEM({ block: menuClass, element: menuItemClass, modifiers, className }),
106
- children: useMemo(() => safeCall(children, modifiers), [children, modifiers]),
107
- };
136
+ const modifiers = useMemo(
137
+ () => ({
138
+ type,
139
+ disabled: isDisabled,
140
+ hover: isHovering,
141
+ checked: isChecked,
142
+ anchor: isAnchor,
143
+ }),
144
+ [type, isDisabled, isHovering, isChecked, isAnchor],
145
+ );
108
146
 
109
- if (isAnchor) {
110
- return (
111
- <li role="presentation">
112
- <a href={href} {...menuItemProps} />
113
- </li>
114
- );
115
- } else {
116
- return <li {...menuItemProps} />;
117
- }
118
- },
119
- );
147
+ const mergedProps = mergeProps(
148
+ {
149
+ ...restStateProps,
150
+ onPointerDown: setHover,
151
+ onKeyDown: handleKeyDown,
152
+ onClick: handleClick,
153
+ },
154
+ restProps,
155
+ );
156
+
157
+ // Order of props overriding (same in all components):
158
+ // 1. Preset props adhering to WAI-ARIA Authoring Practices.
159
+ // 2. Merged outer and local props
160
+ // 3. ref, className
161
+ const menuItemProps = {
162
+ role: isRadio ? "menuitemradio" : isCheckBox ? "menuitemcheckbox" : "menuitem",
163
+ "aria-checked": isRadio || isCheckBox ? isChecked : undefined,
164
+ ...mergedProps,
165
+ ...commonProps(isDisabled, isHovering),
166
+ ref: useCombinedRef(externalRef as Ref<any>, menuItemRef),
167
+ className: useBEM({ block: menuClass, element: menuItemClass, modifiers, className }),
168
+ children: useMemo(() => safeCall(children, modifiers), [children, modifiers]),
169
+ };
120
170
 
121
- MenuItem.propTypes = {
122
- ...stylePropTypes(),
123
- value: any,
124
- href: string,
125
- type: oneOf(["checkbox", "radio"]),
126
- checked: bool,
127
- disabled: bool,
128
- children: oneOfType([node, func]),
129
- onClick: func,
171
+ if (isAnchor) {
172
+ return (
173
+ <li role="presentation">
174
+ <a href={href} {...menuItemProps} />
175
+ </li>
176
+ );
177
+ } else {
178
+ return <li {...menuItemProps} />;
179
+ }
130
180
  };
181
+
182
+ // FIXME matt as any
183
+ export const MenuItem = withHovering("MenuItem", MenuItemFr) as any as typeof MenuItemFr;
@@ -1,5 +1,4 @@
1
- // @ts-nocheck
2
- import { useState, useReducer, useEffect, useRef, useMemo, useCallback, useContext } from "react";
1
+ import { useState, useReducer, useEffect, useRef, useMemo, useCallback, useContext, MutableRefObject } from "react";
3
2
  import { flushSync } from "react-dom";
4
3
  import { useBEM, useCombinedRef, useLayoutEffect, useItems } from "../hooks";
5
4
  import { getPositionHelpers, positionMenu, positionContextMenu } from "../positionUtils";
@@ -23,6 +22,65 @@ import {
23
22
  MenuListItemContext,
24
23
  HoverItemContext,
25
24
  } from "../utils";
25
+ import { EventHandler, FocusPosition, MenuCloseEvent, MenuDirection, MenuState, RootMenuProps } from "../index";
26
+
27
+ interface ExtraMenuProps {
28
+ isDisabled?: boolean;
29
+ ariaLabel?: string;
30
+ containerRef: MutableRefObject<HTMLElement>;
31
+ externalRef: MutableRefObject<HTMLUListElement>;
32
+ parentScrollingRef: MutableRefObject<any>;
33
+ }
34
+
35
+ //
36
+ // ControlledMenu
37
+ // ----------------------------------------------------------------------
38
+ export interface ControlledMenuProps extends RootMenuProps, ExtraMenuProps {
39
+ /**
40
+ * Viewport coordinates to which context menu will be positioned.
41
+ *
42
+ * *Use this prop only for context menu*
43
+ */
44
+ anchorPoint?: {
45
+ x: number;
46
+ y: number;
47
+ };
48
+ /**
49
+ * A ref object attached to a DOM element to which menu will be positioned.
50
+ *
51
+ * *Don't set this prop for context menu*
52
+ */
53
+ anchorRef?: React.MutableRefObject<HTMLElement>;
54
+ skipOpen?: React.RefObject<boolean>;
55
+ /**
56
+ * If `true`, the menu list element will gain focus after menu is open.
57
+ * @default true
58
+ */
59
+ captureFocus?: boolean;
60
+ /**
61
+ * Controls the state of menu. When the prop is `undefined`, menu will be unmounted from DOM.
62
+ */
63
+ state?: MenuState;
64
+ /**
65
+ * Sets which menu item receives focus (hover) when menu opens.
66
+ * You will usually set this prop when the menu is opened by keyboard events.
67
+ *
68
+ * *Note: If you don't intend to update focus (hover) position,
69
+ * it's important to keep this prop's identity stable when your component re-renders.*
70
+ */
71
+ menuItemFocus?: {
72
+ position?: FocusPosition;
73
+ alwaysUpdate?: boolean;
74
+ };
75
+ /**
76
+ * Set the return value of `useMenuState` to this prop.
77
+ */
78
+ endTransition?: () => void;
79
+ /**
80
+ * Event fired when menu is about to close.
81
+ */
82
+ onClose?: EventHandler<MenuCloseEvent>;
83
+ }
26
84
 
27
85
  export const MenuList = ({
28
86
  ariaLabel,
@@ -52,10 +110,10 @@ export const MenuList = ({
52
110
  children,
53
111
  onClose,
54
112
  ...restProps
55
- }) => {
113
+ }: ControlledMenuProps) => {
56
114
  const [menuPosition, setMenuPosition] = useState({ x: 0, y: 0 });
57
- const [arrowPosition, setArrowPosition] = useState({});
58
- const [overflowData, setOverflowData] = useState();
115
+ const [arrowPosition, setArrowPosition] = useState({ x: 0, y: 0 });
116
+ const [overflowData, setOverflowData] = useState<{ height: number; overflowAmt: number | undefined }>();
59
117
  const [expandedDirection, setExpandedDirection] = useState(direction);
60
118
  const [openSubmenuCount, setOpenSubmenuCount] = useState(0);
61
119
  const [reposSubmenu, forceReposSubmenu] = useReducer((c) => c + 1, 1);
@@ -70,9 +128,9 @@ export const MenuList = ({
70
128
  viewScroll,
71
129
  } = useContext(SettingsContext);
72
130
  const reposFlag = useContext(MenuListContext).reposSubmenu || repositionFlag;
73
- const menuRef = useRef(null);
74
- const focusRef = useRef();
75
- const arrowRef = useRef();
131
+ const menuRef = useRef<HTMLUListElement>({} as HTMLUListElement);
132
+ const focusRef = useRef<HTMLDivElement>(null);
133
+ const arrowRef = useRef<HTMLDivElement>(null);
76
134
  const prevOpen = useRef(false);
77
135
  const latestMenuSize = useRef({ width: 0, height: 0 });
78
136
  const latestHandlePosition = useRef(() => {});
@@ -83,34 +141,37 @@ export const MenuList = ({
83
141
  const closeTransition = getTransition(transition, "close");
84
142
  const scrollNodes = scrollNodesRef.current;
85
143
 
86
- const onKeyDown = (e) => {
144
+ const onKeyDown = (e: React.KeyboardEvent<HTMLElement>) => {
145
+ const elementTarget = e.target instanceof HTMLElement ? (e.target as HTMLElement) : null;
87
146
  const isTextInputTarget =
88
- e.target.nodeName === "TEXTAREA" || (e.target.nodeName === "INPUT" && e.target.getAttribute("type") === "text");
147
+ elementTarget &&
148
+ (elementTarget.nodeName === "TEXTAREA" ||
149
+ (elementTarget.nodeName === "INPUT" && elementTarget.getAttribute("type") === "text"));
89
150
  switch (e.key) {
90
151
  case Keys.HOME:
91
152
  // Don't eat home/end events on inputs
92
153
  if (isTextInputTarget) return;
93
- dispatch(HoverActionTypes.FIRST);
154
+ dispatch(HoverActionTypes.FIRST, null, 0);
94
155
  break;
95
156
 
96
157
  case Keys.END:
97
158
  // Don't eat home/end events on inputs
98
159
  if (isTextInputTarget) return;
99
- dispatch(HoverActionTypes.LAST);
160
+ dispatch(HoverActionTypes.LAST, null, 0);
100
161
  break;
101
162
 
102
163
  case Keys.UP:
103
- dispatch(HoverActionTypes.DECREASE, hoverItem);
164
+ dispatch(HoverActionTypes.DECREASE, hoverItem, 0);
104
165
  break;
105
166
 
106
167
  case Keys.DOWN:
107
- dispatch(HoverActionTypes.INCREASE, hoverItem);
168
+ dispatch(HoverActionTypes.INCREASE, hoverItem, 0);
108
169
  break;
109
170
 
110
171
  // prevent browser from scrolling the page when SPACE is pressed
111
172
  case Keys.SPACE:
112
173
  // Don't preventDefault on children of FocusableItem
113
- if (e.target && e.target.className.indexOf(menuClass) !== -1) {
174
+ if (elementTarget && elementTarget.className.includes(menuClass)) {
114
175
  e.preventDefault();
115
176
  }
116
177
  return;
@@ -125,14 +186,14 @@ export const MenuList = ({
125
186
 
126
187
  const onAnimationEnd = () => {
127
188
  if (state === "closing") {
128
- setOverflowData(); // reset overflowData after closing
189
+ setOverflowData(undefined); // reset overflowData after closing
129
190
  }
130
191
 
131
- safeCall(endTransition);
192
+ endTransition && safeCall(endTransition);
132
193
  };
133
194
 
134
195
  const handlePosition = useCallback(
135
- (noOverflowCheck) => {
196
+ (noOverflowCheck?: boolean) => {
136
197
  if (!containerRef.current) {
137
198
  if (process.env.NODE_ENV !== "production") {
138
199
  console.error(
@@ -146,12 +207,16 @@ export const MenuList = ({
146
207
  scrollNodes.menu =
147
208
  (boundingBoxRef
148
209
  ? boundingBoxRef.current // user explicitly sets boundingBoxRef
149
- : getScrollAncestor(rootMenuRef.current)) || window; // try to discover bounding box automatically
210
+ : getScrollAncestor(rootMenuRef?.current)) || window; // try to discover bounding box automatically
150
211
  }
151
212
 
152
213
  const positionHelpers = getPositionHelpers(containerRef, menuRef, scrollNodes.menu, boundingBoxPadding);
153
214
  const { menuRect } = positionHelpers;
154
- let results = { computedDirection: "bottom" };
215
+ let results: { computedDirection: MenuDirection; arrowX?: number; arrowY?: number; x: number; y: number } = {
216
+ computedDirection: "bottom",
217
+ x: 0,
218
+ y: 0,
219
+ };
155
220
  if (anchorPoint) {
156
221
  results = positionContextMenu({ positionHelpers, anchorPoint });
157
222
  } else if (anchorRef) {
@@ -167,13 +232,14 @@ export const MenuList = ({
167
232
  positionHelpers,
168
233
  });
169
234
  }
170
- let { arrowX, arrowY, x, y, computedDirection } = results;
235
+ let { y } = results;
236
+ const { x, arrowX, arrowY, computedDirection } = results;
171
237
  let menuHeight = menuRect.height;
172
238
 
173
239
  if (!noOverflowCheck && overflow !== "visible") {
174
240
  const { getTopOverflow, getBottomOverflow } = positionHelpers;
175
241
 
176
- let height, overflowAmt;
242
+ let height: number | undefined, overflowAmt: number | undefined;
177
243
  const prevHeight = latestMenuSize.current.height;
178
244
  const bottomOverflow = getBottomOverflow(y);
179
245
  // When bottomOverflow is 0, menu is on the bottom edge of viewport
@@ -192,16 +258,16 @@ export const MenuList = ({
192
258
  }
193
259
  }
194
260
 
195
- if (height >= 0) {
261
+ if (height != null && height >= 0) {
196
262
  // To avoid triggering reposition in the next ResizeObserver callback
197
263
  menuHeight = height;
198
264
  setOverflowData({ height, overflowAmt });
199
265
  } else {
200
- setOverflowData();
266
+ setOverflowData(undefined);
201
267
  }
202
268
  }
203
269
 
204
- if (arrow) setArrowPosition({ x: arrowX, y: arrowY });
270
+ if (arrow) setArrowPosition({ x: arrowX ?? 0, y: arrowY ?? 0 });
205
271
  setMenuPosition({ x, y });
206
272
  setExpandedDirection(computedDirection);
207
273
  latestMenuSize.current = { width: menuRect.width, height: menuHeight };
@@ -267,11 +333,11 @@ export const MenuList = ({
267
333
  };
268
334
 
269
335
  const scrollObservers = scrollNodes.anchors.concat(viewScroll !== "initial" ? menuScroll : []);
270
- scrollObservers.forEach((o) => o.addEventListener("scroll", handleScroll));
336
+ scrollObservers.forEach((o: any) => o.addEventListener("scroll", handleScroll));
271
337
  return () => scrollObservers.forEach((o) => o.removeEventListener("scroll", handleScroll));
272
338
  }, [rootAnchorRef, scrollNodes, isOpen, onClose, viewScroll, handlePosition]);
273
339
 
274
- const hasOverflow = !!overflowData && overflowData.overflowAmt > 0;
340
+ const hasOverflow = !!overflowData && overflowData.overflowAmt != null && overflowData.overflowAmt > 0;
275
341
  useEffect(() => {
276
342
  if (hasOverflow || !isOpen || !parentScrollingRef) return;
277
343
 
@@ -313,18 +379,18 @@ export const MenuList = ({
313
379
 
314
380
  useEffect(() => {
315
381
  if (!isOpen) {
316
- dispatch(HoverActionTypes.RESET);
317
- if (!closeTransition) setOverflowData();
318
- return;
382
+ dispatch(HoverActionTypes.RESET, undefined, 0);
383
+ if (!closeTransition) setOverflowData(undefined);
384
+ return () => {};
319
385
  }
320
386
 
321
387
  const { position, alwaysUpdate } = menuItemFocus || {};
322
388
  const setItemFocus = () => {
323
389
  if (position === FocusPositions.FIRST) {
324
- dispatch(HoverActionTypes.FIRST);
390
+ dispatch(HoverActionTypes.FIRST, undefined, 0);
325
391
  } else if (position === FocusPositions.LAST) {
326
- dispatch(HoverActionTypes.LAST);
327
- } else if (position >= -1) {
392
+ dispatch(HoverActionTypes.LAST, undefined, 0);
393
+ } else if (typeof position === "number" && position >= -1) {
328
394
  dispatch(HoverActionTypes.SET_INDEX, undefined, position);
329
395
  }
330
396
  };
@@ -337,7 +403,7 @@ export const MenuList = ({
337
403
  () => {
338
404
  // If focus has already been set to a children element, don't set focus on menu or item
339
405
  if (!menuRef.current.contains(document.activeElement)) {
340
- focusRef.current.focus();
406
+ focusRef.current?.focus();
341
407
  setItemFocus();
342
408
  }
343
409
  },
@@ -346,6 +412,7 @@ export const MenuList = ({
346
412
 
347
413
  return () => clearTimeout(id);
348
414
  }
415
+ return () => {};
349
416
  }, [isOpen, openTransition, closeTransition, captureFocus, menuItemFocus, dispatch]);
350
417
 
351
418
  const isSubmenuOpen = openSubmenuCount > 0;
@@ -360,7 +427,8 @@ export const MenuList = ({
360
427
  [isOpen, isSubmenuOpen, dispatch, updateItems],
361
428
  );
362
429
 
363
- let maxHeight, overflowAmt;
430
+ let maxHeight: number | undefined;
431
+ let overflowAmt: number | undefined;
364
432
  if (overflowData) {
365
433
  setDownOverflow ? (overflowAmt = overflowData.overflowAmt) : (maxHeight = overflowData.height);
366
434
  }
@@ -375,7 +443,7 @@ export const MenuList = ({
375
443
  }),
376
444
  [reposSubmenu, overflow, overflowAmt, expandedDirection],
377
445
  );
378
- const overflowStyle = maxHeight >= 0 ? { maxHeight, overflow } : undefined;
446
+ const overflowStyle = maxHeight != null && maxHeight >= 0 ? { maxHeight, overflow } : undefined;
379
447
 
380
448
  const modifiers = useMemo(
381
449
  () => ({
@@ -1,13 +1,57 @@
1
- // @ts-nocheck
2
- import { forwardRef, useMemo } from "react";
3
- import { any, string, func } from "prop-types";
1
+ import { ForwardedRef, forwardRef, ReactNode, useMemo } from "react";
4
2
  import { useBEM } from "../hooks";
5
- import { stylePropTypes, menuClass, radioGroupClass, RadioGroupContext } from "../utils";
3
+ import { menuClass, radioGroupClass, RadioGroupContext } from "../utils";
4
+ import { BaseProps, Event, EventHandler } from "../index";
6
5
 
7
- export const MenuRadioGroup = forwardRef(function MenuRadioGroup(
8
- { "aria-label": ariaLabel, className, name, value, onRadioChange, ...restProps },
9
- externalRef,
10
- ) {
6
+ export interface RadioChangeEvent extends Event {
7
+ /**
8
+ * The `name` prop passed to the `MenuRadioGroup` when the menu item is in a radio group.
9
+ */
10
+ name?: string;
11
+ /**
12
+ * Set this property on event object to control whether to keep menu open after menu item is activated.
13
+ * Leaving it `undefined` will behave in accordance with WAI-ARIA Authoring Practices.
14
+ */
15
+ keepOpen?: boolean;
16
+ /**
17
+ * Setting this property on event object to `true` will skip `onItemClick` event on root menu component.
18
+ */
19
+ stopPropagation?: boolean;
20
+ /**
21
+ * DOM event object (React synthetic event)
22
+ */
23
+ syntheticEvent: MouseEvent | KeyboardEvent;
24
+ }
25
+
26
+ //
27
+ // MenuRadioGroup
28
+ // ----------------------------------------------------------------------
29
+ export interface MenuRadioGroupProps extends BaseProps {
30
+ /**
31
+ * Optionally set the radio group name.
32
+ *
33
+ * The name will be passed to the `onRadioChange` event.
34
+ * It's useful for identifying radio groups if you attach the same event handler to multiple groups.
35
+ */
36
+ name?: string;
37
+ /**
38
+ * Set value of the radio group.
39
+ *
40
+ * The child menu item which has the same value (strict equality ===) as the
41
+ * radio group is marked as checked.
42
+ */
43
+ value?: any;
44
+ children?: ReactNode;
45
+ /**
46
+ * Event fired when a child menu item is clicked (selected).
47
+ */
48
+ onRadioChange?: EventHandler<RadioChangeEvent>;
49
+ }
50
+
51
+ export const MenuRadioGroupFr = (
52
+ { "aria-label": ariaLabel, className, name, value, onRadioChange, ...restProps }: MenuRadioGroupProps,
53
+ externalRef: ForwardedRef<HTMLUListElement>,
54
+ ) => {
11
55
  const contextValue = useMemo(() => ({ name, value, onRadioChange }), [name, value, onRadioChange]);
12
56
 
13
57
  return (
@@ -23,11 +67,6 @@ export const MenuRadioGroup = forwardRef(function MenuRadioGroup(
23
67
  </li>
24
68
  </RadioGroupContext.Provider>
25
69
  );
26
- });
27
-
28
- MenuRadioGroup.propTypes = {
29
- ...stylePropTypes(),
30
- name: string,
31
- value: any,
32
- onRadioChange: func,
33
70
  };
71
+
72
+ export const MenuRadioGroup = forwardRef(MenuRadioGroupFr) as any as typeof MenuRadioGroupFr;