@fluentui-react-native/menu 1.4.33 → 1.5.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.
- package/CHANGELOG.json +67 -1
- package/CHANGELOG.md +24 -2
- package/lib/Menu/Menu.d.ts.map +1 -1
- package/lib/Menu/Menu.js +2 -6
- package/lib/Menu/Menu.js.map +1 -1
- package/lib/Menu/Menu.types.d.ts +20 -1
- package/lib/Menu/Menu.types.d.ts.map +1 -1
- package/lib/Menu/Menu.types.js +6 -0
- package/lib/Menu/Menu.types.js.map +1 -1
- package/lib/Menu/renderMenu.android.d.ts +5 -0
- package/lib/Menu/renderMenu.android.d.ts.map +1 -0
- package/lib/Menu/renderMenu.android.js +14 -0
- package/lib/Menu/renderMenu.android.js.map +1 -0
- package/lib/Menu/renderMenu.d.ts +5 -0
- package/lib/Menu/renderMenu.d.ts.map +1 -0
- package/lib/Menu/renderMenu.js +10 -0
- package/lib/Menu/renderMenu.js.map +1 -0
- package/lib/Menu/useMenu.android.d.ts +3 -0
- package/lib/Menu/useMenu.android.d.ts.map +1 -0
- package/lib/Menu/useMenu.android.js +257 -0
- package/lib/Menu/useMenu.android.js.map +1 -0
- package/lib/MenuCallout/MenuCallout.android.d.ts +4 -0
- package/lib/MenuCallout/MenuCallout.android.d.ts.map +1 -0
- package/lib/MenuCallout/MenuCallout.android.js +33 -0
- package/lib/MenuCallout/MenuCallout.android.js.map +1 -0
- package/lib/MenuCallout/MenuCallout.d.ts +4 -0
- package/lib/MenuCallout/MenuCallout.d.ts.map +1 -0
- package/lib/MenuCallout/MenuCallout.js +15 -0
- package/lib/MenuCallout/MenuCallout.js.map +1 -0
- package/lib/MenuCallout/MenuCallout.types.d.ts +18 -0
- package/lib/MenuCallout/MenuCallout.types.d.ts.map +1 -0
- package/lib/MenuCallout/MenuCallout.types.js +2 -0
- package/lib/MenuCallout/MenuCallout.types.js.map +1 -0
- package/lib/MenuCallout/index.d.ts +4 -0
- package/lib/MenuCallout/index.d.ts.map +1 -0
- package/lib/MenuCallout/index.js +3 -0
- package/lib/MenuCallout/index.js.map +1 -0
- package/lib/MenuDivider/MenuDivider.d.ts +2 -1
- package/lib/MenuDivider/MenuDivider.d.ts.map +1 -1
- package/lib/MenuDivider/MenuDivider.styling.d.ts.map +1 -1
- package/lib/MenuDivider/MenuDivider.styling.js +4 -8
- package/lib/MenuDivider/MenuDivider.styling.js.map +1 -1
- package/lib/MenuDivider/MenuDivider.types.d.ts +6 -1
- package/lib/MenuDivider/MenuDivider.types.d.ts.map +1 -1
- package/lib/MenuDivider/MenuDivider.types.js +1 -0
- package/lib/MenuDivider/MenuDivider.types.js.map +1 -1
- package/lib/MenuDivider/MenuDividerTokens.android.d.ts +5 -0
- package/lib/MenuDivider/MenuDividerTokens.android.d.ts.map +1 -0
- package/lib/MenuDivider/MenuDividerTokens.android.js +7 -0
- package/lib/MenuDivider/MenuDividerTokens.android.js.map +1 -0
- package/lib/MenuDivider/index.d.ts +1 -1
- package/lib/MenuDivider/index.d.ts.map +1 -1
- package/lib/MenuItem/MenuItem.styling.d.ts.map +1 -1
- package/lib/MenuItem/MenuItem.styling.js +2 -1
- package/lib/MenuItem/MenuItem.styling.js.map +1 -1
- package/lib/MenuItem/MenuItem.types.d.ts +4 -0
- package/lib/MenuItem/MenuItem.types.d.ts.map +1 -1
- package/lib/MenuItem/MenuItemTokens.android.d.ts +5 -0
- package/lib/MenuItem/MenuItemTokens.android.d.ts.map +1 -0
- package/lib/MenuItem/MenuItemTokens.android.js +20 -0
- package/lib/MenuItem/MenuItemTokens.android.js.map +1 -0
- package/lib/MenuItem/useMenuItem.d.ts.map +1 -1
- package/lib/MenuItem/useMenuItem.js.map +1 -1
- package/lib/MenuItemCheckbox/MenuItemCheckbox.d.ts.map +1 -1
- package/lib/MenuItemCheckbox/MenuItemCheckbox.js +5 -10
- package/lib/MenuItemCheckbox/MenuItemCheckbox.js.map +1 -1
- package/lib/MenuItemCheckbox/MenuItemCheckbox.styling.d.ts.map +1 -1
- package/lib/MenuItemCheckbox/MenuItemCheckbox.styling.js +25 -20
- package/lib/MenuItemCheckbox/MenuItemCheckbox.styling.js.map +1 -1
- package/lib/MenuItemCheckbox/MenuItemCheckbox.types.d.ts +40 -0
- package/lib/MenuItemCheckbox/MenuItemCheckbox.types.d.ts.map +1 -1
- package/lib/MenuItemCheckbox/MenuItemCheckboxTokens.android.d.ts +5 -0
- package/lib/MenuItemCheckbox/MenuItemCheckboxTokens.android.d.ts.map +1 -0
- package/lib/MenuItemCheckbox/MenuItemCheckboxTokens.android.js +41 -0
- package/lib/MenuItemCheckbox/MenuItemCheckboxTokens.android.js.map +1 -0
- package/lib/MenuItemRadio/MenuItemRadio.d.ts +6 -3
- package/lib/MenuItemRadio/MenuItemRadio.d.ts.map +1 -1
- package/lib/MenuItemRadio/MenuItemRadio.js +37 -9
- package/lib/MenuItemRadio/MenuItemRadio.js.map +1 -1
- package/lib/MenuItemRadio/MenuItemRadio.styling.android.d.ts +6 -0
- package/lib/MenuItemRadio/MenuItemRadio.styling.android.d.ts.map +1 -0
- package/lib/MenuItemRadio/MenuItemRadio.styling.android.js +57 -0
- package/lib/MenuItemRadio/MenuItemRadio.styling.android.js.map +1 -0
- package/lib/MenuItemRadio/MenuItemRadio.styling.d.ts +5 -0
- package/lib/MenuItemRadio/MenuItemRadio.styling.d.ts.map +1 -0
- package/lib/MenuItemRadio/MenuItemRadio.styling.js +37 -0
- package/lib/MenuItemRadio/MenuItemRadio.styling.js.map +1 -0
- package/lib/MenuItemRadio/MenuItemRadio.types.d.ts +162 -0
- package/lib/MenuItemRadio/MenuItemRadio.types.d.ts.map +1 -0
- package/lib/MenuItemRadio/MenuItemRadio.types.js +2 -0
- package/lib/MenuItemRadio/MenuItemRadio.types.js.map +1 -0
- package/lib/MenuItemRadio/MenuItemRadioTokens.android.d.ts +5 -0
- package/lib/MenuItemRadio/MenuItemRadioTokens.android.d.ts.map +1 -0
- package/lib/MenuItemRadio/MenuItemRadioTokens.android.js +44 -0
- package/lib/MenuItemRadio/MenuItemRadioTokens.android.js.map +1 -0
- package/lib/MenuItemRadio/MenuItemRadioTokens.d.ts +5 -0
- package/lib/MenuItemRadio/MenuItemRadioTokens.d.ts.map +1 -0
- package/lib/MenuItemRadio/MenuItemRadioTokens.js +52 -0
- package/lib/MenuItemRadio/MenuItemRadioTokens.js.map +1 -0
- package/lib/MenuItemRadio/index.d.ts +2 -1
- package/lib/MenuItemRadio/index.d.ts.map +1 -1
- package/lib/MenuItemRadio/index.js +1 -1
- package/lib/MenuItemRadio/index.js.map +1 -1
- package/lib/MenuItemRadio/useMenuItemRadio.d.ts +2 -2
- package/lib/MenuItemRadio/useMenuItemRadio.d.ts.map +1 -1
- package/lib/MenuItemRadio/useMenuItemRadio.js.map +1 -1
- package/lib/MenuList/MenuList.styling.d.ts.map +1 -1
- package/lib/MenuList/MenuList.styling.js +2 -1
- package/lib/MenuList/MenuList.styling.js.map +1 -1
- package/lib/MenuList/MenuList.types.d.ts +4 -0
- package/lib/MenuList/MenuList.types.d.ts.map +1 -1
- package/lib/MenuList/MenuListTokens.android.d.ts +5 -0
- package/lib/MenuList/MenuListTokens.android.d.ts.map +1 -0
- package/lib/MenuList/MenuListTokens.android.js +7 -0
- package/lib/MenuList/MenuListTokens.android.js.map +1 -0
- package/lib/MenuPopover/MenuPopover.d.ts +4 -2
- package/lib/MenuPopover/MenuPopover.d.ts.map +1 -1
- package/lib/MenuPopover/MenuPopover.js +2 -2
- package/lib/MenuPopover/MenuPopover.js.map +1 -1
- package/lib/MenuPopover/MenuPopover.types.d.ts +12 -1
- package/lib/MenuPopover/MenuPopover.types.d.ts.map +1 -1
- package/lib/MenuPopover/MenuPopoverTokens.android.d.ts +5 -0
- package/lib/MenuPopover/MenuPopoverTokens.android.d.ts.map +1 -0
- package/lib/MenuPopover/MenuPopoverTokens.android.js +14 -0
- package/lib/MenuPopover/MenuPopoverTokens.android.js.map +1 -0
- package/lib/MenuPopover/MenuPopoverTokens.d.ts +4 -2
- package/lib/MenuPopover/MenuPopoverTokens.d.ts.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib-commonjs/Menu/Menu.d.ts.map +1 -1
- package/lib-commonjs/Menu/Menu.js +2 -6
- package/lib-commonjs/Menu/Menu.js.map +1 -1
- package/lib-commonjs/Menu/Menu.types.d.ts +20 -1
- package/lib-commonjs/Menu/Menu.types.d.ts.map +1 -1
- package/lib-commonjs/Menu/Menu.types.js +7 -1
- package/lib-commonjs/Menu/Menu.types.js.map +1 -1
- package/lib-commonjs/Menu/renderMenu.android.d.ts +5 -0
- package/lib-commonjs/Menu/renderMenu.android.d.ts.map +1 -0
- package/lib-commonjs/Menu/renderMenu.android.js +19 -0
- package/lib-commonjs/Menu/renderMenu.android.js.map +1 -0
- package/lib-commonjs/Menu/renderMenu.d.ts +5 -0
- package/lib-commonjs/Menu/renderMenu.d.ts.map +1 -0
- package/lib-commonjs/Menu/renderMenu.js +15 -0
- package/lib-commonjs/Menu/renderMenu.js.map +1 -0
- package/lib-commonjs/Menu/useMenu.android.d.ts +3 -0
- package/lib-commonjs/Menu/useMenu.android.d.ts.map +1 -0
- package/lib-commonjs/Menu/useMenu.android.js +261 -0
- package/lib-commonjs/Menu/useMenu.android.js.map +1 -0
- package/lib-commonjs/MenuCallout/MenuCallout.android.d.ts +4 -0
- package/lib-commonjs/MenuCallout/MenuCallout.android.d.ts.map +1 -0
- package/lib-commonjs/MenuCallout/MenuCallout.android.js +36 -0
- package/lib-commonjs/MenuCallout/MenuCallout.android.js.map +1 -0
- package/lib-commonjs/MenuCallout/MenuCallout.d.ts +4 -0
- package/lib-commonjs/MenuCallout/MenuCallout.d.ts.map +1 -0
- package/lib-commonjs/MenuCallout/MenuCallout.js +18 -0
- package/lib-commonjs/MenuCallout/MenuCallout.js.map +1 -0
- package/lib-commonjs/MenuCallout/MenuCallout.types.d.ts +18 -0
- package/lib-commonjs/MenuCallout/MenuCallout.types.d.ts.map +1 -0
- package/lib-commonjs/MenuCallout/MenuCallout.types.js +5 -0
- package/lib-commonjs/MenuCallout/MenuCallout.types.js.map +1 -0
- package/lib-commonjs/MenuCallout/index.d.ts +4 -0
- package/lib-commonjs/MenuCallout/index.d.ts.map +1 -0
- package/lib-commonjs/MenuCallout/index.js +8 -0
- package/lib-commonjs/MenuCallout/index.js.map +1 -0
- package/lib-commonjs/MenuDivider/MenuDivider.d.ts +2 -1
- package/lib-commonjs/MenuDivider/MenuDivider.d.ts.map +1 -1
- package/lib-commonjs/MenuDivider/MenuDivider.styling.d.ts.map +1 -1
- package/lib-commonjs/MenuDivider/MenuDivider.styling.js +4 -8
- package/lib-commonjs/MenuDivider/MenuDivider.styling.js.map +1 -1
- package/lib-commonjs/MenuDivider/MenuDivider.types.d.ts +6 -1
- package/lib-commonjs/MenuDivider/MenuDivider.types.d.ts.map +1 -1
- package/lib-commonjs/MenuDivider/MenuDivider.types.js +2 -1
- package/lib-commonjs/MenuDivider/MenuDivider.types.js.map +1 -1
- package/lib-commonjs/MenuDivider/MenuDividerTokens.android.d.ts +5 -0
- package/lib-commonjs/MenuDivider/MenuDividerTokens.android.d.ts.map +1 -0
- package/lib-commonjs/MenuDivider/MenuDividerTokens.android.js +11 -0
- package/lib-commonjs/MenuDivider/MenuDividerTokens.android.js.map +1 -0
- package/lib-commonjs/MenuDivider/index.d.ts +1 -1
- package/lib-commonjs/MenuDivider/index.d.ts.map +1 -1
- package/lib-commonjs/MenuItem/MenuItem.styling.d.ts.map +1 -1
- package/lib-commonjs/MenuItem/MenuItem.styling.js +2 -1
- package/lib-commonjs/MenuItem/MenuItem.styling.js.map +1 -1
- package/lib-commonjs/MenuItem/MenuItem.types.d.ts +4 -0
- package/lib-commonjs/MenuItem/MenuItem.types.d.ts.map +1 -1
- package/lib-commonjs/MenuItem/MenuItemTokens.android.d.ts +5 -0
- package/lib-commonjs/MenuItem/MenuItemTokens.android.d.ts.map +1 -0
- package/lib-commonjs/MenuItem/MenuItemTokens.android.js +24 -0
- package/lib-commonjs/MenuItem/MenuItemTokens.android.js.map +1 -0
- package/lib-commonjs/MenuItem/useMenuItem.d.ts.map +1 -1
- package/lib-commonjs/MenuItem/useMenuItem.js.map +1 -1
- package/lib-commonjs/MenuItemCheckbox/MenuItemCheckbox.d.ts.map +1 -1
- package/lib-commonjs/MenuItemCheckbox/MenuItemCheckbox.js +4 -9
- package/lib-commonjs/MenuItemCheckbox/MenuItemCheckbox.js.map +1 -1
- package/lib-commonjs/MenuItemCheckbox/MenuItemCheckbox.styling.d.ts.map +1 -1
- package/lib-commonjs/MenuItemCheckbox/MenuItemCheckbox.styling.js +25 -20
- package/lib-commonjs/MenuItemCheckbox/MenuItemCheckbox.styling.js.map +1 -1
- package/lib-commonjs/MenuItemCheckbox/MenuItemCheckbox.types.d.ts +40 -0
- package/lib-commonjs/MenuItemCheckbox/MenuItemCheckbox.types.d.ts.map +1 -1
- package/lib-commonjs/MenuItemCheckbox/MenuItemCheckboxTokens.android.d.ts +5 -0
- package/lib-commonjs/MenuItemCheckbox/MenuItemCheckboxTokens.android.d.ts.map +1 -0
- package/lib-commonjs/MenuItemCheckbox/MenuItemCheckboxTokens.android.js +45 -0
- package/lib-commonjs/MenuItemCheckbox/MenuItemCheckboxTokens.android.js.map +1 -0
- package/lib-commonjs/MenuItemRadio/MenuItemRadio.d.ts +6 -3
- package/lib-commonjs/MenuItemRadio/MenuItemRadio.d.ts.map +1 -1
- package/lib-commonjs/MenuItemRadio/MenuItemRadio.js +39 -10
- package/lib-commonjs/MenuItemRadio/MenuItemRadio.js.map +1 -1
- package/lib-commonjs/MenuItemRadio/MenuItemRadio.styling.android.d.ts +6 -0
- package/lib-commonjs/MenuItemRadio/MenuItemRadio.styling.android.d.ts.map +1 -0
- package/lib-commonjs/MenuItemRadio/MenuItemRadio.styling.android.js +60 -0
- package/lib-commonjs/MenuItemRadio/MenuItemRadio.styling.android.js.map +1 -0
- package/lib-commonjs/MenuItemRadio/MenuItemRadio.styling.d.ts +5 -0
- package/lib-commonjs/MenuItemRadio/MenuItemRadio.styling.d.ts.map +1 -0
- package/lib-commonjs/MenuItemRadio/MenuItemRadio.styling.js +40 -0
- package/lib-commonjs/MenuItemRadio/MenuItemRadio.styling.js.map +1 -0
- package/lib-commonjs/MenuItemRadio/MenuItemRadio.types.d.ts +162 -0
- package/lib-commonjs/MenuItemRadio/MenuItemRadio.types.d.ts.map +1 -0
- package/lib-commonjs/MenuItemRadio/MenuItemRadio.types.js +5 -0
- package/lib-commonjs/MenuItemRadio/MenuItemRadio.types.js.map +1 -0
- package/lib-commonjs/MenuItemRadio/MenuItemRadioTokens.android.d.ts +5 -0
- package/lib-commonjs/MenuItemRadio/MenuItemRadioTokens.android.d.ts.map +1 -0
- package/lib-commonjs/MenuItemRadio/MenuItemRadioTokens.android.js +48 -0
- package/lib-commonjs/MenuItemRadio/MenuItemRadioTokens.android.js.map +1 -0
- package/lib-commonjs/MenuItemRadio/MenuItemRadioTokens.d.ts +5 -0
- package/lib-commonjs/MenuItemRadio/MenuItemRadioTokens.d.ts.map +1 -0
- package/lib-commonjs/MenuItemRadio/MenuItemRadioTokens.js +56 -0
- package/lib-commonjs/MenuItemRadio/MenuItemRadioTokens.js.map +1 -0
- package/lib-commonjs/MenuItemRadio/index.d.ts +2 -1
- package/lib-commonjs/MenuItemRadio/index.d.ts.map +1 -1
- package/lib-commonjs/MenuItemRadio/index.js +1 -2
- package/lib-commonjs/MenuItemRadio/index.js.map +1 -1
- package/lib-commonjs/MenuItemRadio/useMenuItemRadio.d.ts +2 -2
- package/lib-commonjs/MenuItemRadio/useMenuItemRadio.d.ts.map +1 -1
- package/lib-commonjs/MenuItemRadio/useMenuItemRadio.js.map +1 -1
- package/lib-commonjs/MenuList/MenuList.styling.d.ts.map +1 -1
- package/lib-commonjs/MenuList/MenuList.styling.js +2 -1
- package/lib-commonjs/MenuList/MenuList.styling.js.map +1 -1
- package/lib-commonjs/MenuList/MenuList.types.d.ts +4 -0
- package/lib-commonjs/MenuList/MenuList.types.d.ts.map +1 -1
- package/lib-commonjs/MenuList/MenuListTokens.android.d.ts +5 -0
- package/lib-commonjs/MenuList/MenuListTokens.android.d.ts.map +1 -0
- package/lib-commonjs/MenuList/MenuListTokens.android.js +11 -0
- package/lib-commonjs/MenuList/MenuListTokens.android.js.map +1 -0
- package/lib-commonjs/MenuPopover/MenuPopover.d.ts +4 -2
- package/lib-commonjs/MenuPopover/MenuPopover.d.ts.map +1 -1
- package/lib-commonjs/MenuPopover/MenuPopover.js +2 -2
- package/lib-commonjs/MenuPopover/MenuPopover.js.map +1 -1
- package/lib-commonjs/MenuPopover/MenuPopover.types.d.ts +12 -1
- package/lib-commonjs/MenuPopover/MenuPopover.types.d.ts.map +1 -1
- package/lib-commonjs/MenuPopover/MenuPopoverTokens.android.d.ts +5 -0
- package/lib-commonjs/MenuPopover/MenuPopoverTokens.android.d.ts.map +1 -0
- package/lib-commonjs/MenuPopover/MenuPopoverTokens.android.js +17 -0
- package/lib-commonjs/MenuPopover/MenuPopoverTokens.android.js.map +1 -0
- package/lib-commonjs/MenuPopover/MenuPopoverTokens.d.ts +4 -2
- package/lib-commonjs/MenuPopover/MenuPopoverTokens.d.ts.map +1 -1
- package/lib-commonjs/index.d.ts +1 -1
- package/lib-commonjs/index.d.ts.map +1 -1
- package/lib-commonjs/index.js +1 -2
- package/lib-commonjs/index.js.map +1 -1
- package/package.json +7 -7
- package/src/Menu/Menu.tsx +3 -13
- package/src/Menu/Menu.types.ts +22 -1
- package/src/Menu/renderMenu.android.tsx +26 -0
- package/src/Menu/renderMenu.tsx +18 -0
- package/src/Menu/useMenu.android.ts +325 -0
- package/src/MenuCallout/MenuCallout.android.tsx +60 -0
- package/src/MenuCallout/MenuCallout.tsx +20 -0
- package/src/MenuCallout/MenuCallout.types.ts +22 -0
- package/src/MenuCallout/index.ts +3 -0
- package/src/MenuDivider/MenuDivider.styling.ts +4 -0
- package/src/MenuDivider/MenuDivider.types.ts +7 -1
- package/src/MenuDivider/MenuDividerTokens.android.ts +11 -0
- package/src/MenuDivider/index.ts +1 -1
- package/src/MenuItem/MenuItem.styling.ts +3 -1
- package/src/MenuItem/MenuItem.types.ts +5 -0
- package/src/MenuItem/MenuItemTokens.android.ts +24 -0
- package/src/MenuItem/useMenuItem.ts +0 -1
- package/src/MenuItemCheckbox/MenuItemCheckbox.styling.ts +29 -2
- package/src/MenuItemCheckbox/MenuItemCheckbox.tsx +15 -2
- package/src/MenuItemCheckbox/MenuItemCheckbox.types.ts +47 -0
- package/src/MenuItemCheckbox/MenuItemCheckboxTokens.android.ts +46 -0
- package/src/MenuItemRadio/MenuItemRadio.styling.android.ts +98 -0
- package/src/MenuItemRadio/MenuItemRadio.styling.ts +75 -0
- package/src/MenuItemRadio/MenuItemRadio.tsx +68 -9
- package/src/MenuItemRadio/MenuItemRadio.types.ts +190 -0
- package/src/MenuItemRadio/MenuItemRadioTokens.android.ts +51 -0
- package/src/MenuItemRadio/MenuItemRadioTokens.ts +56 -0
- package/src/MenuItemRadio/index.ts +9 -1
- package/src/MenuItemRadio/useMenuItemRadio.ts +2 -2
- package/src/MenuList/MenuList.styling.ts +3 -0
- package/src/MenuList/MenuList.types.ts +5 -0
- package/src/MenuList/MenuListTokens.android.ts +11 -0
- package/src/MenuPopover/MenuPopover.tsx +6 -2
- package/src/MenuPopover/MenuPopover.types.ts +14 -1
- package/src/MenuPopover/MenuPopoverTokens.android.ts +21 -0
- package/src/index.ts +10 -1
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
|
2
|
+
import type { LayoutChangeEvent, View } from 'react-native';
|
|
3
|
+
import { Animated, Dimensions, Easing, I18nManager, StatusBar } from 'react-native';
|
|
4
|
+
|
|
5
|
+
import type { InteractionEvent } from '@fluentui-react-native/interactive-hooks';
|
|
6
|
+
|
|
7
|
+
import type { MenuProps, MenuState } from './Menu.types';
|
|
8
|
+
import { AndroidMenuStates } from './Menu.types';
|
|
9
|
+
import { useMenuContext } from '../context/menuContext';
|
|
10
|
+
|
|
11
|
+
// Due to how events get fired we get double notifications
|
|
12
|
+
// for the same event causing us to immediately reopen
|
|
13
|
+
// a menu when we close it. Adding in a delay to prevent
|
|
14
|
+
// this behavior.
|
|
15
|
+
// This are use when show() function is called to show the Menu
|
|
16
|
+
const delayOpen = 150;
|
|
17
|
+
let lastCloseTimestamp = -1;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Values related to Screen Width and Animation Easing
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
// Animated easing value for Menu transitions(close and open)
|
|
24
|
+
const EASING = Easing.bezier(0.4, 0, 0.2, 1);
|
|
25
|
+
|
|
26
|
+
// Screen indent is the fixed value according to Android guidelines which depicts the minimum distance from screen edge Menu should have
|
|
27
|
+
const SCREEN_INDENT = 16;
|
|
28
|
+
|
|
29
|
+
export const useMenu = (props: MenuProps): MenuState => {
|
|
30
|
+
/**
|
|
31
|
+
* State , Ref and Context Values for Menu Container and Anchor
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
const triggerRef = React.useRef();
|
|
35
|
+
const context = useMenuContext();
|
|
36
|
+
const isSubmenu = context.triggerRef !== null;
|
|
37
|
+
const isOpenControlled = typeof props.open !== 'undefined';
|
|
38
|
+
const _container = useRef<View>(null);
|
|
39
|
+
const [menuState, setMenuState] = React.useState<AndroidMenuStates>(AndroidMenuStates.Hidden);
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Call for useMenuCheckedState for identifying if any MenuItemCheckbox is checked or not
|
|
43
|
+
*/
|
|
44
|
+
const [checked, onCheckedChange] = useMenuCheckedState(props);
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* State Variables related to Height,Width and Position of the Menu Popover
|
|
48
|
+
*/
|
|
49
|
+
const [maxMenuHeight] = useState(250);
|
|
50
|
+
const [anchorWidth, setAnchorWidth] = React.useState<number>(0);
|
|
51
|
+
const [left, setLeft] = React.useState<number>(0);
|
|
52
|
+
const [menuHeight, setMenuHeight] = React.useState<number>(0);
|
|
53
|
+
const [menuWidth, setMenuWidth] = React.useState<number>(0);
|
|
54
|
+
const [top, setTop] = React.useState<number>(0);
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Animation value for the Menu popover show,hide and opacity values
|
|
58
|
+
*/
|
|
59
|
+
const [menuSizeAnimation, setMenuSizeAnimation] = React.useState<Animated.ValueXY>(new Animated.ValueXY({ x: 0, y: 0 }));
|
|
60
|
+
const [opacityAnimation, setOpacityAnimation] = React.useState<Animated.Value>(new Animated.Value(0));
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* RTL for the MenuItem needs to taken care as well.
|
|
64
|
+
*/
|
|
65
|
+
const { isRTL } = I18nManager;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Calcualations related to Menu Popver position and dimensions
|
|
69
|
+
*/
|
|
70
|
+
const dimensions = Dimensions.get('screen');
|
|
71
|
+
const { width: windowWidth } = dimensions;
|
|
72
|
+
const windowHeight = dimensions.height - (StatusBar.currentHeight || 0);
|
|
73
|
+
const menuSize = {
|
|
74
|
+
width: menuSizeAnimation.x,
|
|
75
|
+
height: menuSizeAnimation.y,
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* show function handles the opening of the Menu , it calcuates the position of the Anchor in the screen.
|
|
80
|
+
* It also sets the Anchor width and change the state of the Popover
|
|
81
|
+
*/ /**
|
|
82
|
+
* show function handles the opening of the Menu , it calcuates the position of the Anchor in the screen.
|
|
83
|
+
* It also sets the Anchor width and change the state of the Popover
|
|
84
|
+
*/
|
|
85
|
+
|
|
86
|
+
const show = React.useCallback(() => {
|
|
87
|
+
_container.current?.measureInWindow((left, top, buttonWidth, buttonHeight) => {
|
|
88
|
+
setAnchorWidth(buttonWidth);
|
|
89
|
+
setLeft(left);
|
|
90
|
+
setMenuState(AndroidMenuStates.Shown);
|
|
91
|
+
setTop(top + buttonHeight);
|
|
92
|
+
});
|
|
93
|
+
}, []);
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* hide function handles the hiding of the Menu when user clicks on the scrim outside Menu or MenuItems such as (MenuItemRadio, MenuItem)
|
|
97
|
+
*/
|
|
98
|
+
const hide = React.useCallback(() => {
|
|
99
|
+
Animated.timing(opacityAnimation, {
|
|
100
|
+
toValue: 0,
|
|
101
|
+
duration: 250,
|
|
102
|
+
easing: EASING,
|
|
103
|
+
useNativeDriver: false,
|
|
104
|
+
}).start(() => {
|
|
105
|
+
// Reset state
|
|
106
|
+
setMenuState(AndroidMenuStates.Hidden);
|
|
107
|
+
setMenuSizeAnimation(new Animated.ValueXY({ x: 0, y: 0 }));
|
|
108
|
+
setOpacityAnimation(new Animated.Value(0));
|
|
109
|
+
});
|
|
110
|
+
}, [opacityAnimation]);
|
|
111
|
+
|
|
112
|
+
// Hook to maintain the state of the Menu for non controlled and controlled components.
|
|
113
|
+
const [open, shouldFocusOnContainer, setOpen] = useMenuOpenState(isOpenControlled, props, context.setOpen, hide, show);
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Checks the value of the open props and show the menu accordingly
|
|
117
|
+
*/
|
|
118
|
+
useEffect(() => {
|
|
119
|
+
if (props.open) {
|
|
120
|
+
show();
|
|
121
|
+
}
|
|
122
|
+
}, [props.open]);
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* onMenuLayout handles the start of the Animation when anchor is clicked
|
|
126
|
+
*/
|
|
127
|
+
const onMenuLayout = React.useCallback(
|
|
128
|
+
(e: LayoutChangeEvent) => {
|
|
129
|
+
if (menuState === AndroidMenuStates.Animating) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
const { width, height } = e.nativeEvent.layout;
|
|
133
|
+
setMenuHeight(height);
|
|
134
|
+
setMenuWidth(width);
|
|
135
|
+
setMenuState(AndroidMenuStates.Animating);
|
|
136
|
+
Animated.parallel([
|
|
137
|
+
Animated.timing(menuSizeAnimation, {
|
|
138
|
+
toValue: { x: width, y: height },
|
|
139
|
+
duration: 100,
|
|
140
|
+
easing: EASING,
|
|
141
|
+
useNativeDriver: false,
|
|
142
|
+
}),
|
|
143
|
+
Animated.timing(opacityAnimation, {
|
|
144
|
+
toValue: 1,
|
|
145
|
+
duration: 100,
|
|
146
|
+
easing: EASING,
|
|
147
|
+
useNativeDriver: false,
|
|
148
|
+
}),
|
|
149
|
+
]).start();
|
|
150
|
+
},
|
|
151
|
+
[menuSizeAnimation, menuState, opacityAnimation],
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* onRequestClose handles the closing of the Menu when the MenuItem or scrim or outside is clicked
|
|
156
|
+
*/
|
|
157
|
+
const onRequestClose = (e: InteractionEvent) => {
|
|
158
|
+
setOpen(e, false, false);
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
// Adjust position of menu
|
|
162
|
+
const transforms = [];
|
|
163
|
+
|
|
164
|
+
useMemo(() => {
|
|
165
|
+
/**
|
|
166
|
+
* If the Menu width and SCREEN_INDENT cross the screen width then the Menu will be adjusted to the oppostion left side of the screen
|
|
167
|
+
*/
|
|
168
|
+
if ((isRTL && left + anchorWidth - menuWidth > SCREEN_INDENT) || (!isRTL && left + menuWidth > windowWidth - SCREEN_INDENT)) {
|
|
169
|
+
transforms.push({
|
|
170
|
+
translateX: Animated.multiply(menuSizeAnimation.x, -1),
|
|
171
|
+
});
|
|
172
|
+
} else if (left < SCREEN_INDENT) {
|
|
173
|
+
// Setting the left podition of the Menu if the left positon is less than screen indent
|
|
174
|
+
setLeft(SCREEN_INDENT);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Flip by Y axis if menu hits bottom screen border
|
|
178
|
+
if (top + menuHeight + SCREEN_INDENT > windowHeight) {
|
|
179
|
+
if (menuHeight > maxMenuHeight) {
|
|
180
|
+
transforms.push({
|
|
181
|
+
translateY: Animated.multiply(menuSizeAnimation.y, -1),
|
|
182
|
+
});
|
|
183
|
+
} else {
|
|
184
|
+
transforms.push({
|
|
185
|
+
translateY: Animated.multiply(menuSizeAnimation.y, -1),
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
} else if (top < SCREEN_INDENT) {
|
|
189
|
+
setTop(SCREEN_INDENT);
|
|
190
|
+
}
|
|
191
|
+
}, [
|
|
192
|
+
anchorWidth,
|
|
193
|
+
isRTL,
|
|
194
|
+
left,
|
|
195
|
+
maxMenuHeight,
|
|
196
|
+
menuHeight,
|
|
197
|
+
menuSizeAnimation.x,
|
|
198
|
+
menuSizeAnimation.y,
|
|
199
|
+
menuWidth,
|
|
200
|
+
top,
|
|
201
|
+
transforms,
|
|
202
|
+
windowHeight,
|
|
203
|
+
windowWidth,
|
|
204
|
+
]);
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Styles to be applied on the Modal Popover Animated.View
|
|
208
|
+
*/
|
|
209
|
+
const shadowMenuContainerStyle = useMemo(() => {
|
|
210
|
+
return {
|
|
211
|
+
opacity: opacityAnimation,
|
|
212
|
+
transform: transforms,
|
|
213
|
+
top,
|
|
214
|
+
// Switch left to right for rtl devices
|
|
215
|
+
...(isRTL ? { right: left } : { left }),
|
|
216
|
+
};
|
|
217
|
+
}, [isRTL, left, opacityAnimation, top, transforms]);
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* handles the state when menu is opening or closing with Animation
|
|
221
|
+
*/
|
|
222
|
+
const animationStarted = menuState === AndroidMenuStates.Animating;
|
|
223
|
+
const { testID } = props;
|
|
224
|
+
|
|
225
|
+
// Default behavior for submenu is to open on hover
|
|
226
|
+
// the ...props line below will override this behavior for a submenu
|
|
227
|
+
// or apply openOnHover if passed into a root Menu.
|
|
228
|
+
const openOnHover = isSubmenu;
|
|
229
|
+
// We need to be able to cancel the timer that gets set on
|
|
230
|
+
// hover out of the parent popover if the parent popover
|
|
231
|
+
// is also set to open/close on hover out. Otherwise
|
|
232
|
+
// the parent menu will close when the timeout passes.
|
|
233
|
+
const parentPopoverHoverOutTimer = isSubmenu ? context.popoverHoverOutTimer : undefined;
|
|
234
|
+
return {
|
|
235
|
+
openOnHover,
|
|
236
|
+
...props,
|
|
237
|
+
open,
|
|
238
|
+
setOpen,
|
|
239
|
+
shouldFocusOnContainer,
|
|
240
|
+
triggerRef,
|
|
241
|
+
isSubmenu,
|
|
242
|
+
isControlled: isOpenControlled,
|
|
243
|
+
parentPopoverHoverOutTimer,
|
|
244
|
+
setAnchorWidth,
|
|
245
|
+
shadowMenuContainerStyle,
|
|
246
|
+
_container,
|
|
247
|
+
onRequestClose,
|
|
248
|
+
onMenuLayout,
|
|
249
|
+
checked,
|
|
250
|
+
onCheckedChange,
|
|
251
|
+
menuHeight,
|
|
252
|
+
maxMenuHeight,
|
|
253
|
+
animationStarted,
|
|
254
|
+
menuSize,
|
|
255
|
+
testID,
|
|
256
|
+
};
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* useMenuOpenState handles the open and closing of the Menu based on the click
|
|
261
|
+
* It also takes care of Controlled Menu component by checking open variable
|
|
262
|
+
*
|
|
263
|
+
*/
|
|
264
|
+
const useMenuOpenState = (
|
|
265
|
+
isControlled: boolean,
|
|
266
|
+
props: MenuProps,
|
|
267
|
+
parentSetOpen: (e: InteractionEvent, isOpen: boolean, bubble?: boolean) => void,
|
|
268
|
+
hide: () => void,
|
|
269
|
+
show: () => void,
|
|
270
|
+
): [boolean, boolean, (e: InteractionEvent, isOpen: boolean, bubble?: boolean) => void] => {
|
|
271
|
+
const { defaultOpen, onOpenChange, open } = props;
|
|
272
|
+
const initialState = typeof defaultOpen !== 'undefined' ? defaultOpen : !!open;
|
|
273
|
+
const [openInternal, setOpenInternal] = React.useState<boolean>(initialState);
|
|
274
|
+
const [shouldFocusOnContainer, setShouldFocusOnContainer] = React.useState<boolean | undefined>(undefined);
|
|
275
|
+
const state = isControlled ? open : openInternal;
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* setOpen handles the open of the Menu and setting focus on the Popover container
|
|
279
|
+
*/
|
|
280
|
+
const setOpen = React.useCallback(
|
|
281
|
+
(e: InteractionEvent, isOpen: boolean, bubble?: boolean) => {
|
|
282
|
+
const openPrev = state;
|
|
283
|
+
if (!isControlled && (!isOpen || lastCloseTimestamp + delayOpen <= Date.now())) {
|
|
284
|
+
setOpenInternal(isOpen);
|
|
285
|
+
}
|
|
286
|
+
if (isOpen) {
|
|
287
|
+
show();
|
|
288
|
+
setShouldFocusOnContainer(true);
|
|
289
|
+
}
|
|
290
|
+
if (!isOpen) {
|
|
291
|
+
setShouldFocusOnContainer(undefined);
|
|
292
|
+
lastCloseTimestamp = Date.now();
|
|
293
|
+
hide();
|
|
294
|
+
}
|
|
295
|
+
if (onOpenChange && openPrev !== isOpen) {
|
|
296
|
+
onOpenChange(e, isOpen);
|
|
297
|
+
}
|
|
298
|
+
if (bubble && parentSetOpen && !isControlled) {
|
|
299
|
+
parentSetOpen(e, isOpen, bubble);
|
|
300
|
+
}
|
|
301
|
+
},
|
|
302
|
+
[state, onOpenChange, parentSetOpen, show, hide],
|
|
303
|
+
);
|
|
304
|
+
return [state, shouldFocusOnContainer, setOpen];
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Call for useMenuCheckedState for identifying if any MenuItemCheckbox is checked or not
|
|
309
|
+
*/
|
|
310
|
+
const useMenuCheckedState = (props: MenuProps): [string[], (e: InteractionEvent, checked: string[]) => void] => {
|
|
311
|
+
const { checked, defaultChecked, onCheckedChange: onCheckedChangeOriginal } = props;
|
|
312
|
+
const [checkedInternal, setCheckedInternal] = React.useState(defaultChecked ?? checked ?? []);
|
|
313
|
+
const isControlled = typeof checked !== 'undefined';
|
|
314
|
+
const state = isControlled ? checked : checkedInternal;
|
|
315
|
+
const onCheckedChange = React.useCallback(
|
|
316
|
+
(e: InteractionEvent, checked: string[]) => {
|
|
317
|
+
if (!isControlled) {
|
|
318
|
+
setCheckedInternal(checked);
|
|
319
|
+
}
|
|
320
|
+
onCheckedChangeOriginal?.(e, checked);
|
|
321
|
+
},
|
|
322
|
+
[isControlled, setCheckedInternal, onCheckedChangeOriginal],
|
|
323
|
+
);
|
|
324
|
+
return [state, onCheckedChange];
|
|
325
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Animated, Modal, TouchableWithoutFeedback, View, StyleSheet, ScrollView } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import { stagedComponent } from '@fluentui-react-native/framework';
|
|
5
|
+
import { mergeProps } from '@fluentui-react-native/framework';
|
|
6
|
+
|
|
7
|
+
import type { MenuCalloutProps } from './MenuCallout.types';
|
|
8
|
+
import { menuCalloutName } from './MenuCallout.types';
|
|
9
|
+
import { useMenuContext } from '../context';
|
|
10
|
+
|
|
11
|
+
const AnimatedScrollView = Animated.createAnimatedComponent(ScrollView);
|
|
12
|
+
|
|
13
|
+
export const MenuCallout = stagedComponent((props: MenuCalloutProps) => {
|
|
14
|
+
const context = useMenuContext();
|
|
15
|
+
|
|
16
|
+
return (_rest: MenuCalloutProps, children: React.ReactNode) => {
|
|
17
|
+
const mergedProps = mergeProps(props, _rest);
|
|
18
|
+
const tokens = props.tokens;
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<Modal
|
|
22
|
+
{...mergedProps}
|
|
23
|
+
visible={context.open}
|
|
24
|
+
onRequestClose={context.onRequestClose}
|
|
25
|
+
supportedOrientations={['portrait', 'portrait-upside-down', 'landscape', 'landscape-left', 'landscape-right']}
|
|
26
|
+
transparent
|
|
27
|
+
>
|
|
28
|
+
<TouchableWithoutFeedback onPress={context.onRequestClose} accessible={false}>
|
|
29
|
+
<View style={[StyleSheet.absoluteFill]}>
|
|
30
|
+
<Animated.View
|
|
31
|
+
onLayout={context.onMenuLayout}
|
|
32
|
+
style={[
|
|
33
|
+
context.shadowMenuContainerStyle,
|
|
34
|
+
{
|
|
35
|
+
maxHeight: mergedProps.maxHeight ? mergedProps.maxHeight : tokens.maxHeight,
|
|
36
|
+
maxWidth: tokens.maxWidth,
|
|
37
|
+
position: 'absolute',
|
|
38
|
+
borderRadius: tokens.cornerRadius,
|
|
39
|
+
elevation: tokens.elevation,
|
|
40
|
+
overflow: 'hidden',
|
|
41
|
+
},
|
|
42
|
+
]}
|
|
43
|
+
>
|
|
44
|
+
{context.menuHeight + tokens.minPadding >= tokens.maxHeight ||
|
|
45
|
+
context.menuHeight + tokens.minPadding >= mergedProps.maxHeight ? (
|
|
46
|
+
<AnimatedScrollView style={[context.animationStarted && context.menuSize]}>{children}</AnimatedScrollView>
|
|
47
|
+
) : (
|
|
48
|
+
<Animated.View style={[context.animationStarted && context.menuSize]}>{children}</Animated.View>
|
|
49
|
+
)}
|
|
50
|
+
</Animated.View>
|
|
51
|
+
</View>
|
|
52
|
+
</TouchableWithoutFeedback>
|
|
53
|
+
</Modal>
|
|
54
|
+
);
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
MenuCallout.displayName = menuCalloutName;
|
|
59
|
+
|
|
60
|
+
export default MenuCallout;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { Callout } from '@fluentui-react-native/callout';
|
|
4
|
+
import { stagedComponent } from '@fluentui-react-native/framework';
|
|
5
|
+
import { mergeProps } from '@fluentui-react-native/framework';
|
|
6
|
+
|
|
7
|
+
import type { MenuCalloutProps } from './MenuCallout.types';
|
|
8
|
+
import { menuCalloutName } from './MenuCallout.types';
|
|
9
|
+
|
|
10
|
+
export const MenuCallout = stagedComponent((props: MenuCalloutProps) => {
|
|
11
|
+
return (_rest: MenuCalloutProps, children: React.ReactNode) => {
|
|
12
|
+
const mergedProps = mergeProps(props, _rest);
|
|
13
|
+
|
|
14
|
+
return <Callout {...mergedProps}>{children}</Callout>;
|
|
15
|
+
};
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
MenuCallout.displayName = menuCalloutName;
|
|
19
|
+
|
|
20
|
+
export default MenuCallout;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ICalloutProps, ICalloutTokens } from '@fluentui-react-native/callout';
|
|
2
|
+
|
|
3
|
+
export const menuCalloutName = 'MenuCallout';
|
|
4
|
+
|
|
5
|
+
// Support for anchorRect and beakWidth will come at a later time.
|
|
6
|
+
// Omitting dismissBehaviors as it doesn't seem to make sense as a token
|
|
7
|
+
export type MenuCalloutTokens =
|
|
8
|
+
| Omit<ICalloutTokens, 'anchorRect' | 'beakWidth' | 'dismissBehaviors'> & {
|
|
9
|
+
/**
|
|
10
|
+
* The token for the corner radius for the Modal MenuPopover
|
|
11
|
+
* @platform android
|
|
12
|
+
*/
|
|
13
|
+
cornerRadius?: number;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Shadown elevation token for the Modal MenuPopover
|
|
17
|
+
* @platform android
|
|
18
|
+
*/
|
|
19
|
+
elevation?: number;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type MenuCalloutProps = ICalloutProps & { tokens: MenuCalloutTokens };
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { Platform } from 'react-native';
|
|
2
|
+
|
|
1
3
|
import type { UseStylingOptions } from '@fluentui-react-native/framework';
|
|
2
4
|
import { buildProps } from '@fluentui-react-native/framework';
|
|
3
5
|
|
|
@@ -7,6 +9,7 @@ import { defaultMenuDividerTokens } from './MenuDividerTokens';
|
|
|
7
9
|
|
|
8
10
|
export const stylingSettings: UseStylingOptions<MenuDividerProps, MenuDividerSlotProps, MenuDividerTokens> = {
|
|
9
11
|
tokens: [defaultMenuDividerTokens, menuDividerName],
|
|
12
|
+
tokensThatAreAlsoProps: ['insetSize'],
|
|
10
13
|
slotProps: {
|
|
11
14
|
root: buildProps(
|
|
12
15
|
(tokens: MenuDividerTokens) => ({
|
|
@@ -17,6 +20,7 @@ export const stylingSettings: UseStylingOptions<MenuDividerProps, MenuDividerSlo
|
|
|
17
20
|
margin: tokens.margin,
|
|
18
21
|
marginVertical: tokens.marginVertical,
|
|
19
22
|
display: 'flex',
|
|
23
|
+
...(Platform.OS === 'android' && { marginStart: tokens.insetSize }),
|
|
20
24
|
},
|
|
21
25
|
}),
|
|
22
26
|
['backgroundColor', 'height', 'margin', 'marginVertical', 'width'],
|
|
@@ -6,14 +6,20 @@ import type { IBackgroundColorTokens } from '@fluentui-react-native/tokens';
|
|
|
6
6
|
|
|
7
7
|
export const menuDividerName = 'MenuDivider';
|
|
8
8
|
|
|
9
|
+
export const MenuDividerInsetSizes = [0, 16, 56, 68, 72, 108] as const;
|
|
10
|
+
export type MenuDividerInsetSize = (typeof MenuDividerInsetSizes)[number];
|
|
11
|
+
|
|
9
12
|
export type MenuDividerTokens = IBackgroundColorTokens & {
|
|
10
13
|
height?: number;
|
|
11
14
|
margin?: number;
|
|
12
15
|
marginVertical?: number;
|
|
13
16
|
width?: ViewStyle['width'];
|
|
17
|
+
insetSize?: MenuDividerInsetSize;
|
|
14
18
|
};
|
|
15
19
|
|
|
16
|
-
export type MenuDividerProps = IViewProps
|
|
20
|
+
export type MenuDividerProps = IViewProps & {
|
|
21
|
+
insetSize?: MenuDividerInsetSize;
|
|
22
|
+
};
|
|
17
23
|
|
|
18
24
|
export interface MenuDividerSlotProps {
|
|
19
25
|
root: React.PropsWithRef<IViewProps>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Theme } from '@fluentui-react-native/framework';
|
|
2
|
+
import { globalTokens } from '@fluentui-react-native/theme-tokens';
|
|
3
|
+
import type { TokenSettings } from '@fluentui-react-native/use-styling';
|
|
4
|
+
|
|
5
|
+
import type { MenuDividerTokens } from './MenuDivider.types';
|
|
6
|
+
|
|
7
|
+
export const defaultMenuDividerTokens: TokenSettings<MenuDividerTokens, Theme> = (t: Theme): MenuDividerTokens => ({
|
|
8
|
+
backgroundColor: t.colors.neutralStroke2,
|
|
9
|
+
height: globalTokens.stroke.width10,
|
|
10
|
+
insetSize: 0,
|
|
11
|
+
});
|
package/src/MenuDivider/index.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { MenuDivider } from './MenuDivider';
|
|
2
2
|
export { menuDividerName } from './MenuDivider.types';
|
|
3
|
-
export type { MenuDividerProps, MenuDividerTokens, MenuDividerSlotProps, MenuDividerType } from './MenuDivider.types';
|
|
3
|
+
export type { MenuDividerProps, MenuDividerTokens, MenuDividerSlotProps, MenuDividerType, MenuDividerInsetSize } from './MenuDivider.types';
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { Platform } from 'react-native';
|
|
2
|
+
|
|
1
3
|
import type { Theme, UseStylingOptions } from '@fluentui-react-native/framework';
|
|
2
4
|
import { buildProps } from '@fluentui-react-native/framework';
|
|
3
5
|
import { borderStyles, fontStyles, layoutStyles } from '@fluentui-react-native/tokens';
|
|
@@ -30,7 +32,7 @@ export const stylingSettings: UseStylingOptions<MenuItemProps, MenuItemSlotProps
|
|
|
30
32
|
style: {
|
|
31
33
|
height: tokens.checkmarkSize,
|
|
32
34
|
width: tokens.checkmarkSize,
|
|
33
|
-
marginEnd: tokens.gap,
|
|
35
|
+
marginEnd: Platform.OS === 'android' ? tokens.marginEndForCheckedAndroid : tokens.gap,
|
|
34
36
|
},
|
|
35
37
|
}),
|
|
36
38
|
['checkmarkSize', 'gap'],
|
|
@@ -31,6 +31,11 @@ export interface MenuItemTokens extends LayoutTokens, FontTokens, IBorderTokens,
|
|
|
31
31
|
*/
|
|
32
32
|
iconSize?: number;
|
|
33
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Amount of space in pixels at the end of the item control that is reserved to align the item's text with other items which have checkmarks
|
|
36
|
+
*/
|
|
37
|
+
marginEndForCheckedAndroid?: number;
|
|
38
|
+
|
|
34
39
|
/**
|
|
35
40
|
* Color of the indicator that shows that an item has a submenu
|
|
36
41
|
*/
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Theme } from '@fluentui-react-native/framework';
|
|
2
|
+
import { globalTokens } from '@fluentui-react-native/theme-tokens';
|
|
3
|
+
import type { TokenSettings } from '@fluentui-react-native/use-styling';
|
|
4
|
+
|
|
5
|
+
import type { MenuItemTokens } from './MenuItem.types';
|
|
6
|
+
|
|
7
|
+
export const defaultMenuItemTokens: TokenSettings<MenuItemTokens, Theme> = (t: Theme): MenuItemTokens => ({
|
|
8
|
+
color: t.colors.neutralForeground1,
|
|
9
|
+
variant: 'body1',
|
|
10
|
+
paddingHorizontal: globalTokens.size160,
|
|
11
|
+
paddingVertical: globalTokens.size60,
|
|
12
|
+
iconColor: t.colors.neutralForeground3,
|
|
13
|
+
iconSize: globalTokens.size240,
|
|
14
|
+
marginEndForCheckedAndroid: globalTokens.size360,
|
|
15
|
+
pressed: {
|
|
16
|
+
backgroundColor: t.colors.neutralBackground1Pressed,
|
|
17
|
+
},
|
|
18
|
+
disabled: {
|
|
19
|
+
backgroundColor: t.colors.neutralBackground1,
|
|
20
|
+
color: t.colors.neutralForegroundDisabled1,
|
|
21
|
+
iconColor: t.colors.disabledText,
|
|
22
|
+
},
|
|
23
|
+
gap: globalTokens.size160,
|
|
24
|
+
});
|
|
@@ -28,7 +28,6 @@ export const useMenuItem = (props: MenuItemProps): MenuItemInfo => {
|
|
|
28
28
|
const onInvoke = React.useCallback(
|
|
29
29
|
(e: InteractionEvent) => {
|
|
30
30
|
const isRtl = I18nManager.isRTL;
|
|
31
|
-
|
|
32
31
|
const isArrowKey = isKeyPressEvent(e) && (e.nativeEvent.key === 'ArrowLeft' || e.nativeEvent.key === 'ArrowRight');
|
|
33
32
|
const isArrowOpen =
|
|
34
33
|
hasSubmenu &&
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { Platform } from 'react-native';
|
|
2
|
+
|
|
1
3
|
import type { Theme, UseStylingOptions } from '@fluentui-react-native/framework';
|
|
2
4
|
import { buildProps } from '@fluentui-react-native/framework';
|
|
3
5
|
import { borderStyles, fontStyles, layoutStyles } from '@fluentui-react-native/tokens';
|
|
@@ -7,6 +9,7 @@ import { menuItemCheckboxName } from './MenuItemCheckbox.types';
|
|
|
7
9
|
import { defaultMenuItemCheckboxTokens } from './MenuItemCheckboxTokens';
|
|
8
10
|
|
|
9
11
|
export const menuItemCheckboxStates: (keyof MenuItemCheckboxTokens)[] = ['hovered', 'focused', 'pressed', 'disabled', 'checked'];
|
|
12
|
+
const hasPressRententionForA11y = Platform.OS === 'android';
|
|
10
13
|
|
|
11
14
|
export const stylingSettings: UseStylingOptions<MenuItemCheckboxProps, MenuItemCheckboxSlotProps, MenuItemCheckboxTokens> = {
|
|
12
15
|
tokens: [defaultMenuItemCheckboxTokens, menuItemCheckboxName],
|
|
@@ -25,14 +28,37 @@ export const stylingSettings: UseStylingOptions<MenuItemCheckboxProps, MenuItemC
|
|
|
25
28
|
}),
|
|
26
29
|
['backgroundColor', ...borderStyles.keys, ...layoutStyles.keys],
|
|
27
30
|
),
|
|
31
|
+
...(Platform.OS === 'android' && {
|
|
32
|
+
checkbox: buildProps(
|
|
33
|
+
(tokens: MenuItemCheckboxTokens) => ({
|
|
34
|
+
style: {
|
|
35
|
+
height: tokens.checkboxSize,
|
|
36
|
+
marginEnd: tokens.paddingHorizontal,
|
|
37
|
+
width: tokens.checkboxSize,
|
|
38
|
+
backgroundColor: tokens.checkboxBackgroundColor,
|
|
39
|
+
borderColor: tokens.checkboxBorderColor,
|
|
40
|
+
borderRadius: tokens.checkboxBorderRadius,
|
|
41
|
+
borderWidth: tokens.checkboxBorderWidth,
|
|
42
|
+
alignItems: 'center',
|
|
43
|
+
justifyContent: 'center',
|
|
44
|
+
},
|
|
45
|
+
...(hasPressRententionForA11y && {
|
|
46
|
+
pressRetentionOffset: typeof tokens.padding === 'number' ? tokens.padding : parseFloat(tokens.padding), /// Retention of the press area outside of the checkbox equal to padding to match accessibility requirement
|
|
47
|
+
}),
|
|
48
|
+
android_ripple: { color: tokens.rippleColor, radius: tokens.checkmarkSize, foreground: true },
|
|
49
|
+
}),
|
|
50
|
+
['checkboxBackgroundColor', 'checkboxBorderColor', 'checkboxBorderRadius', 'checkboxBorderWidth', 'checkboxSize', 'rippleColor'],
|
|
51
|
+
),
|
|
52
|
+
}),
|
|
53
|
+
|
|
28
54
|
checkmark: buildProps(
|
|
29
55
|
(tokens: MenuItemCheckboxTokens) => ({
|
|
30
56
|
opacity: tokens.checkmarkVisibility,
|
|
31
|
-
color: tokens.color,
|
|
57
|
+
color: tokens.checkmarkColor ?? tokens.color,
|
|
32
58
|
height: tokens.checkmarkSize,
|
|
33
59
|
width: tokens.checkmarkSize,
|
|
34
60
|
viewBox: '0 0 ' + (tokens.checkmarkSize - tokens.checkmarkPadding * 2) + ' ' + (tokens.checkmarkSize - tokens.checkmarkPadding * 2),
|
|
35
|
-
style: { marginEnd: tokens.gap },
|
|
61
|
+
...(Platform.OS !== 'android' && { style: { marginEnd: tokens.gap } }),
|
|
36
62
|
}),
|
|
37
63
|
['checkmarkPadding', 'checkmarkSize', 'checkmarkVisibility', 'color', 'gap'],
|
|
38
64
|
),
|
|
@@ -41,6 +67,7 @@ export const stylingSettings: UseStylingOptions<MenuItemCheckboxProps, MenuItemC
|
|
|
41
67
|
style: {
|
|
42
68
|
flexGrow: 1,
|
|
43
69
|
color: tokens.color,
|
|
70
|
+
...(Platform.OS === 'android' && { flexShrink: 1 }),
|
|
44
71
|
...fontStyles.from(tokens, theme),
|
|
45
72
|
},
|
|
46
73
|
}),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** @jsx withSlots */
|
|
2
2
|
import React from 'react';
|
|
3
|
-
import { Image, Pressable, View } from 'react-native';
|
|
3
|
+
import { Image, Platform, Pressable, View } from 'react-native';
|
|
4
4
|
|
|
5
5
|
import type { Slots, UseSlots } from '@fluentui-react-native/framework';
|
|
6
6
|
import { compose, mergeProps, withSlots } from '@fluentui-react-native/framework';
|
|
@@ -24,6 +24,7 @@ export const MenuItemCheckbox = compose<MenuItemCheckboxType>({
|
|
|
24
24
|
...stylingSettings,
|
|
25
25
|
slots: {
|
|
26
26
|
root: Pressable,
|
|
27
|
+
...(Platform.OS === 'android' && { checkbox: Pressable }),
|
|
27
28
|
checkmark: SvgXml,
|
|
28
29
|
content: Text,
|
|
29
30
|
iconPlaceholder: View,
|
|
@@ -44,17 +45,29 @@ export const menuItemFinalRender = (
|
|
|
44
45
|
): React.FunctionComponent<MenuItemCheckboxProps> => {
|
|
45
46
|
return (final: MenuItemCheckboxProps, children: React.ReactNode) => {
|
|
46
47
|
const { accessibilityLabel, icon, tooltip, ...mergedProps } = mergeProps(menuItem.props, final);
|
|
48
|
+
|
|
47
49
|
const checkmarkXml = `
|
|
48
50
|
<svg>
|
|
49
51
|
<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' />
|
|
50
52
|
</svg>`;
|
|
51
53
|
|
|
54
|
+
const androidCheckmarkPath = `
|
|
55
|
+
<svg>
|
|
56
|
+
<path fill='currentColor' d='M9.76497 3.20474C10.0661 3.48915 10.0797 3.96383 9.79526 4.26497L5.54526 8.76497C5.40613 8.91228 5.21332 8.99703 5.01071 8.99993C4.8081 9.00282 4.61295 8.92361 4.46967 8.78033L2.21967 6.53033C1.92678 6.23744 1.92678 5.76257 2.21967 5.46967C2.51256 5.17678 2.98744 5.17678 3.28033 5.46967L4.98463 7.17397L8.70474 3.23503C8.98915 2.9339 9.46383 2.92033 9.76497 3.20474Z' />
|
|
57
|
+
</svg>`;
|
|
58
|
+
|
|
52
59
|
const label = getAccessibilityLabel(accessibilityLabel, children[0]);
|
|
53
60
|
const tooltipResult = getTooltip(tooltip, menuItem.state.hasTooltips, children[0]);
|
|
54
61
|
|
|
55
62
|
return (
|
|
56
63
|
<Slots.root {...mergedProps} accessibilityLabel={label}>
|
|
57
|
-
|
|
64
|
+
{Platform.OS === 'android' ? (
|
|
65
|
+
<Slots.checkbox onPress={mergedProps.onPress} accessible={false} focusable={false}>
|
|
66
|
+
<Slots.checkmark xml={androidCheckmarkPath} />
|
|
67
|
+
</Slots.checkbox>
|
|
68
|
+
) : (
|
|
69
|
+
<Slots.checkmark accessible={false} xml={checkmarkXml} />
|
|
70
|
+
)}
|
|
58
71
|
{(icon || menuItem.state.hasIcons) && (
|
|
59
72
|
<Slots.iconPlaceholder accessible={false}>
|
|
60
73
|
{icon && icon.source && <Slots.imgIcon accessible={false} {...icon} />}
|