@fluentui-react-native/menu 0.11.1 → 0.13.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 (109) hide show
  1. package/CHANGELOG.json +46 -1
  2. package/CHANGELOG.md +26 -2
  3. package/lib/Menu/Menu.types.d.ts +2 -0
  4. package/lib/Menu/Menu.types.d.ts.map +1 -1
  5. package/lib/Menu/useMenu.d.ts.map +1 -1
  6. package/lib/Menu/useMenu.js +7 -2
  7. package/lib/Menu/useMenu.js.map +1 -1
  8. package/lib/Menu/useMenuContextValue.d.ts.map +1 -1
  9. package/lib/Menu/useMenuContextValue.js +4 -1
  10. package/lib/Menu/useMenuContextValue.js.map +1 -1
  11. package/lib/MenuItem/MenuItem.js +1 -1
  12. package/lib/MenuItem/MenuItem.js.map +1 -1
  13. package/lib/MenuItem/useMenuItem.d.ts.map +1 -1
  14. package/lib/MenuItem/useMenuItem.js +34 -6
  15. package/lib/MenuItem/useMenuItem.js.map +1 -1
  16. package/lib/MenuItemCheckbox/MenuItemCheckbox.js +1 -1
  17. package/lib/MenuItemCheckbox/MenuItemCheckbox.js.map +1 -1
  18. package/lib/MenuItemCheckbox/useMenuItemCheckbox.d.ts.map +1 -1
  19. package/lib/MenuItemCheckbox/useMenuItemCheckbox.js +12 -8
  20. package/lib/MenuItemCheckbox/useMenuItemCheckbox.js.map +1 -1
  21. package/lib/MenuItemRadio/useMenuItemRadio.d.ts.map +1 -1
  22. package/lib/MenuItemRadio/useMenuItemRadio.js +5 -3
  23. package/lib/MenuItemRadio/useMenuItemRadio.js.map +1 -1
  24. package/lib/MenuPopover/MenuPopover.d.ts +1 -2
  25. package/lib/MenuPopover/MenuPopover.d.ts.map +1 -1
  26. package/lib/MenuPopover/MenuPopover.js +7 -3
  27. package/lib/MenuPopover/MenuPopover.js.map +1 -1
  28. package/lib/MenuPopover/MenuPopover.types.d.ts +5 -11
  29. package/lib/MenuPopover/MenuPopover.types.d.ts.map +1 -1
  30. package/lib/MenuPopover/useMenuPopover.d.ts.map +1 -1
  31. package/lib/MenuPopover/useMenuPopover.js +35 -8
  32. package/lib/MenuPopover/useMenuPopover.js.map +1 -1
  33. package/lib/MenuTrigger/MenuTrigger.d.ts.map +1 -1
  34. package/lib/MenuTrigger/MenuTrigger.js +24 -2
  35. package/lib/MenuTrigger/MenuTrigger.js.map +1 -1
  36. package/lib/MenuTrigger/MenuTrigger.types.d.ts +3 -0
  37. package/lib/MenuTrigger/MenuTrigger.types.d.ts.map +1 -1
  38. package/lib/MenuTrigger/useMenuTrigger.d.ts.map +1 -1
  39. package/lib/MenuTrigger/useMenuTrigger.js +41 -17
  40. package/lib/MenuTrigger/useMenuTrigger.js.map +1 -1
  41. package/lib/consts.d.ts +3 -0
  42. package/lib/consts.d.ts.map +1 -0
  43. package/lib/consts.js +7 -0
  44. package/lib/consts.js.map +1 -0
  45. package/lib/context/menuContext.d.ts +10 -4
  46. package/lib/context/menuContext.d.ts.map +1 -1
  47. package/lib/context/menuContext.js.map +1 -1
  48. package/lib-commonjs/Menu/Menu.types.d.ts +2 -0
  49. package/lib-commonjs/Menu/Menu.types.d.ts.map +1 -1
  50. package/lib-commonjs/Menu/useMenu.d.ts.map +1 -1
  51. package/lib-commonjs/Menu/useMenu.js +7 -2
  52. package/lib-commonjs/Menu/useMenu.js.map +1 -1
  53. package/lib-commonjs/Menu/useMenuContextValue.d.ts.map +1 -1
  54. package/lib-commonjs/Menu/useMenuContextValue.js +4 -1
  55. package/lib-commonjs/Menu/useMenuContextValue.js.map +1 -1
  56. package/lib-commonjs/MenuItem/MenuItem.js +1 -1
  57. package/lib-commonjs/MenuItem/MenuItem.js.map +1 -1
  58. package/lib-commonjs/MenuItem/useMenuItem.d.ts.map +1 -1
  59. package/lib-commonjs/MenuItem/useMenuItem.js +32 -4
  60. package/lib-commonjs/MenuItem/useMenuItem.js.map +1 -1
  61. package/lib-commonjs/MenuItemCheckbox/MenuItemCheckbox.js +1 -1
  62. package/lib-commonjs/MenuItemCheckbox/MenuItemCheckbox.js.map +1 -1
  63. package/lib-commonjs/MenuItemCheckbox/useMenuItemCheckbox.d.ts.map +1 -1
  64. package/lib-commonjs/MenuItemCheckbox/useMenuItemCheckbox.js +12 -8
  65. package/lib-commonjs/MenuItemCheckbox/useMenuItemCheckbox.js.map +1 -1
  66. package/lib-commonjs/MenuItemRadio/useMenuItemRadio.d.ts.map +1 -1
  67. package/lib-commonjs/MenuItemRadio/useMenuItemRadio.js +5 -3
  68. package/lib-commonjs/MenuItemRadio/useMenuItemRadio.js.map +1 -1
  69. package/lib-commonjs/MenuPopover/MenuPopover.d.ts +1 -2
  70. package/lib-commonjs/MenuPopover/MenuPopover.d.ts.map +1 -1
  71. package/lib-commonjs/MenuPopover/MenuPopover.js +5 -2
  72. package/lib-commonjs/MenuPopover/MenuPopover.js.map +1 -1
  73. package/lib-commonjs/MenuPopover/MenuPopover.types.d.ts +5 -11
  74. package/lib-commonjs/MenuPopover/MenuPopover.types.d.ts.map +1 -1
  75. package/lib-commonjs/MenuPopover/useMenuPopover.d.ts.map +1 -1
  76. package/lib-commonjs/MenuPopover/useMenuPopover.js +35 -8
  77. package/lib-commonjs/MenuPopover/useMenuPopover.js.map +1 -1
  78. package/lib-commonjs/MenuTrigger/MenuTrigger.d.ts.map +1 -1
  79. package/lib-commonjs/MenuTrigger/MenuTrigger.js +22 -1
  80. package/lib-commonjs/MenuTrigger/MenuTrigger.js.map +1 -1
  81. package/lib-commonjs/MenuTrigger/MenuTrigger.types.d.ts +3 -0
  82. package/lib-commonjs/MenuTrigger/MenuTrigger.types.d.ts.map +1 -1
  83. package/lib-commonjs/MenuTrigger/useMenuTrigger.d.ts.map +1 -1
  84. package/lib-commonjs/MenuTrigger/useMenuTrigger.js +42 -17
  85. package/lib-commonjs/MenuTrigger/useMenuTrigger.js.map +1 -1
  86. package/lib-commonjs/consts.d.ts +3 -0
  87. package/lib-commonjs/consts.d.ts.map +1 -0
  88. package/lib-commonjs/consts.js +10 -0
  89. package/lib-commonjs/consts.js.map +1 -0
  90. package/lib-commonjs/context/menuContext.d.ts +10 -4
  91. package/lib-commonjs/context/menuContext.d.ts.map +1 -1
  92. package/lib-commonjs/context/menuContext.js.map +1 -1
  93. package/package.json +1 -1
  94. package/src/Menu/Menu.types.ts +1 -0
  95. package/src/Menu/useMenu.ts +8 -1
  96. package/src/Menu/useMenuContextValue.ts +4 -1
  97. package/src/MenuItem/MenuItem.tsx +1 -1
  98. package/src/MenuItem/useMenuItem.ts +49 -9
  99. package/src/MenuItemCheckbox/MenuItemCheckbox.tsx +1 -1
  100. package/src/MenuItemCheckbox/useMenuItemCheckbox.ts +13 -9
  101. package/src/MenuItemRadio/useMenuItemRadio.ts +5 -3
  102. package/src/MenuPopover/MenuPopover.tsx +7 -13
  103. package/src/MenuPopover/MenuPopover.types.ts +5 -9
  104. package/src/MenuPopover/useMenuPopover.ts +47 -8
  105. package/src/MenuTrigger/MenuTrigger.tsx +29 -3
  106. package/src/MenuTrigger/MenuTrigger.types.ts +3 -0
  107. package/src/MenuTrigger/useMenuTrigger.ts +62 -23
  108. package/src/consts.ts +8 -0
  109. package/src/context/menuContext.ts +6 -1
@@ -1,7 +1,8 @@
1
1
  import React from 'react';
2
- import { stagedComponent } from '@fluentui-react-native/framework';
3
- import { menuTriggerName, MenuTriggerProps } from './MenuTrigger.types';
2
+ import { memoize, stagedComponent } from '@fluentui-react-native/framework';
3
+ import { menuTriggerName, MenuTriggerProps, MenuTriggerState } from './MenuTrigger.types';
4
4
  import { useMenuTrigger } from './useMenuTrigger';
5
+ import { AccessibilityActionEvent } from 'react-native';
5
6
  import { MenuTriggerProvider } from '../context/menuTriggerContext';
6
7
 
7
8
  export const MenuTrigger = stagedComponent((props: MenuTriggerProps) => {
@@ -16,12 +17,37 @@ export const MenuTrigger = stagedComponent((props: MenuTriggerProps) => {
16
17
  }
17
18
  }
18
19
 
20
+ // In order to properly support accessibility without erasing props set on the
21
+ // child component which may affect accessibility, we need to modify the
22
+ // state in the inner render so we can access the child component and its props.
19
23
  const child = childrenArray[0];
20
- const revised = React.cloneElement(child, menuTrigger.props);
24
+ const revisedProps = getRevisedState(menuTrigger, child.props);
25
+ const revised = React.cloneElement(child, revisedProps);
21
26
 
22
27
  return <MenuTriggerProvider value={menuTrigger.hasSubmenu}>{revised}</MenuTriggerProvider>;
23
28
  };
24
29
  });
25
30
  MenuTrigger.displayName = menuTriggerName;
26
31
 
32
+ const getRevisedState = memoize(getRevisedStateWorker);
33
+ function getRevisedStateWorker(state: MenuTriggerState, props: any): MenuTriggerProps {
34
+ const revisedProps = { ...state.props };
35
+ if (props.accessibilityState) {
36
+ revisedProps.accessibilityState = { ...state.props.accessibilityState, ...props.accessibilityState };
37
+ }
38
+
39
+ if (props.accessibilityActions) {
40
+ revisedProps.accessibilityActions = { ...state.props.accessibilityActions, ...props.accessibilityActions };
41
+ }
42
+
43
+ if (props.onAccessibilityAction) {
44
+ revisedProps.onAccessibilityAction = (e: AccessibilityActionEvent) => {
45
+ state.props.onAccessibilityAction(e);
46
+ props.onAccessibilityAction(e);
47
+ };
48
+ }
49
+
50
+ return revisedProps;
51
+ }
52
+
27
53
  export default MenuTrigger;
@@ -9,6 +9,9 @@ export interface MenuTriggerProps extends Omit<IWithPressableOptions<ViewProps>,
9
9
  */
10
10
  componentRef?: React.RefObject<React.Component>;
11
11
 
12
+ /**
13
+ * A callback to call on button click event
14
+ */
12
15
  onClick?: (e: InteractionEvent) => void;
13
16
  }
14
17
 
@@ -1,39 +1,78 @@
1
1
  import { useMenuContext } from '../context/menuContext';
2
2
  import { InteractionEvent } from '@fluentui-react-native/interactive-hooks';
3
3
  import { MenuTriggerProps, MenuTriggerState } from './MenuTrigger.types';
4
- import { Platform } from 'react-native';
4
+ import { AccessibilityActionEvent, AccessibilityActionName, Platform } from 'react-native';
5
+ import React from 'react';
6
+ import { delayHover, isCloseOnHoverOutEnabled } from '../consts';
7
+
8
+ const accessibilityActions =
9
+ Platform.OS === ('win32' as any) ? [{ name: 'Expand' as AccessibilityActionName }, { name: 'Collapse' as AccessibilityActionName }] : [];
5
10
 
6
11
  export const useMenuTrigger = (_props: MenuTriggerProps): MenuTriggerState => {
7
12
  const context = useMenuContext();
13
+ const { open, openOnHover, popoverHoverOutTimer, setOpen, setTriggerHoverOutTimer, triggerHoverOutTimer, triggerRef } = context;
8
14
 
9
- const setOpen = context.setOpen;
10
- const open = context.open;
11
- const openOnHover = context.openOnHover;
12
- const triggerRef = context.triggerRef;
15
+ const accessibilityState = open ? { expanded: true } : { expanded: false };
13
16
 
14
- const delayHover = Platform.select({
15
- macos: 100,
16
- default: 500, // win32
17
- });
17
+ const onAccessibilityAction = React.useCallback(
18
+ (e: AccessibilityActionEvent) => {
19
+ if (Platform.OS === ('win32' as any)) {
20
+ switch (e.nativeEvent.actionName) {
21
+ case 'Expand':
22
+ setOpen(e, true /* isOpen */);
23
+ break;
18
24
 
19
- const onHoverIn = (e: InteractionEvent) => {
20
- if (openOnHover) {
21
- setOpen(e, true /* isOpen */);
22
- }
23
- };
25
+ case 'Collapse':
26
+ setOpen(e, false /* isOpen */);
27
+ break;
28
+ }
29
+ }
30
+ },
31
+ [setOpen],
32
+ );
24
33
 
25
- const onHoverOut = (e: InteractionEvent) => {
26
- if (openOnHover) {
27
- setOpen(e, false /* isOpen */);
28
- }
29
- };
34
+ const onHoverIn = React.useCallback(
35
+ (e: InteractionEvent) => {
36
+ if (openOnHover) {
37
+ clearTimeout(popoverHoverOutTimer);
38
+ clearTimeout(triggerHoverOutTimer);
39
+ setTimeout(() => {
40
+ setOpen(e, true /* isOpen */);
41
+ }, delayHover);
42
+ }
43
+ },
44
+ [openOnHover, setOpen, triggerHoverOutTimer, popoverHoverOutTimer],
45
+ );
30
46
 
31
- const onClick = (e: InteractionEvent) => {
32
- setOpen(e, !open);
33
- };
47
+ const onHoverOut = React.useCallback(
48
+ (e: InteractionEvent) => {
49
+ if (openOnHover) {
50
+ const timer = setTimeout(() => {
51
+ setOpen(e, false /* isOpen */);
52
+ }, delayHover);
53
+ setTriggerHoverOutTimer(timer);
54
+ }
55
+ },
56
+ [openOnHover, setOpen, setTriggerHoverOutTimer],
57
+ );
58
+
59
+ const onClick = React.useCallback(
60
+ (e: InteractionEvent) => {
61
+ setOpen(e, !open);
62
+ },
63
+ [open, setOpen],
64
+ );
34
65
 
35
66
  return {
36
- props: { onClick, onHoverIn, onHoverOut, componentRef: triggerRef, delayHoverIn: delayHover, delayHoverOut: delayHover },
67
+ props: {
68
+ onClick,
69
+ onHoverIn,
70
+ onHoverOut: isCloseOnHoverOutEnabled && onHoverOut,
71
+ componentRef: triggerRef,
72
+ accessibilityState,
73
+ accessibilityActions,
74
+ onAccessibilityAction,
75
+ },
37
76
  hasSubmenu: context.isSubmenu,
38
77
  };
39
78
  };
package/src/consts.ts ADDED
@@ -0,0 +1,8 @@
1
+ import { Platform } from 'react-native';
2
+
3
+ export const delayHover = Platform.select({
4
+ macos: 100,
5
+ default: 500, // win32
6
+ });
7
+
8
+ export const isCloseOnHoverOutEnabled = Platform.OS === ('win32' as any);
@@ -4,7 +4,12 @@ import type { MenuState } from '../Menu/Menu.types';
4
4
  /**
5
5
  * Context shared between Menu and its child components
6
6
  */
7
- export type MenuContextValue = MenuState;
7
+ export interface MenuContextValue extends MenuState {
8
+ popoverHoverOutTimer?: NodeJS.Timeout;
9
+ triggerHoverOutTimer?: NodeJS.Timeout;
10
+ setPopoverHoverOutTimer?: (timer: NodeJS.Timeout) => void;
11
+ setTriggerHoverOutTimer?: (timer: NodeJS.Timeout) => void;
12
+ }
8
13
 
9
14
  export const MenuContext = React.createContext<MenuContextValue>({
10
15
  isControlled: false,