@fluentui-react-native/menu 0.6.0 → 0.9.0

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 (201) hide show
  1. package/CHANGELOG.json +46 -1
  2. package/CHANGELOG.md +26 -2
  3. package/lib/Menu/Menu.types.d.ts +2 -2
  4. package/lib/Menu/Menu.types.d.ts.map +1 -1
  5. package/lib/MenuDivider/MenuDivider.d.ts +2 -0
  6. package/lib/MenuDivider/MenuDivider.d.ts.map +1 -0
  7. package/lib/MenuDivider/MenuDivider.js +15 -0
  8. package/lib/MenuDivider/MenuDivider.js.map +1 -0
  9. package/lib/MenuDivider/MenuDivider.styling.d.ts +4 -0
  10. package/lib/MenuDivider/MenuDivider.styling.d.ts.map +1 -0
  11. package/lib/MenuDivider/MenuDivider.styling.js +19 -0
  12. package/lib/MenuDivider/MenuDivider.styling.js.map +1 -0
  13. package/lib/MenuDivider/MenuDivider.types.d.ts +21 -0
  14. package/lib/MenuDivider/MenuDivider.types.d.ts.map +1 -0
  15. package/lib/MenuDivider/MenuDivider.types.js +2 -0
  16. package/lib/MenuDivider/MenuDivider.types.js.map +1 -0
  17. package/lib/MenuDivider/MenuDividerTokens.d.ts +5 -0
  18. package/lib/MenuDivider/MenuDividerTokens.d.ts.map +1 -0
  19. package/lib/MenuDivider/MenuDividerTokens.js +7 -0
  20. package/lib/MenuDivider/MenuDividerTokens.js.map +1 -0
  21. package/lib/MenuDivider/MenuDividerTokens.win32.d.ts +5 -0
  22. package/lib/MenuDivider/MenuDividerTokens.win32.d.ts.map +1 -0
  23. package/lib/MenuDivider/MenuDividerTokens.win32.js +7 -0
  24. package/lib/MenuDivider/MenuDividerTokens.win32.js.map +1 -0
  25. package/lib/MenuItem/MenuItem.d.ts.map +1 -1
  26. package/lib/MenuItem/MenuItem.js +3 -1
  27. package/lib/MenuItem/MenuItem.js.map +1 -1
  28. package/lib/MenuItem/MenuItem.styling.d.ts.map +1 -1
  29. package/lib/MenuItem/MenuItem.styling.js +7 -0
  30. package/lib/MenuItem/MenuItem.styling.js.map +1 -1
  31. package/lib/MenuItem/MenuItem.types.d.ts +12 -7
  32. package/lib/MenuItem/MenuItem.types.d.ts.map +1 -1
  33. package/lib/MenuItem/MenuItemTokens.d.ts.map +1 -1
  34. package/lib/MenuItem/MenuItemTokens.js +2 -0
  35. package/lib/MenuItem/MenuItemTokens.js.map +1 -1
  36. package/lib/MenuItem/MenuItemTokens.win32.d.ts.map +1 -1
  37. package/lib/MenuItem/MenuItemTokens.win32.js +2 -0
  38. package/lib/MenuItem/MenuItemTokens.win32.js.map +1 -1
  39. package/lib/MenuItem/useMenuItem.d.ts.map +1 -1
  40. package/lib/MenuItem/useMenuItem.js +5 -1
  41. package/lib/MenuItem/useMenuItem.js.map +1 -1
  42. package/lib/MenuItemCheckbox/MenuItemCheckbox.d.ts.map +1 -1
  43. package/lib/MenuItemCheckbox/MenuItemCheckbox.js +6 -1
  44. package/lib/MenuItemCheckbox/MenuItemCheckbox.js.map +1 -1
  45. package/lib/MenuItemCheckbox/MenuItemCheckbox.styling.d.ts.map +1 -1
  46. package/lib/MenuItemCheckbox/MenuItemCheckbox.styling.js +12 -6
  47. package/lib/MenuItemCheckbox/MenuItemCheckbox.styling.js.map +1 -1
  48. package/lib/MenuItemCheckbox/MenuItemCheckbox.types.d.ts +14 -9
  49. package/lib/MenuItemCheckbox/MenuItemCheckbox.types.d.ts.map +1 -1
  50. package/lib/MenuItemCheckbox/MenuItemCheckbox.types.js.map +1 -1
  51. package/lib/MenuItemCheckbox/MenuItemCheckboxTokens.d.ts.map +1 -1
  52. package/lib/MenuItemCheckbox/MenuItemCheckboxTokens.js +20 -0
  53. package/lib/MenuItemCheckbox/MenuItemCheckboxTokens.js.map +1 -1
  54. package/lib/MenuItemCheckbox/MenuItemCheckboxTokens.win32.d.ts.map +1 -1
  55. package/lib/MenuItemCheckbox/MenuItemCheckboxTokens.win32.js +20 -0
  56. package/lib/MenuItemCheckbox/MenuItemCheckboxTokens.win32.js.map +1 -1
  57. package/lib/MenuItemCheckbox/useMenuItemCheckbox.d.ts.map +1 -1
  58. package/lib/MenuItemCheckbox/useMenuItemCheckbox.js +31 -12
  59. package/lib/MenuItemCheckbox/useMenuItemCheckbox.js.map +1 -1
  60. package/lib/MenuList/MenuList.d.ts.map +1 -1
  61. package/lib/MenuList/MenuList.js +8 -2
  62. package/lib/MenuList/MenuList.js.map +1 -1
  63. package/lib/MenuList/MenuList.types.d.ts +8 -0
  64. package/lib/MenuList/MenuList.types.d.ts.map +1 -1
  65. package/lib/MenuList/MenuList.types.js.map +1 -1
  66. package/lib/MenuList/useMenuContextValue.d.ts +4 -0
  67. package/lib/MenuList/useMenuContextValue.d.ts.map +1 -0
  68. package/lib/MenuList/useMenuContextValue.js +5 -0
  69. package/lib/MenuList/useMenuContextValue.js.map +1 -0
  70. package/lib/MenuList/useMenuList.d.ts +3 -0
  71. package/lib/MenuList/useMenuList.d.ts.map +1 -0
  72. package/lib/MenuList/useMenuList.js +31 -0
  73. package/lib/MenuList/useMenuList.js.map +1 -0
  74. package/lib/context/menuContext.d.ts.map +1 -1
  75. package/lib/context/menuContext.js +4 -0
  76. package/lib/context/menuContext.js.map +1 -1
  77. package/lib/context/menuListContext.d.ts +10 -0
  78. package/lib/context/menuListContext.d.ts.map +1 -0
  79. package/lib/context/menuListContext.js +11 -0
  80. package/lib/context/menuListContext.js.map +1 -0
  81. package/lib/index.d.ts +2 -0
  82. package/lib/index.d.ts.map +1 -1
  83. package/lib/index.js +2 -0
  84. package/lib/index.js.map +1 -1
  85. package/lib-commonjs/Menu/Menu.types.d.ts +2 -2
  86. package/lib-commonjs/Menu/Menu.types.d.ts.map +1 -1
  87. package/lib-commonjs/MenuDivider/MenuDivider.d.ts +2 -0
  88. package/lib-commonjs/MenuDivider/MenuDivider.d.ts.map +1 -0
  89. package/lib-commonjs/MenuDivider/MenuDivider.js +18 -0
  90. package/lib-commonjs/MenuDivider/MenuDivider.js.map +1 -0
  91. package/lib-commonjs/MenuDivider/MenuDivider.styling.d.ts +4 -0
  92. package/lib-commonjs/MenuDivider/MenuDivider.styling.d.ts.map +1 -0
  93. package/lib-commonjs/MenuDivider/MenuDivider.styling.js +22 -0
  94. package/lib-commonjs/MenuDivider/MenuDivider.styling.js.map +1 -0
  95. package/lib-commonjs/MenuDivider/MenuDivider.types.d.ts +21 -0
  96. package/lib-commonjs/MenuDivider/MenuDivider.types.d.ts.map +1 -0
  97. package/lib-commonjs/MenuDivider/MenuDivider.types.js +5 -0
  98. package/lib-commonjs/MenuDivider/MenuDivider.types.js.map +1 -0
  99. package/lib-commonjs/MenuDivider/MenuDividerTokens.d.ts +5 -0
  100. package/lib-commonjs/MenuDivider/MenuDividerTokens.d.ts.map +1 -0
  101. package/lib-commonjs/MenuDivider/MenuDividerTokens.js +11 -0
  102. package/lib-commonjs/MenuDivider/MenuDividerTokens.js.map +1 -0
  103. package/lib-commonjs/MenuDivider/MenuDividerTokens.win32.d.ts +5 -0
  104. package/lib-commonjs/MenuDivider/MenuDividerTokens.win32.d.ts.map +1 -0
  105. package/lib-commonjs/MenuDivider/MenuDividerTokens.win32.js +11 -0
  106. package/lib-commonjs/MenuDivider/MenuDividerTokens.win32.js.map +1 -0
  107. package/lib-commonjs/MenuItem/MenuItem.d.ts.map +1 -1
  108. package/lib-commonjs/MenuItem/MenuItem.js +3 -1
  109. package/lib-commonjs/MenuItem/MenuItem.js.map +1 -1
  110. package/lib-commonjs/MenuItem/MenuItem.styling.d.ts.map +1 -1
  111. package/lib-commonjs/MenuItem/MenuItem.styling.js +7 -0
  112. package/lib-commonjs/MenuItem/MenuItem.styling.js.map +1 -1
  113. package/lib-commonjs/MenuItem/MenuItem.types.d.ts +12 -7
  114. package/lib-commonjs/MenuItem/MenuItem.types.d.ts.map +1 -1
  115. package/lib-commonjs/MenuItem/MenuItemTokens.d.ts.map +1 -1
  116. package/lib-commonjs/MenuItem/MenuItemTokens.js +2 -0
  117. package/lib-commonjs/MenuItem/MenuItemTokens.js.map +1 -1
  118. package/lib-commonjs/MenuItem/MenuItemTokens.win32.d.ts.map +1 -1
  119. package/lib-commonjs/MenuItem/MenuItemTokens.win32.js +2 -0
  120. package/lib-commonjs/MenuItem/MenuItemTokens.win32.js.map +1 -1
  121. package/lib-commonjs/MenuItem/useMenuItem.d.ts.map +1 -1
  122. package/lib-commonjs/MenuItem/useMenuItem.js +5 -1
  123. package/lib-commonjs/MenuItem/useMenuItem.js.map +1 -1
  124. package/lib-commonjs/MenuItemCheckbox/MenuItemCheckbox.d.ts.map +1 -1
  125. package/lib-commonjs/MenuItemCheckbox/MenuItemCheckbox.js +6 -1
  126. package/lib-commonjs/MenuItemCheckbox/MenuItemCheckbox.js.map +1 -1
  127. package/lib-commonjs/MenuItemCheckbox/MenuItemCheckbox.styling.d.ts.map +1 -1
  128. package/lib-commonjs/MenuItemCheckbox/MenuItemCheckbox.styling.js +12 -6
  129. package/lib-commonjs/MenuItemCheckbox/MenuItemCheckbox.styling.js.map +1 -1
  130. package/lib-commonjs/MenuItemCheckbox/MenuItemCheckbox.types.d.ts +14 -9
  131. package/lib-commonjs/MenuItemCheckbox/MenuItemCheckbox.types.d.ts.map +1 -1
  132. package/lib-commonjs/MenuItemCheckbox/MenuItemCheckbox.types.js.map +1 -1
  133. package/lib-commonjs/MenuItemCheckbox/MenuItemCheckboxTokens.d.ts.map +1 -1
  134. package/lib-commonjs/MenuItemCheckbox/MenuItemCheckboxTokens.js +20 -0
  135. package/lib-commonjs/MenuItemCheckbox/MenuItemCheckboxTokens.js.map +1 -1
  136. package/lib-commonjs/MenuItemCheckbox/MenuItemCheckboxTokens.win32.d.ts.map +1 -1
  137. package/lib-commonjs/MenuItemCheckbox/MenuItemCheckboxTokens.win32.js +20 -0
  138. package/lib-commonjs/MenuItemCheckbox/MenuItemCheckboxTokens.win32.js.map +1 -1
  139. package/lib-commonjs/MenuItemCheckbox/useMenuItemCheckbox.d.ts.map +1 -1
  140. package/lib-commonjs/MenuItemCheckbox/useMenuItemCheckbox.js +29 -10
  141. package/lib-commonjs/MenuItemCheckbox/useMenuItemCheckbox.js.map +1 -1
  142. package/lib-commonjs/MenuList/MenuList.d.ts.map +1 -1
  143. package/lib-commonjs/MenuList/MenuList.js +8 -2
  144. package/lib-commonjs/MenuList/MenuList.js.map +1 -1
  145. package/lib-commonjs/MenuList/MenuList.types.d.ts +8 -0
  146. package/lib-commonjs/MenuList/MenuList.types.d.ts.map +1 -1
  147. package/lib-commonjs/MenuList/MenuList.types.js.map +1 -1
  148. package/lib-commonjs/MenuList/useMenuContextValue.d.ts +4 -0
  149. package/lib-commonjs/MenuList/useMenuContextValue.d.ts.map +1 -0
  150. package/lib-commonjs/MenuList/useMenuContextValue.js +9 -0
  151. package/lib-commonjs/MenuList/useMenuContextValue.js.map +1 -0
  152. package/lib-commonjs/MenuList/useMenuList.d.ts +3 -0
  153. package/lib-commonjs/MenuList/useMenuList.d.ts.map +1 -0
  154. package/lib-commonjs/MenuList/useMenuList.js +35 -0
  155. package/lib-commonjs/MenuList/useMenuList.js.map +1 -0
  156. package/lib-commonjs/context/menuContext.d.ts.map +1 -1
  157. package/lib-commonjs/context/menuContext.js +4 -0
  158. package/lib-commonjs/context/menuContext.js.map +1 -1
  159. package/lib-commonjs/context/menuListContext.d.ts +10 -0
  160. package/lib-commonjs/context/menuListContext.d.ts.map +1 -0
  161. package/lib-commonjs/context/menuListContext.js +16 -0
  162. package/lib-commonjs/context/menuListContext.js.map +1 -0
  163. package/lib-commonjs/index.d.ts +2 -0
  164. package/lib-commonjs/index.d.ts.map +1 -1
  165. package/lib-commonjs/index.js +5 -1
  166. package/lib-commonjs/index.js.map +1 -1
  167. package/package.json +1 -1
  168. package/src/Menu/Menu.types.ts +2 -2
  169. package/src/MenuDivider/MenuDivider.styling.ts +22 -0
  170. package/src/MenuDivider/MenuDivider.tsx +20 -0
  171. package/src/MenuDivider/MenuDivider.types.ts +25 -0
  172. package/src/MenuDivider/MenuDividerTokens.ts +10 -0
  173. package/src/MenuDivider/MenuDividerTokens.win32.ts +10 -0
  174. package/src/MenuItem/MenuItem.styling.ts +10 -0
  175. package/src/MenuItem/MenuItem.tsx +3 -1
  176. package/src/MenuItem/MenuItem.types.ts +14 -8
  177. package/src/MenuItem/MenuItemTokens.ts +2 -0
  178. package/src/MenuItem/MenuItemTokens.win32.ts +2 -0
  179. package/src/MenuItem/useMenuItem.ts +5 -2
  180. package/src/MenuItemCheckbox/MenuItemCheckbox.styling.ts +19 -10
  181. package/src/MenuItemCheckbox/MenuItemCheckbox.tsx +12 -1
  182. package/src/MenuItemCheckbox/MenuItemCheckbox.types.ts +14 -10
  183. package/src/MenuItemCheckbox/MenuItemCheckboxTokens.ts +20 -0
  184. package/src/MenuItemCheckbox/MenuItemCheckboxTokens.win32.ts +20 -0
  185. package/src/MenuItemCheckbox/useMenuItemCheckbox.ts +64 -16
  186. package/src/MenuList/MenuList.tsx +11 -2
  187. package/src/MenuList/MenuList.types.ts +11 -1
  188. package/src/MenuList/useMenuContextValue.ts +6 -0
  189. package/src/MenuList/useMenuList.ts +49 -0
  190. package/src/context/menuContext.ts +4 -0
  191. package/src/context/menuListContext.ts +18 -0
  192. package/src/index.ts +2 -0
  193. package/lib/context/menuTriggerContext.d.ts +0 -1
  194. package/lib/context/menuTriggerContext.d.ts.map +0 -1
  195. package/lib/context/menuTriggerContext.js +0 -2
  196. package/lib/context/menuTriggerContext.js.map +0 -1
  197. package/lib-commonjs/context/menuTriggerContext.d.ts +0 -1
  198. package/lib-commonjs/context/menuTriggerContext.d.ts.map +0 -1
  199. package/lib-commonjs/context/menuTriggerContext.js +0 -2
  200. package/lib-commonjs/context/menuTriggerContext.js.map +0 -1
  201. package/src/context/menuTriggerContext.ts +0 -0
@@ -3,7 +3,7 @@ import { fontStyles, layoutStyles } from '@fluentui-react-native/tokens';
3
3
  import { defaultMenuItemCheckboxTokens } from './MenuItemCheckboxTokens';
4
4
  import { menuItemCheckboxName, MenuItemCheckboxProps, MenuItemCheckboxTokens, MenuItemCheckboxSlotProps } from './MenuItemCheckbox.types';
5
5
 
6
- export const menuItemCheckboxStates: (keyof MenuItemCheckboxTokens)[] = ['hovered', 'focused', 'pressed', 'disabled'];
6
+ export const menuItemCheckboxStates: (keyof MenuItemCheckboxTokens)[] = ['hovered', 'focused', 'pressed', 'disabled', 'checked'];
7
7
 
8
8
  export const stylingSettings: UseStylingOptions<MenuItemCheckboxProps, MenuItemCheckboxSlotProps, MenuItemCheckboxTokens> = {
9
9
  tokens: [defaultMenuItemCheckboxTokens, menuItemCheckboxName],
@@ -21,16 +21,25 @@ export const stylingSettings: UseStylingOptions<MenuItemCheckboxProps, MenuItemC
21
21
  }),
22
22
  ['backgroundColor', ...layoutStyles.keys],
23
23
  ),
24
+ checkmark: buildProps(
25
+ (tokens: MenuItemCheckboxTokens) => ({
26
+ opacity: tokens.checkmarkVisibility,
27
+ color: tokens.color,
28
+ height: tokens.checkmarkSize,
29
+ width: tokens.checkmarkSize,
30
+ viewBox: '0 0 ' + (tokens.checkmarkSize - tokens.checkmarkPadding * 2) + ' ' + (tokens.checkmarkSize - tokens.checkmarkPadding * 2),
31
+ style: { marginEnd: tokens.gap },
32
+ }),
33
+ ['checkmarkSize', 'gap', 'color'],
34
+ ),
24
35
  content: buildProps(
25
- (tokens: MenuItemCheckboxTokens, theme: Theme) => {
26
- return {
27
- style: {
28
- flexGrow: 1,
29
- color: tokens.color,
30
- ...fontStyles.from(tokens, theme),
31
- },
32
- };
33
- },
36
+ (tokens: MenuItemCheckboxTokens, theme: Theme) => ({
37
+ style: {
38
+ flexGrow: 1,
39
+ color: tokens.color,
40
+ ...fontStyles.from(tokens, theme),
41
+ },
42
+ }),
34
43
  ['color', ...fontStyles.keys],
35
44
  ),
36
45
  },
@@ -1,5 +1,6 @@
1
1
  /** @jsx withSlots */
2
2
  import { View } from 'react-native';
3
+ import { SvgXml } from 'react-native-svg';
3
4
  import { compose, mergeProps, UseSlots, withSlots } from '@fluentui-react-native/framework';
4
5
  import { Text } from '@fluentui-react-native/experimental-text';
5
6
  import { menuItemCheckboxName, MenuItemCheckboxProps, MenuItemCheckboxType } from './MenuItemCheckbox.types';
@@ -11,6 +12,7 @@ export const MenuItemCheckbox = compose<MenuItemCheckboxType>({
11
12
  ...stylingSettings,
12
13
  slots: {
13
14
  root: View,
15
+ checkmark: SvgXml,
14
16
  content: Text,
15
17
  },
16
18
  useRender: (userProps: MenuItemCheckboxProps, useSlots: UseSlots<MenuItemCheckboxType>) => {
@@ -19,8 +21,17 @@ export const MenuItemCheckbox = compose<MenuItemCheckboxType>({
19
21
 
20
22
  return (final: MenuItemCheckboxProps) => {
21
23
  const mergedProps = mergeProps(menuItem.props, final);
24
+ const chevronXml = `
25
+ <svg>
26
+ <path fill='currentColor' d='M9.85355 3.14645C10.0488 3.34171 10.0488 3.65829 9.85355 3.85355L5.35355 8.35355C5.15829 8.54882 4.84171 8.54882 4.64645 8.35355L2.64645 6.35355C2.45118 6.15829 2.45118 5.84171 2.64645 5.64645C2.84171 5.45118 3.15829 5.45118 3.35355 5.64645L5 7.29289L9.14645 3.14645C9.34171 2.95118 9.65829 2.95118 9.85355 3.14645Z' />
27
+ </svg>`;
22
28
 
23
- return <Slots.root {...mergedProps}>{mergedProps.content && <Slots.content>{mergedProps.content}</Slots.content>}</Slots.root>;
29
+ return (
30
+ <Slots.root {...mergedProps}>
31
+ <Slots.checkmark xml={chevronXml} />
32
+ {mergedProps.content && <Slots.content>{mergedProps.content}</Slots.content>}
33
+ </Slots.root>
34
+ );
24
35
  };
25
36
  },
26
37
  });
@@ -1,13 +1,21 @@
1
1
  import * as React from 'react';
2
- import { ViewProps } from 'react-native';
2
+ import { ColorValue, ViewProps } from 'react-native';
3
+ import { XmlProps } from 'react-native-svg';
3
4
  import type { IViewProps } from '@fluentui-react-native/adapters';
4
5
  import { TextProps } from '@fluentui-react-native/experimental-text';
5
- import { IFocusable, InteractionEvent, IPressableHooks, IWithPressableOptions } from '@fluentui-react-native/interactive-hooks';
6
+ import { IFocusable, IPressableHooks, IWithPressableOptions } from '@fluentui-react-native/interactive-hooks';
6
7
  import { FontTokens, IBorderTokens, IColorTokens, LayoutTokens } from '@fluentui-react-native/tokens';
7
8
 
8
9
  export const menuItemCheckboxName = 'MenuItemCheckbox';
9
10
 
10
11
  export interface MenuItemCheckboxTokens extends LayoutTokens, FontTokens, IBorderTokens, IColorTokens {
12
+ checkmarkColor?: ColorValue;
13
+ checkmarkPadding?: number;
14
+ checkmarkSize?: number;
15
+ checkmarkVisibility?: number;
16
+ gap?: number;
17
+
18
+ checked?: MenuItemCheckboxTokens;
11
19
  disabled?: MenuItemCheckboxTokens;
12
20
  focused?: MenuItemCheckboxTokens;
13
21
  hovered?: MenuItemCheckboxTokens;
@@ -28,20 +36,16 @@ export interface MenuItemCheckboxProps extends Omit<IWithPressableOptions<ViewPr
28
36
  componentRef?: React.RefObject<IFocusable>;
29
37
 
30
38
  /**
31
- * If the menu item is a trigger for a submenu
32
- */
33
- hasSubmenu?: boolean;
34
-
35
- /**
36
- * A callback to call on button click event
39
+ * Identifier for the control
37
40
  */
38
- onClick?: (e: InteractionEvent) => void;
41
+ name: string;
39
42
  }
40
43
 
41
- export type MenuItemCheckboxState = IPressableHooks<MenuItemCheckboxProps & React.ComponentPropsWithRef<any>>;
44
+ export interface MenuItemCheckboxState extends IPressableHooks<MenuItemCheckboxProps & React.ComponentPropsWithRef<any>> {}
42
45
 
43
46
  export interface MenuItemCheckboxSlotProps {
44
47
  root: React.PropsWithRef<IViewProps>;
48
+ checkmark?: XmlProps;
45
49
  content?: TextProps;
46
50
  }
47
51
 
@@ -6,10 +6,14 @@ import { MenuItemCheckboxTokens } from './MenuItemCheckbox.types';
6
6
  export const defaultMenuItemCheckboxTokens: TokenSettings<MenuItemCheckboxTokens, Theme> = (t: Theme): MenuItemCheckboxTokens => ({
7
7
  backgroundColor: t.colors.neutralBackground1,
8
8
  borderRadius: globalTokens.corner.radius.medium,
9
+ checkmarkPadding: globalTokens.spacing.none,
10
+ checkmarkSize: 16,
11
+ checkmarkVisibility: 0,
9
12
  color: t.colors.neutralForeground2,
10
13
  fontFamily: t.typography.families.primary,
11
14
  fontSize: globalTokens.font.size[300],
12
15
  fontWeight: globalTokens.font.weight.regular as FontWeightValue,
16
+ gap: globalTokens.spacing.xs,
13
17
  minHeight: 32,
14
18
  minWidth: 160,
15
19
  maxWidth: 300,
@@ -17,13 +21,29 @@ export const defaultMenuItemCheckboxTokens: TokenSettings<MenuItemCheckboxTokens
17
21
  hovered: {
18
22
  backgroundColor: t.colors.neutralBackground1Hover,
19
23
  color: t.colors.neutralForeground2Hover,
24
+ checked: {
25
+ checkmarkColor: t.colors.neutralForeground2Hover,
26
+ checkmarkVisibility: 1,
27
+ },
20
28
  },
21
29
  pressed: {
22
30
  backgroundColor: t.colors.neutralBackground1Pressed,
23
31
  color: t.colors.neutralForeground2Pressed,
32
+ checked: {
33
+ checkmarkColor: t.colors.neutralForeground2Pressed,
34
+ checkmarkVisibility: 1,
35
+ },
24
36
  },
25
37
  disabled: {
26
38
  backgroundColor: t.colors.neutralBackground1,
27
39
  color: t.colors.neutralForegroundDisabled,
40
+ checked: {
41
+ checkmarkColor: t.colors.neutralForegroundDisabled,
42
+ checkmarkVisibility: 1,
43
+ },
44
+ },
45
+ checked: {
46
+ checkmarkColor: t.colors.neutralForeground2,
47
+ checkmarkVisibility: 1,
28
48
  },
29
49
  });
@@ -6,10 +6,14 @@ import { MenuItemCheckboxTokens } from './MenuItemCheckbox.types';
6
6
  export const defaultMenuItemCheckboxTokens: TokenSettings<MenuItemCheckboxTokens, Theme> = (t: Theme): MenuItemCheckboxTokens => ({
7
7
  backgroundColor: t.colors.neutralBackground1,
8
8
  borderRadius: globalTokens.corner.radius.none,
9
+ checkmarkPadding: globalTokens.spacing.xxs,
10
+ checkmarkSize: 16,
11
+ checkmarkVisibility: 0,
9
12
  color: t.colors.neutralForeground1,
10
13
  fontFamily: t.typography.families.primary,
11
14
  fontSize: globalTokens.font.size[200],
12
15
  fontWeight: globalTokens.font.weight.regular as FontWeightValue,
16
+ gap: globalTokens.spacing.xs,
13
17
  minHeight: 24,
14
18
  minWidth: 160,
15
19
  maxWidth: 300,
@@ -18,13 +22,29 @@ export const defaultMenuItemCheckboxTokens: TokenSettings<MenuItemCheckboxTokens
18
22
  hovered: {
19
23
  backgroundColor: t.colors.neutralBackground1Hover,
20
24
  color: t.colors.neutralForeground1Hover,
25
+ checked: {
26
+ checkmarkColor: t.colors.neutralForeground1Hover,
27
+ checkmarkVisibility: 1,
28
+ },
21
29
  },
22
30
  pressed: {
23
31
  backgroundColor: t.colors.neutralBackground1Pressed,
24
32
  color: t.colors.neutralForeground1Pressed,
33
+ checked: {
34
+ checkmarkColor: t.colors.neutralForeground1Pressed,
35
+ checkmarkVisibility: 1,
36
+ },
25
37
  },
26
38
  disabled: {
27
39
  backgroundColor: t.colors.neutralBackground1,
28
40
  color: t.colors.neutralForegroundDisabled,
41
+ checked: {
42
+ checkmarkColor: t.colors.neutralForegroundDisabled,
43
+ checkmarkVisibility: 1,
44
+ },
45
+ },
46
+ checked: {
47
+ checkmarkColor: t.colors.neutralForeground1,
48
+ checkmarkVisibility: 1,
29
49
  },
30
50
  });
@@ -1,40 +1,88 @@
1
1
  import * as React from 'react';
2
- import { AccessibilityState } from 'react-native';
2
+ import { AccessibilityActionEvent, AccessibilityState } from 'react-native';
3
3
  import { MenuItemCheckboxProps, MenuItemCheckboxState } from './MenuItemCheckbox.types';
4
4
  import { memoize } from '@fluentui-react-native/framework';
5
- import { useAsPressable, useKeyProps } from '@fluentui-react-native/interactive-hooks';
6
- import { useMenuContext } from '../context/menuContext';
5
+ import {
6
+ InteractionEvent,
7
+ useAsPressable,
8
+ useKeyProps,
9
+ useOnPressWithFocus,
10
+ useViewCommandFocus,
11
+ } from '@fluentui-react-native/interactive-hooks';
12
+ import { useMenuListContext } from '../context/menuListContext';
13
+
14
+ const defaultAccessibilityActions = [{ name: 'Toggle' }];
7
15
 
8
16
  export const useMenuItemCheckbox = (props: MenuItemCheckboxProps): MenuItemCheckboxState => {
9
17
  // attach the pressable state handlers
10
18
  const defaultComponentRef = React.useRef(null);
11
- const { onClick, accessibilityState, componentRef = defaultComponentRef, disabled, ...rest } = props;
12
- const pressable = useAsPressable({ ...rest, disabled, onPress: onClick });
13
- const onKeyProps = useKeyProps(onClick, ' ', 'Enter');
14
- const hasSubmenu = useMenuContext().isSubmenu;
19
+ const {
20
+ accessibilityActions,
21
+ accessibilityState,
22
+ componentRef = defaultComponentRef,
23
+ disabled,
24
+ name,
25
+ onAccessibilityAction,
26
+ ...rest
27
+ } = props;
28
+ const context = useMenuListContext();
29
+ const checked = context.checked?.[name];
30
+ const onCheckedChange = context.onCheckedChange;
31
+
32
+ const toggleChecked = React.useCallback(
33
+ (e: InteractionEvent) => {
34
+ onCheckedChange(e, name, !checked);
35
+ },
36
+ [checked, name, onCheckedChange],
37
+ );
38
+ // Ensure focus is placed on checkbox after click
39
+ const toggleCheckedWithFocus = useOnPressWithFocus(componentRef, toggleChecked);
40
+
41
+ const pressable = useAsPressable({ onPress: toggleCheckedWithFocus, ...rest });
42
+ const buttonRef = useViewCommandFocus(componentRef);
43
+
44
+ const onKeyProps = useKeyProps(toggleChecked, ' ');
45
+ const accessibilityActionsProp = accessibilityActions
46
+ ? [...defaultAccessibilityActions, ...accessibilityActions]
47
+ : defaultAccessibilityActions;
48
+ const onAccessibilityActionProp = React.useCallback(
49
+ (event: AccessibilityActionEvent) => {
50
+ if (event.nativeEvent.actionName === 'Toggle') {
51
+ toggleChecked(event);
52
+ }
53
+ onAccessibilityAction && onAccessibilityAction(event);
54
+ },
55
+ [toggleChecked, onAccessibilityAction],
56
+ );
57
+
58
+ const state = {
59
+ ...pressable.state,
60
+ disabled: !!props.disabled,
61
+ checked: checked,
62
+ };
15
63
 
16
64
  return {
17
65
  props: {
18
66
  ...pressable.props,
19
67
  accessible: true,
20
- accessibilityRole: 'button',
21
- onAccessibilityTap: props.onAccessibilityTap || props.onClick,
68
+ accessibilityActions: accessibilityActionsProp,
22
69
  accessibilityLabel: props.accessibilityLabel,
23
- accessibilityState: getAccessibilityState(disabled, accessibilityState),
70
+ accessibilityRole: 'menuitem',
71
+ accessibilityState: getAccessibilityState(disabled, state.checked, accessibilityState),
24
72
  enableFocusRing: true,
25
73
  focusable: !disabled,
26
- hasSubmenu,
27
- ref: componentRef,
74
+ onAccessibilityAction: onAccessibilityActionProp,
75
+ ref: buttonRef,
28
76
  ...onKeyProps,
29
77
  },
30
- state: pressable.state,
78
+ state: state,
31
79
  };
32
80
  };
33
81
 
34
82
  const getAccessibilityState = memoize(getAccessibilityStateWorker);
35
- function getAccessibilityStateWorker(disabled: boolean, accessibilityState?: AccessibilityState) {
83
+ function getAccessibilityStateWorker(disabled: boolean, checked: boolean, accessibilityState?: AccessibilityState) {
36
84
  if (accessibilityState) {
37
- return { disabled, ...accessibilityState };
85
+ return { disabled, checked, ...accessibilityState };
38
86
  }
39
- return { disabled };
87
+ return { disabled, checked };
40
88
  }
@@ -4,6 +4,9 @@ import { View } from 'react-native';
4
4
  import { compose, UseSlots, withSlots } from '@fluentui-react-native/framework';
5
5
  import { menuListName, MenuListProps, MenuListType } from './MenuList.types';
6
6
  import { stylingSettings } from './MenuList.styling';
7
+ import { MenuListProvider } from '../context/menuListContext';
8
+ import { useMenuList } from './useMenuList';
9
+ import { useMenuListContextValue } from './useMenuContextValue';
7
10
 
8
11
  export const MenuList = compose<MenuListType>({
9
12
  displayName: menuListName,
@@ -12,10 +15,16 @@ export const MenuList = compose<MenuListType>({
12
15
  root: View,
13
16
  },
14
17
  useRender: (userProps: MenuListProps, useSlots: UseSlots<MenuListType>) => {
15
- const Slots = useSlots(userProps);
18
+ const menuList = useMenuList(userProps);
19
+ const contextValue = useMenuListContextValue(menuList);
20
+ const Slots = useSlots(menuList);
16
21
 
17
22
  return (_final: MenuListProps, children: React.ReactNode) => {
18
- return <Slots.root>{children}</Slots.root>;
23
+ return (
24
+ <MenuListProvider value={contextValue}>
25
+ <Slots.root>{children}</Slots.root>
26
+ </MenuListProvider>
27
+ );
19
28
  };
20
29
  },
21
30
  });
@@ -1,11 +1,21 @@
1
1
  import type { IViewProps } from '@fluentui-react-native/adapters';
2
+ import { InteractionEvent } from '@fluentui-react-native/interactive-hooks';
2
3
  import { IBackgroundColorTokens, LayoutTokens } from '@fluentui-react-native/tokens';
3
4
 
4
5
  export const menuListName = 'MenuList';
5
6
 
6
7
  export interface MenuListTokens extends LayoutTokens, IBackgroundColorTokens {}
7
8
 
8
- export interface MenuListProps extends Omit<IViewProps, 'onPress'> {}
9
+ export interface MenuListProps extends Omit<IViewProps, 'onPress'> {
10
+ checked?: Record<string, boolean>;
11
+ defaultChecked?: Record<string, boolean>;
12
+ hasCheckmarks?: boolean;
13
+ onCheckedChange?: (e: InteractionEvent, name: string, isChecked: boolean) => void;
14
+ }
15
+
16
+ export interface MenuListState extends MenuListProps {
17
+ isCheckedControlled: boolean;
18
+ }
9
19
 
10
20
  export interface MenuListSlotProps {
11
21
  root: React.PropsWithRef<IViewProps>;
@@ -0,0 +1,6 @@
1
+ import { MenuListContextValue } from '../context/menuListContext';
2
+ import { MenuListState } from './MenuList.types';
3
+
4
+ export const useMenuListContextValue = (state: MenuListState): MenuListContextValue => {
5
+ return { ...state };
6
+ };
@@ -0,0 +1,49 @@
1
+ import { InteractionEvent } from '@fluentui-react-native/interactive-hooks';
2
+ import React from 'react';
3
+ import { useMenuContext } from '../context/menuContext';
4
+ import { MenuListProps, MenuListState } from './MenuList.types';
5
+
6
+ export const useMenuList = (_props: MenuListProps): MenuListState => {
7
+ const context = useMenuContext();
8
+
9
+ // MenuList v2 needs to be able to be standalone, but this is not in scope for v1
10
+ // Assuming that checked information will come from parent Menu
11
+ const isCheckedControlled = typeof context.checked !== 'undefined';
12
+ const [checked, onCheckedChange] = useMenuCheckedState(isCheckedControlled, context);
13
+
14
+ return {
15
+ ...context,
16
+ isCheckedControlled,
17
+ checked,
18
+ onCheckedChange,
19
+ };
20
+ };
21
+
22
+ const useMenuCheckedState = (
23
+ isControlled: boolean,
24
+ props: MenuListProps,
25
+ ): [Record<string, boolean>, (e: InteractionEvent, name: string, isChecked: boolean) => void] => {
26
+ const { defaultChecked, onCheckedChange, checked } = props;
27
+ const initialState = defaultChecked ?? checked ?? {};
28
+ const [checkedInternal, setCheckedInternal] = React.useState<Record<string, boolean>>(initialState);
29
+
30
+ const state = isControlled ? checked : checkedInternal;
31
+
32
+ const setChecked = React.useCallback(
33
+ (e: InteractionEvent, name: string, isChecked: boolean) => {
34
+ if (!isControlled) {
35
+ const curChecked = state;
36
+ curChecked[name] = isChecked;
37
+ const updatedChecked = { ...curChecked };
38
+ setCheckedInternal(updatedChecked);
39
+ }
40
+
41
+ if (onCheckedChange) {
42
+ onCheckedChange(e, name, isChecked);
43
+ }
44
+ },
45
+ [isControlled, state, onCheckedChange, setCheckedInternal],
46
+ );
47
+
48
+ return [state, setChecked];
49
+ };
@@ -8,8 +8,12 @@ export type MenuContextValue = MenuState;
8
8
 
9
9
  export const MenuContext = React.createContext<MenuContextValue>({
10
10
  isControlled: false,
11
+ checked: {},
12
+ defaultChecked: {},
13
+ hasCheckmarks: false,
11
14
  isSubmenu: false,
12
15
  open: false,
16
+ onCheckedChange: () => false,
13
17
  setOpen: () => false,
14
18
  triggerRef: null,
15
19
  });
@@ -0,0 +1,18 @@
1
+ import * as React from 'react';
2
+ import type { MenuListState } from '../MenuList/MenuList.types';
3
+
4
+ /**
5
+ * Context shared between Menu and its child components
6
+ */
7
+ export type MenuListContextValue = MenuListState;
8
+
9
+ export const MenuListContext = React.createContext<MenuListContextValue>({
10
+ isCheckedControlled: false,
11
+ checked: {},
12
+ defaultChecked: {},
13
+ hasCheckmarks: false,
14
+ onCheckedChange: () => false,
15
+ });
16
+
17
+ export const MenuListProvider = MenuListContext.Provider;
18
+ export const useMenuListContext = () => React.useContext(MenuListContext);
package/src/index.ts CHANGED
@@ -2,4 +2,6 @@ export { Menu } from './Menu/Menu';
2
2
  export { MenuTrigger } from './MenuTrigger/MenuTrigger';
3
3
  export { MenuPopover } from './MenuPopover/MenuPopover';
4
4
  export { MenuItem } from './MenuItem/MenuItem';
5
+ export { MenuItemCheckbox } from './MenuItemCheckbox/MenuItemCheckbox';
5
6
  export { MenuList } from './MenuList/MenuList';
7
+ export { MenuDivider } from './MenuDivider/MenuDivider';
@@ -1 +0,0 @@
1
- //# sourceMappingURL=menuTriggerContext.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"menuTriggerContext.d.ts","sourceRoot":"","sources":["../../src/context/menuTriggerContext.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- "use strict";
2
- //# sourceMappingURL=menuTriggerContext.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"menuTriggerContext.js","sourceRoot":"","sources":["../../src/context/menuTriggerContext.ts"],"names":[],"mappings":""}
@@ -1 +0,0 @@
1
- //# sourceMappingURL=menuTriggerContext.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"menuTriggerContext.d.ts","sourceRoot":"","sources":["../../src/context/menuTriggerContext.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- "use strict";
2
- //# sourceMappingURL=menuTriggerContext.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"menuTriggerContext.js","sourceRoot":"","sources":["../../src/context/menuTriggerContext.ts"],"names":[],"mappings":""}
File without changes