Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch Menu components to Pressable #2147

Merged
merged 15 commits into from
Oct 18, 2022
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "Switch Menu to Pressable",
"packageName": "@fluentui-react-native/contextual-menu",
"email": "sanajmi@microsoft.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "Switch Menu to Pressable",
"packageName": "@fluentui-react-native/menu",
"email": "sanajmi@microsoft.com",
"dependentChangeType": "patch"
}
14 changes: 8 additions & 6 deletions packages/components/ContextualMenu/src/ContextualMenuItem.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/** @jsx withSlots */
import * as React from 'react';
import { View } from 'react-native';
import { Pressable, View } from 'react-native';
import {
ContextualMenuItemSlotProps,
ContextualMenuItemState,
Expand All @@ -15,7 +15,7 @@ import { Text } from '@fluentui-react-native/text';
import { settings } from './ContextualMenuItem.settings';
import { backgroundColorTokens, borderTokens, textTokens, foregroundColorTokens, getPaletteFromTheme } from '@fluentui-react-native/tokens';
import { mergeSettings } from '@uifabricshared/foundation-settings';
import { useAsPressable, useKeyProps, useViewCommandFocus } from '@fluentui-react-native/interactive-hooks';
import { usePressableState, useKeyProps, useViewCommandFocus } from '@fluentui-react-native/interactive-hooks';
import { CMContext } from './ContextualMenu';
import { Icon } from '@fluentui-react-native/icon';
import { createIconProps } from '@fluentui-react-native/interactive-hooks';
Expand Down Expand Up @@ -64,7 +64,7 @@ export const ContextualMenuItem = compose<ContextualMenuItemType>({
}
}, [componentRef, disabled, context]);

const pressable = useAsPressable({ ...rest, onPress: onItemClick, onHoverIn: onItemHoverIn });
const pressable = usePressableState({ ...rest, onPress: onItemClick, onHoverIn: onItemHoverIn });

const onKeyUpProps = useKeyProps(onItemClick, ' ', 'Enter');

Expand All @@ -80,9 +80,11 @@ export const ContextualMenuItem = compose<ContextualMenuItemType>({
/**
* On Desktop, focus gets moved to the root of the menu, so hovering off the menu does not automatically call onBlur as we expect it to.
* onMouseLeave is overridden to explicitly call onBlur to simulate removing focus
* To achieve this, we override the onMouseLEave handler returned by useAsPressable, and replace it with our own. Inside our own
* onMouseLeave handler, we call useAsPressable's onMouseLEave handler,
* To achieve this, we override the onMouseLeave handler returned by usePressableState, and replace it with our own. Inside our own
* onMouseLeave handler, we call usePressableState's onMouseLEave handler,
*/
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore onMouseLeave not in PressableProps but is supported on desktop
const { onBlur, onMouseLeave, ...restPressableProps } = pressable.props;
const onMouseLeaveModified = React.useCallback(
(e) => {
Expand Down Expand Up @@ -136,7 +138,7 @@ export const ContextualMenuItem = compose<ContextualMenuItemType>({
);
},
slots: {
root: View,
root: Pressable,
stack: { slotType: View },
icon: { slotType: Icon as React.ComponentType },
content: Text,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as React from 'react';
import { PressableProps } from 'react-native';
import { IViewProps } from '@fluentui-react-native/adapters';
import { IRenderData } from '@uifabricshared/foundation-composable';
import { ITextProps } from '@fluentui-react-native/text';
Expand Down Expand Up @@ -80,7 +81,7 @@ export interface ContextualMenuItemProps extends Omit<IPressableProps, 'onPress'
}

export interface ContextualMenuItemSlotProps {
root: React.PropsWithRef<IViewProps>;
root: React.PropsWithRef<PressableProps>;
stack: IViewProps;
icon: IconProps;
content: ITextProps;
Expand Down
18 changes: 10 additions & 8 deletions packages/components/ContextualMenu/src/SubmenuItem.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/** @jsx withSlots */
import * as React from 'react';
import { I18nManager, Platform, View } from 'react-native';
import { I18nManager, Platform, Pressable, View } from 'react-native';
import {
SubmenuItemSlotProps,
SubmenuItemState,
Expand All @@ -15,7 +15,7 @@ import { Text } from '@fluentui-react-native/text';
import { settings } from './SubmenuItem.settings';
import { backgroundColorTokens, borderTokens, textTokens, foregroundColorTokens, getPaletteFromTheme } from '@fluentui-react-native/tokens';
import { mergeSettings } from '@uifabricshared/foundation-settings';
import { useAsPressable, useKeyDownProps, useViewCommandFocus } from '@fluentui-react-native/interactive-hooks';
import { usePressableState, useKeyDownProps, useViewCommandFocus } from '@fluentui-react-native/interactive-hooks';
import { CMContext } from './ContextualMenu';
import { Icon, SvgIconProps } from '@fluentui-react-native/icon';
import { createIconProps } from '@fluentui-react-native/interactive-hooks';
Expand Down Expand Up @@ -64,7 +64,7 @@ export const SubmenuItem = compose<SubmenuItemType>({
}
}, [context, disabled, itemKey, onClick]);

const pressable = useAsPressable({
const pressable = usePressableState({
...rest,
onPress: onItemPress,
onHoverIn: onItemHoverIn,
Expand All @@ -75,25 +75,27 @@ export const SubmenuItem = compose<SubmenuItemType>({
/**
* GH #1267
* We want onMouseEnter to fire right away to set focus, and then Pressable's onHoverIn to fire after a delay to show the submenu.
* To achieve this, we override the onMouseEnter handler returned by useAsPressable, and replace it with our own. Inside our own
* onMouseEnter handler, we call useAsPressable's onMouseEnter handler, which incorporates the delay passed to delayHoverIn
* To achieve this, we override the onMouseEnter handler returned by usePressableState, and replace it with our own. Inside our own
* onMouseEnter handler, we call usePressableState's onMouseEnter handler, which incorporates the delay passed to delayHoverIn
* In the future, we can avoid needing to override onMouseEnter by handling submenu rendering internally rather than depending on the
* client to conditionally render it with onHoverIn.
*/
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore onMouseLeave not in PressableProps but is supported on desktop
const { onBlur, onMouseEnter, onMouseLeave, ...restPressableProps } = pressable.props;
const onMouseEnterModified = React.useCallback(
(e) => {
componentRef.current.focus();
onMouseEnter && onMouseEnter(e);
},
[onMouseEnter],
[componentRef, onMouseEnter],
);
const onMouseLeaveModified = React.useCallback(
(e) => {
onBlur(e);
onMouseLeave && onMouseLeave(e);
},
[onMouseLeave],
[onBlur, onMouseLeave],
);
const pressablePropsModified = {
onBlur: onBlur,
Expand Down Expand Up @@ -182,7 +184,7 @@ export const SubmenuItem = compose<SubmenuItemType>({
);
},
slots: {
root: View,
root: Pressable,
startstack: View,
icon: Icon as React.ComponentType,
content: Text,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as React from 'react';
import { PressableProps } from 'react-native';
import { IViewProps } from '@fluentui-react-native/adapters';
import { IRenderData } from '@uifabricshared/foundation-composable';
import { ITextProps } from '@fluentui-react-native/text';
Expand All @@ -14,7 +15,7 @@ export type SubmenuItemProps = ContextualMenuItemProps;
export type SubmenuItemState = ContextualMenuItemState;

export interface SubmenuItemSlotProps {
root: React.PropsWithRef<IViewProps>;
root: React.PropsWithRef<PressableProps>;
startstack: IViewProps;
icon: IconProps;
content: ITextProps;
Expand Down
4 changes: 2 additions & 2 deletions packages/components/Menu/src/MenuItem/MenuItem.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/** @jsx withSlots */
import { I18nManager, View } from 'react-native';
import { I18nManager, Pressable, View } from 'react-native';
import { SvgXml } from 'react-native-svg';
import { compose, memoize, mergeProps, UseSlots, withSlots } from '@fluentui-react-native/framework';
import { TextV1 as Text } from '@fluentui-react-native/text';
Expand All @@ -12,7 +12,7 @@ export const MenuItem = compose<MenuItemType>({
displayName: menuItemName,
...stylingSettings,
slots: {
root: View,
root: Pressable,
checkmark: View,
content: Text,
submenuIndicator: SvgXml,
Expand Down
4 changes: 2 additions & 2 deletions packages/components/Menu/src/MenuItem/MenuItem.types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import { ColorValue } from 'react-native';
import { ColorValue, PressableProps } from 'react-native';
import { XmlProps } from 'react-native-svg';
import type { IViewProps } from '@fluentui-react-native/adapters';
import { TextProps } from '@fluentui-react-native/text';
Expand Down Expand Up @@ -70,7 +70,7 @@ export interface MenuItemState extends IPressableHooks<MenuItemProps & React.Com
}

export interface MenuItemSlotProps {
root: React.PropsWithRef<IViewProps>;
root: React.PropsWithRef<PressableProps>;
Saadnajmi marked this conversation as resolved.
Show resolved Hide resolved
content?: TextProps;
checkmark?: React.PropsWithRef<IViewProps>;
submenuIndicator?: XmlProps;
Expand Down
4 changes: 2 additions & 2 deletions packages/components/Menu/src/MenuItem/useMenuItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { memoize } from '@fluentui-react-native/framework';
import {
InteractionEvent,
isKeyPressEvent,
useAsPressable,
usePressableState,
useKeyDownProps,
useViewCommandFocus,
} from '@fluentui-react-native/interactive-hooks';
Expand Down Expand Up @@ -54,7 +54,7 @@ export const useMenuItem = (props: MenuItemProps): MenuItemState => {
[disabled, hasSubmenu, onArrowClose, onClick, setOpen, shouldPersist],
);

const pressable = useAsPressable({ ...rest, disabled, onPress: onInvoke });
const pressable = usePressableState({ ...rest, disabled, onPress: onInvoke });
const itemRef = useViewCommandFocus(componentRef);
const keys = isSubmenu ? submenuTriggerKeys : triggerKeys;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/** @jsx withSlots */
import { View } from 'react-native';
import { Pressable } from 'react-native';
import { SvgXml } from 'react-native-svg';
import { compose, mergeProps, Slots, UseSlots, withSlots } from '@fluentui-react-native/framework';
import { TextV1 as Text } from '@fluentui-react-native/text';
Expand All @@ -19,7 +19,7 @@ export const MenuItemCheckbox = compose<MenuItemCheckboxType>({
displayName: menuItemCheckboxName,
...stylingSettings,
slots: {
root: View,
root: Pressable,
checkmark: SvgXml,
content: Text,
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import * as React from 'react';
import { ColorValue } from 'react-native';
import { ColorValue, PressableProps } from 'react-native';
import { XmlProps } from 'react-native-svg';
import type { IViewProps } from '@fluentui-react-native/adapters';
import { TextProps } from '@fluentui-react-native/text';
import { IPressableHooks } from '@fluentui-react-native/interactive-hooks';
import { MenuItemProps, MenuItemTokens } from '../MenuItem/MenuItem.types';
Expand Down Expand Up @@ -45,7 +44,7 @@ export interface MenuItemCheckboxProps extends MenuItemProps {
export interface MenuItemCheckboxState extends IPressableHooks<MenuItemCheckboxProps & React.ComponentPropsWithRef<any>> {}

export interface MenuItemCheckboxSlotProps {
root: React.PropsWithRef<IViewProps>;
root: React.PropsWithRef<PressableProps>;
checkmark?: XmlProps;
content?: TextProps;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { memoize } from '@fluentui-react-native/framework';
import {
InteractionEvent,
KeyPressEvent,
useAsPressable,
usePressableState,
useKeyDownProps,
useOnPressWithFocus,
useViewCommandFocus,
Expand Down Expand Up @@ -74,7 +74,7 @@ export const useMenuCheckboxInteraction = (
// Ensure focus is placed on checkbox after click
const toggleCheckedWithFocus = useOnPressWithFocus(componentRef, toggleCallback);

const pressable = useAsPressable({ ...rest, disabled, onPress: toggleCheckedWithFocus });
const pressable = usePressableState({ ...rest, disabled, onPress: toggleCheckedWithFocus });
const buttonRef = useViewCommandFocus(componentRef);

const onKeysPressed = React.useCallback(
Expand Down
Loading