@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
@@ -1,43 +1,58 @@
1
- // @ts-nocheck
2
- import { cloneElement, Fragment, forwardRef, useRef, useCallback, useImperativeHandle } from "react";
3
- import { element, func, oneOfType } from "prop-types";
1
+ import {
2
+ cloneElement,
3
+ Fragment,
4
+ forwardRef,
5
+ useRef,
6
+ useCallback,
7
+ useImperativeHandle,
8
+ ReactElement,
9
+ ForwardedRef,
10
+ } from "react";
4
11
  import { ControlledMenu } from "./ControlledMenu";
5
12
  import { useMenuChange, useMenuStateAndFocus, useCombinedRef } from "../hooks";
6
- import {
7
- getName,
8
- mergeProps,
9
- safeCall,
10
- isMenuOpen,
11
- uncontrolledMenuPropTypes,
12
- rootMenuPropTypes,
13
- Keys,
14
- FocusPositions,
15
- } from "../utils";
13
+ import { getName, mergeProps, safeCall, isMenuOpen, Keys, FocusPositions } from "../utils";
14
+ import { MenuButtonModifiers, RenderProp, RootMenuProps, UncontrolledMenuProps } from "../types";
16
15
 
17
- export const Menu = forwardRef(function Menu(
18
- { "aria-label": ariaLabel, captureFocus: _, menuButton, instanceRef, onMenuChange, ...restProps },
19
- externalRef,
16
+ //
17
+ // Menu
18
+ // ----------------------------------------------------------------------
19
+ export interface MenuProps extends RootMenuProps, UncontrolledMenuProps {
20
+ /**
21
+ * Can be a `MenuButton`, a `button` element, or a React component.
22
+ * It also can be a render function that returns one.
23
+ *
24
+ * If a React component is provided, it needs to implement the following contracts:
25
+ * - Accepts a `ref` prop that is forwarded to an element to which menu will be positioned.
26
+ * The element should be able to receive focus.
27
+ * - Accepts `onClick` and `onKeyDown` event props.
28
+ */
29
+ menuButton: RenderProp<MenuButtonModifiers, ReactElement>;
30
+ }
31
+
32
+ export function MenuFr(
33
+ { "aria-label": ariaLabel, menuButton, instanceRef, onMenuChange, ...restProps }: MenuProps,
34
+ externalRef: ForwardedRef<any>, // FIXME Matt correct type?
20
35
  ) {
21
36
  const [stateProps, toggleMenu, openMenu] = useMenuStateAndFocus(restProps);
22
37
  const isOpen = isMenuOpen(stateProps.state);
23
38
  const skipOpen = useRef(false);
24
- const buttonRef = useRef(null);
39
+ const buttonRef = useRef<HTMLButtonElement>(null);
25
40
 
26
41
  const handleClose = useCallback(
27
42
  (e) => {
28
43
  toggleMenu(false);
29
- if (e.key) buttonRef.current.focus();
44
+ if (e.key) buttonRef.current && buttonRef.current.focus();
30
45
  },
31
46
  [toggleMenu],
32
47
  );
33
48
 
34
- const onClick = (e) => {
49
+ const onClick = (e: MouseEvent) => {
35
50
  if (skipOpen.current) return;
36
51
  // Focus (hover) the first menu item when onClick event is trigger by keyboard
37
52
  openMenu(e.detail === 0 ? FocusPositions.FIRST : undefined);
38
53
  };
39
54
 
40
- const onKeyDown = (e) => {
55
+ const onKeyDown = (e: KeyboardEvent) => {
41
56
  switch (e.key) {
42
57
  case Keys.UP:
43
58
  openMenu(FocusPositions.LAST);
@@ -54,12 +69,14 @@ export const Menu = forwardRef(function Menu(
54
69
  e.preventDefault();
55
70
  };
56
71
 
57
- const button = safeCall(menuButton, { open: isOpen });
72
+ // FIXME erk! button seems to be many types
73
+ const button: any = safeCall(menuButton, { open: isOpen });
58
74
  if (!button || !button.type) throw new Error("Menu requires a menuButton prop.");
59
75
 
60
76
  const buttonProps = {
61
77
  ref: useCombinedRef(button.ref, buttonRef),
62
78
  ...mergeProps({ onClick, onKeyDown }, button.props),
79
+ isOpen: false,
63
80
  };
64
81
  if (getName(button.type) === "MenuButton") {
65
82
  buttonProps.isOpen = isOpen;
@@ -87,10 +104,5 @@ export const Menu = forwardRef(function Menu(
87
104
  />
88
105
  </Fragment>
89
106
  );
90
- });
91
-
92
- Menu.propTypes = {
93
- ...rootMenuPropTypes,
94
- ...uncontrolledMenuPropTypes,
95
- menuButton: oneOfType([element, func]).isRequired,
96
- };
107
+ }
108
+ export const Menu = forwardRef(MenuFr);
@@ -1,33 +1,34 @@
1
- // @ts-nocheck
2
- import { forwardRef, useMemo } from "react";
3
- import { bool } from "prop-types";
1
+ import { forwardRef, LegacyRef, ReactNode, useMemo } from "react";
4
2
  import { useBEM } from "../hooks";
5
- import { defineName, menuButtonClass, stylePropTypes } from "../utils";
3
+ import { menuButtonClass } from "../utils";
4
+ import { BaseProps, MenuButtonModifiers } from "../types";
6
5
 
7
- export const MenuButton = defineName(
8
- "MenuButton",
9
- forwardRef(function MenuButton({ className, isOpen, disabled, children, ...restProps }, ref) {
10
- const modifiers = useMemo(() => ({ open: isOpen }), [isOpen]);
6
+ export interface MenuButtonProps extends BaseProps<MenuButtonModifiers> {
7
+ disabled?: boolean;
8
+ children?: ReactNode;
11
9
 
12
- return (
13
- <button
14
- aria-haspopup
15
- aria-expanded={isOpen}
16
- aria-disabled={disabled || undefined}
17
- type="button"
18
- disabled={disabled}
19
- {...restProps}
20
- ref={ref}
21
- className={useBEM({ block: menuButtonClass, modifiers, className })}
22
- >
23
- {children}
24
- </button>
25
- );
26
- }),
27
- );
10
+ // FIXME Matt added, seems to be an internal thing
11
+ isOpen?: boolean;
12
+ }
28
13
 
29
- MenuButton.propTypes = {
30
- ...stylePropTypes(),
31
- isOpen: bool,
32
- disabled: bool,
33
- };
14
+ export const MenuButton = forwardRef(function MenuButton(
15
+ { className, isOpen, disabled, children, ...restProps }: MenuButtonProps,
16
+ ref: LegacyRef<HTMLButtonElement>,
17
+ ) {
18
+ const modifiers = useMemo(() => ({ open: isOpen }), [isOpen]);
19
+
20
+ return (
21
+ <button
22
+ aria-haspopup
23
+ aria-expanded={isOpen}
24
+ aria-disabled={disabled || undefined}
25
+ type="button"
26
+ disabled={disabled}
27
+ {...restProps}
28
+ ref={ref}
29
+ className={useBEM({ block: menuButtonClass, modifiers, className })}
30
+ >
31
+ {children}
32
+ </button>
33
+ );
34
+ });
@@ -1,21 +1,17 @@
1
- // @ts-nocheck
2
- import { memo, forwardRef } from "react";
1
+ import { memo, forwardRef, LegacyRef } from "react";
3
2
  import { useBEM } from "../hooks";
4
- import { menuClass, menuDividerClass, stylePropTypes } from "../utils";
3
+ import { menuClass, menuDividerClass } from "../utils";
4
+ import { BaseProps } from "../types";
5
5
 
6
- export const MenuDivider = memo(
7
- forwardRef(function MenuDivider({ className, ...restProps }, externalRef) {
8
- return (
9
- <li
10
- role="separator"
11
- {...restProps}
12
- ref={externalRef}
13
- className={useBEM({ block: menuClass, element: menuDividerClass, className })}
14
- />
15
- );
16
- }),
17
- );
18
-
19
- MenuDivider.propTypes = {
20
- ...stylePropTypes(),
6
+ const MenuDividerFr = ({ className, ...restProps }: BaseProps, externalRef: LegacyRef<HTMLLIElement>) => {
7
+ return (
8
+ <li
9
+ role="separator"
10
+ {...restProps}
11
+ ref={externalRef}
12
+ className={useBEM({ block: menuClass, element: menuDividerClass, className })}
13
+ />
14
+ );
21
15
  };
16
+
17
+ export const MenuDivider = memo(forwardRef(MenuDividerFr));
@@ -1,38 +1,47 @@
1
- // @ts-nocheck
2
- import { forwardRef, useContext, useRef, useState } from "react";
3
- import { bool } from "prop-types";
1
+ import { ForwardedRef, forwardRef, ReactNode, useContext, useRef, useState } from "react";
4
2
  import { useBEM, useLayoutEffect, useCombinedRef } from "../hooks";
5
- import { menuClass, menuGroupClass, stylePropTypes, MenuListContext } from "../utils";
3
+ import { menuClass, menuGroupClass, MenuListContext } from "../utils";
4
+ import { BaseProps, MenuOverflow } from "../types";
6
5
 
7
- export const MenuGroup = forwardRef(function MenuGroup({ className, style, takeOverflow, ...restProps }, externalRef) {
8
- const ref = useRef(null);
9
- const [overflowStyle, setOverflowStyle] = useState();
6
+ export interface MenuGroupProps extends BaseProps {
7
+ children?: ReactNode;
8
+ /**
9
+ * Set `true` to apply overflow of the parent menu to the group.
10
+ * Only one `MenuGroup` in a menu should set this prop as `true`.
11
+ */
12
+ takeOverflow?: boolean;
13
+ }
14
+
15
+ export const MenuGroupFr = (
16
+ { className, style, takeOverflow, ...restProps }: MenuGroupProps,
17
+ externalRef: ForwardedRef<HTMLDivElement>,
18
+ ) => {
19
+ const ref = useRef<HTMLDivElement>(null);
20
+ const [overflowStyle, setOverflowStyle] = useState<{ maxHeight?: number; overflow?: MenuOverflow }>();
10
21
  const { overflow, overflowAmt } = useContext(MenuListContext);
11
22
 
12
23
  useLayoutEffect(() => {
13
24
  let maxHeight;
14
- if (takeOverflow && overflowAmt >= 0) {
25
+ if (takeOverflow && overflowAmt != null && overflowAmt >= 0 && ref.current) {
26
+ // FIXME Matt added && ref.current
15
27
  maxHeight = ref.current.getBoundingClientRect().height - overflowAmt;
16
28
  if (maxHeight < 0) maxHeight = 0;
17
29
  }
18
- setOverflowStyle(maxHeight >= 0 ? { maxHeight, overflow } : undefined);
30
+ setOverflowStyle(maxHeight != null && maxHeight >= 0 ? { maxHeight, overflow } : undefined);
19
31
  }, [takeOverflow, overflow, overflowAmt]);
20
32
 
21
33
  useLayoutEffect(() => {
22
- if (overflowStyle) ref.current.scrollTop = 0;
34
+ if (overflowStyle && ref.current) ref.current.scrollTop = 0;
23
35
  }, [overflowStyle]);
24
36
 
25
37
  return (
26
38
  <div
27
39
  {...restProps}
28
- ref={useCombinedRef(externalRef, ref)}
40
+ ref={useCombinedRef(externalRef, ref)} // TODO wierd refs
29
41
  className={useBEM({ block: menuClass, element: menuGroupClass, className })}
30
42
  style={{ ...style, ...overflowStyle }}
31
43
  />
32
44
  );
33
- });
34
-
35
- MenuGroup.propTypes = {
36
- ...stylePropTypes(),
37
- takeOverflow: bool,
38
45
  };
46
+
47
+ export const MenuGroup = forwardRef(MenuGroupFr);
@@ -1,21 +1,17 @@
1
- // @ts-nocheck
2
- import { memo, forwardRef } from "react";
1
+ import { memo, forwardRef, ForwardedRef } from "react";
3
2
  import { useBEM } from "../hooks";
4
- import { menuClass, menuHeaderClass, stylePropTypes } from "../utils";
3
+ import { menuClass, menuHeaderClass } from "../utils";
4
+ import { BaseProps } from "../types";
5
5
 
6
- export const MenuHeader = memo(
7
- forwardRef(function MenuHeader({ className, ...restProps }, externalRef) {
8
- return (
9
- <li
10
- role="presentation"
11
- {...restProps}
12
- ref={externalRef}
13
- className={useBEM({ block: menuClass, element: menuHeaderClass, className })}
14
- />
15
- );
16
- }),
17
- );
18
-
19
- MenuHeader.propTypes = {
20
- ...stylePropTypes(),
6
+ export const MenuHeaderFr = ({ className, ...restProps }: BaseProps, externalRef: ForwardedRef<HTMLLIElement>) => {
7
+ return (
8
+ <li
9
+ role="presentation"
10
+ {...restProps}
11
+ ref={externalRef}
12
+ className={useBEM({ block: menuClass, element: menuHeaderClass, className })}
13
+ />
14
+ );
21
15
  };
16
+
17
+ export const MenuHeader = memo(forwardRef(MenuHeaderFr));
@@ -1,130 +1,182 @@
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 "../types";
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
+ export const MenuItem = withHovering("MenuItem", MenuItemFr);