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

MenuButton: Re-introducing MenuButton using the latest version of makeStyles #18168

Merged
merged 33 commits into from
Jun 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
fb90b01
MenuButton: Re-introducing MenuButton using the latest version of mak…
khmakoto May 13, 2021
d0e7240
Change files
khmakoto May 13, 2021
96ab486
Fixing merge conflict.
khmakoto May 13, 2021
6bc4667
Updating API.
khmakoto May 13, 2021
e40175f
Improving example by showing MenuButton working with both v8's Contex…
khmakoto May 13, 2021
e0710cf
Fixing merge conflict.
khmakoto May 13, 2021
d175e8b
Change files
khmakoto May 13, 2021
b0df477
Fixing wrong Button vr-tests.
khmakoto May 14, 2021
2b635d0
Fixing merge conflict.
khmakoto May 21, 2021
b48333f
Change files
khmakoto May 21, 2021
db120f7
Calculating iconOnly in useButtonState.
khmakoto May 21, 2021
4857c38
Fixing merge conflict.
khmakoto May 21, 2021
7545114
Change files
khmakoto May 21, 2021
fa958a0
Updating API.
khmakoto May 21, 2021
1b7b33c
Fixing merge conflicts.
khmakoto May 28, 2021
5d40317
Addressing some PR feedback.
khmakoto May 29, 2021
7ab9997
Addressing some PR feedback around the use of the useControllableValu…
khmakoto May 29, 2021
9efd212
Using resolveShorthandProps on the defaultProps of Button and Compoun…
khmakoto May 29, 2021
b6133f9
Moving onlyChild as part of react-utilities and adding tests.
khmakoto May 29, 2021
6b40d32
Change files
khmakoto May 29, 2021
2841d5e
Modifying MenuButton.stories.tsx to adhere to new Playground type gua…
khmakoto May 29, 2021
0fc0e3b
Fixing errors in stories due to changes in Playground type guards.
khmakoto May 29, 2021
34b904a
Delete @fluentui-react-components-ba379fbe-3151-4479-a3e8-bfc0ec6a422…
khmakoto May 29, 2021
6a786c7
Delete @fluentui-react-menu-6626299c-5cf8-43f9-ba7f-4081c0a07d2b.json
khmakoto May 29, 2021
fda3ea3
Fixing merge conflict.
khmakoto Jun 1, 2021
b6549ba
Removing menu slot and simplifying API.
khmakoto Jun 1, 2021
b2e29e3
Fixing error in vr stories.
khmakoto Jun 1, 2021
5d3f190
Fixing error in vr stories.
khmakoto Jun 1, 2021
f6ca650
Removing unused contract from MenuButton while we wait for MenuTrigge…
khmakoto Jun 3, 2021
5aba837
Fixing merge conflicts.
khmakoto Jun 3, 2021
33b0c09
Fixing merge conflicts.
khmakoto Jun 3, 2021
92e24d5
Reverting Flex migration changes.
khmakoto Jun 3, 2021
65eeee5
Fixing error in vr-tests.
khmakoto Jun 3, 2021
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
1 change: 1 addition & 0 deletions apps/test-bundles/webpackUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ function createFluentConvergedFixtures() {
'Image',
'Link',
'Menu',
'MenuButton',
'Portal',
'ToggleButton',
'Tooltip',
Expand Down
62 changes: 59 additions & 3 deletions apps/vr-tests/src/stories/ReactButton.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import { storiesOf } from '@storybook/react';
import * as React from 'react';
import Screener from 'screener-storybook/src/screener';
import { Button, ButtonProps, CompoundButton, ToggleButton } from '@fluentui/react-button';
import {
Button,
ButtonProps,
CompoundButton,
ToggleButton,
MenuButton,
} from '@fluentui/react-button';

import { FluentProviderDecorator, FabricDecorator } from '../utilities/index';

Expand Down Expand Up @@ -162,7 +168,7 @@ storiesOf('react-button CompoundButton', module)
</CompoundButton>
))
.addStory('Size small', () => (
<CompoundButton secondaryContent="This is some secondary text" icon="X" size="large">
<CompoundButton secondaryContent="This is some secondary text" icon="X" size="small">
Hello, world
</CompoundButton>
))
Expand Down Expand Up @@ -217,7 +223,7 @@ storiesOf('react-button ToggleButton', module)
</ToggleButton>
))
.addStory('Size small', () => (
<ToggleButton icon="X" size="large">
<ToggleButton icon="X" size="small">
Hello, world
</ToggleButton>
))
Expand Down Expand Up @@ -247,3 +253,53 @@ storiesOf('react-button ToggleButton', module)
Hello, world
</ToggleButton>
));

storiesOf('react-button MenuButton', module)
.addDecorator(FabricDecorator)
.addDecorator(FluentProviderDecorator)
.addDecorator(story => (
<Screener
steps={new Screener.Steps()
.snapshot('default', { cropTo: '.testWrapper' })
.hover('button')
.snapshot('hover', { cropTo: '.testWrapper' })
.mouseDown('button')
.snapshot('pressed', { cropTo: '.testWrapper' })
.mouseUp('button')
.end()}
>
{story()}
</Screener>
))
.addStory('Default', () => <MenuButton>Hello, world</MenuButton>)
.addStory('Primary', () => <MenuButton primary>Hello, world</MenuButton>)
.addStory('Subtle', () => <MenuButton subtle>Hello, world</MenuButton>)
.addStory('Transparent', () => <MenuButton transparent>Hello, world</MenuButton>)
.addStory('Disabled', () => <MenuButton disabled>Hello, world</MenuButton>)
.addStory('Primary Disabled', () => (
<MenuButton primary disabled>
Hello, world
</MenuButton>
))
.addStory('Subtle Disabled', () => (
<MenuButton subtle disabled>
Hello, world
</MenuButton>
))
.addStory('Transparent Disabled', () => (
<MenuButton transparent disabled>
Hello, world
</MenuButton>
))
.addStory('With icon', () => <MenuButton icon="X">Hello, world</MenuButton>)
.addStory('Size small', () => (
<MenuButton icon="X" size="small">
Hello, world
</MenuButton>
))
.addStory('Size large', () => (
<MenuButton icon="X" size="large">
Hello, world
</MenuButton>
))
.addStory('Icon only', () => <MenuButton icon="X" />);
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "MenuButton: Re-introducing MenuButton using the latest version of makeStyles.",
"packageName": "@fluentui/react-button",
"email": "Humberto.Morimoto@microsoft.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "Adding MenuButton stories.",
"packageName": "@fluentui/react-examples",
"email": "Humberto.Morimoto@microsoft.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Modifying MinimalMenuProps target prop to only be React.Ref<HTMLElement> instead of React.Ref<HTMLElement | undefined>.",
"packageName": "@fluentui/react-shared-contexts",
"email": "Humberto.Morimoto@microsoft.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Moving onlyChild to @fluentui/react-utilities.",
"packageName": "@fluentui/react-tooltip",
"email": "Humberto.Morimoto@microsoft.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Moving onlyChild to @fluentui/react-utilities and adding tests.",
"packageName": "@fluentui/react-utilities",
"email": "Humberto.Morimoto@microsoft.com",
"dependentChangeType": "patch"
}
67 changes: 57 additions & 10 deletions packages/react-button/etc/react-button.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@ export const Button: React_2.FunctionComponent<ButtonProps & React_2.RefAttribut

// @public (undocumented)
export type ButtonProps = ComponentProps & React_2.ButtonHTMLAttributes<HTMLElement> & {
icon?: ShorthandProps<React_2.HTMLAttributes<HTMLSpanElement>>;
icon?: ShorthandProps<React_2.HTMLAttributes<HTMLElement>>;
disabled?: boolean;
iconOnly?: boolean;
iconPosition?: 'before' | 'after';
primary?: boolean;
size?: 'small' | 'medium' | 'large';
Expand All @@ -25,14 +24,15 @@ export type ButtonProps = ComponentProps & React_2.ButtonHTMLAttributes<HTMLElem
};

// @public
export const buttonShorthandProps: readonly ["icon", "children"];
export const buttonShorthandProps: readonly ["children", "icon"];

// @public (undocumented)
export interface ButtonState extends ButtonProps {
// (undocumented)
children?: ObjectShorthandProps<React_2.HTMLAttributes<HTMLSpanElement>>;
children?: ObjectShorthandProps<React_2.HTMLAttributes<HTMLElement>>;
// (undocumented)
icon?: ObjectShorthandProps<React_2.HTMLAttributes<HTMLSpanElement>>;
icon?: ObjectShorthandProps<React_2.HTMLAttributes<HTMLElement>>;
iconOnly?: boolean;
// (undocumented)
ref: React_2.Ref<HTMLElement>;
}
Expand Down Expand Up @@ -110,19 +110,19 @@ export const CompoundButton: React_2.ForwardRefExoticComponent<CompoundButtonPro

// @public (undocumented)
export interface CompoundButtonProps extends ButtonProps {
contentContainer?: ShorthandProps<React_2.HTMLAttributes<HTMLSpanElement>>;
secondaryContent?: ShorthandProps<React_2.HTMLAttributes<HTMLSpanElement>>;
contentContainer?: ShorthandProps<React_2.HTMLAttributes<HTMLElement>>;
secondaryContent?: ShorthandProps<React_2.HTMLAttributes<HTMLElement>>;
}

// @public
export const compoundButtonShorthandProps: readonly ["icon", "children", "contentContainer", "secondaryContent"];
export const compoundButtonShorthandProps: readonly ["children", "contentContainer", "icon", "secondaryContent"];

// @public (undocumented)
export interface CompoundButtonState extends Omit<CompoundButtonProps, 'children' | 'icon'>, ButtonState {
// (undocumented)
contentContainer?: ObjectShorthandProps<React_2.HTMLAttributes<HTMLSpanElement>>;
contentContainer?: ObjectShorthandProps<React_2.HTMLAttributes<HTMLElement>>;
// (undocumented)
secondaryContent?: ObjectShorthandProps<React_2.HTMLAttributes<HTMLSpanElement>>;
secondaryContent?: ObjectShorthandProps<React_2.HTMLAttributes<HTMLElement>>;
}

// @public (undocumented)
Expand All @@ -144,6 +144,41 @@ export type CompoundButtonVariantTokens = Partial<{
[variant in CompoundButtonVariants]: Partial<CompoundButtonTokens>;
}>;

// @public
export const MenuButton: React_2.FunctionComponent<MenuButtonProps & React_2.RefAttributes<HTMLElement>>;

// @public (undocumented)
export type MenuButtonProps = Omit<ButtonProps, 'iconPosition'> & {
menuIcon?: ShorthandProps<React_2.HTMLAttributes<HTMLElement>>;
};

// @public
export const menuButtonShorthandProps: readonly ["children", "icon", "menuIcon"];

// @public (undocumented)
export interface MenuButtonState extends Omit<MenuButtonProps, 'children' | 'icon'>, Omit<ButtonState, 'iconPosition'> {
// (undocumented)
menuIcon?: ObjectShorthandProps<React_2.HTMLAttributes<HTMLElement>>;
}

// @public (undocumented)
export type MenuButtonStyleSelectors = ButtonStyleSelectors & {};

// @public (undocumented)
export type MenuButtonTokens = ButtonTokens & {
menuIconFontSize?: string;
menuIconHeight?: string;
menuIconWidth?: string;
};

// @public (undocumented)
export type MenuButtonVariants = ButtonVariants;

// @public (undocumented)
export type MenuButtonVariantTokens = Partial<{
[variant in MenuButtonVariants]: Partial<MenuButtonTokens>;
}>;

// @public
const renderButton: (state: ButtonState) => JSX.Element;

Expand All @@ -154,6 +189,9 @@ export { renderButton as renderToggleButton }
// @public
export const renderCompoundButton: (state: CompoundButtonState) => JSX.Element;

// @public
export const renderMenuButton: (state: MenuButtonState) => JSX.Element;

// @public
export const ToggleButton: React_2.ForwardRefExoticComponent<ToggleButtonProps & React_2.RefAttributes<HTMLElement>>;

Expand Down Expand Up @@ -201,6 +239,15 @@ export const useCompoundButton: (props: CompoundButtonProps, ref: React_2.Ref<HT
// @public (undocumented)
export const useCompoundButtonStyles: (state: CompoundButtonState, selectors: CompoundButtonStyleSelectors) => void;

// @public
export const useMenuButton: (props: MenuButtonProps, ref: React_2.Ref<HTMLElement>, defaultProps?: MenuButtonProps | undefined) => MenuButtonState;

// @public (undocumented)
export const useMenuButtonState: (state: MenuButtonState) => MenuButtonState;

// @public (undocumented)
export const useMenuButtonStyles: (state: MenuButtonState, selectors: MenuButtonStyleSelectors) => void;

// @public (undocumented)
export const useToggleButton: (props: ToggleButtonProps, ref: React_2.Ref<HTMLElement>, defaultProps?: ToggleButtonProps | undefined) => ToggleButtonState;

Expand Down
1 change: 1 addition & 0 deletions packages/react-button/src/MenuButton.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './components/MenuButton/index';
5 changes: 1 addition & 4 deletions packages/react-button/src/components/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,9 @@ export const Button: React.FunctionComponent<ButtonProps & React.RefAttributes<H
>((props, ref) => {
const state = useButton(props, ref);

const receivedChildren = !!state.children?.children;
const receivedIcon = !!state.icon?.children;

const styleSelectors: ButtonStyleSelectors = {
disabled: state.disabled,
iconOnly: receivedIcon && !receivedChildren,
iconOnly: state.iconOnly,
primary: state.primary,
size: state.size,
subtle: state.subtle,
Expand Down
18 changes: 9 additions & 9 deletions packages/react-button/src/components/Button/Button.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export type ButtonProps = ComponentProps &
* Icon slot that, if specified, renders an icon either before or after the `children` as specified by the
* `iconPosition` prop.
*/
icon?: ShorthandProps<React.HTMLAttributes<HTMLSpanElement>>;
icon?: ShorthandProps<React.HTMLAttributes<HTMLElement>>;

// /**
// * Loader slot that, if specified, renders a `loader` before the `icon` and `children` while the `loading` flag
Expand Down Expand Up @@ -44,12 +44,6 @@ export type ButtonProps = ComponentProps &
// */
// disabledFocusable?: boolean;

/**
* A button can contain only an icon.
* @default false
*/
iconOnly?: boolean;

/**
* A button can format its icon to appear before or after its content.
* @default 'before'
Expand Down Expand Up @@ -104,10 +98,16 @@ export type ButtonProps = ComponentProps &
* {@docCategory Button}
*/
export interface ButtonState extends ButtonProps {
/**
* A button can contain only an icon.
* @default false
*/
iconOnly?: boolean;

ref: React.Ref<HTMLElement>;

icon?: ObjectShorthandProps<React.HTMLAttributes<HTMLSpanElement>>;
children?: ObjectShorthandProps<React.HTMLAttributes<HTMLSpanElement>>;
icon?: ObjectShorthandProps<React.HTMLAttributes<HTMLElement>>;
children?: ObjectShorthandProps<React.HTMLAttributes<HTMLElement>>;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ButtonState } from './Button.types';
import { buttonShorthandProps } from './useButton';

/**
* Define the render function. Given the state of a button, renders it.
* Renders a Button component by passing the state defined props to the appropriate slots.
*/
export const renderButton = (state: ButtonState) => {
const { slots, slotProps } = getSlots(state, buttonShorthandProps);
Expand Down
11 changes: 3 additions & 8 deletions packages/react-button/src/components/Button/useButton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { useButtonState } from './useButtonState';
/**
* Consts listing which props are shorthand props.
*/
export const buttonShorthandProps = ['icon', 'children'] as const;
export const buttonShorthandProps = ['children', 'icon'] as const;

// eslint-disable-next-line deprecation/deprecation
const mergeProps = makeMergePropsCompat<ButtonState>({ deepMerge: buttonShorthandProps });
Expand All @@ -15,18 +15,13 @@ const mergeProps = makeMergePropsCompat<ButtonState>({ deepMerge: buttonShorthan
* Given user props, returns state and render function for a Button.
*/
export const useButton = (props: ButtonProps, ref: React.Ref<HTMLElement>, defaultProps?: ButtonProps): ButtonState => {
// Ensure that the `ref` prop can be used by other things (like useFocusRects) to refer to the root.
// NOTE: We are assuming refs should not mutate to undefined. Either they are passed or not.
// eslint-disable-next-line react-hooks/rules-of-hooks
const resolvedRef = ref || React.useRef<HTMLElement>(null);
const state = mergeProps(
{
ref: resolvedRef,
ref,
as: 'button',
icon: { as: 'span' },
loader: { as: 'span' },
},
defaultProps,
defaultProps && resolveShorthandProps(defaultProps, buttonShorthandProps),
resolveShorthandProps(props, buttonShorthandProps),
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ import { ButtonState } from './Button.types';
* @param state - Button draft state to mutate.
*/
export const useButtonState = (state: ButtonState): ButtonState => {
const { as, disabled, /*disabledFocusable,*/ onClick, onKeyDown: onKeyDownCallback } = state;
const { as, children, disabled, icon, onClick, onKeyDown: onKeyDownCallback } = state;

const receivedChildren = !!children?.children;
const receivedIcon = !!icon?.children;
state.iconOnly = receivedIcon && !receivedChildren;

const onNonAnchorOrButtonKeyDown = (ev: React.KeyboardEvent<HTMLElement>) => {
onKeyDownCallback?.(ev);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,9 @@ import { useCompoundButtonStyles } from './useCompoundButtonStyles';
export const CompoundButton = React.forwardRef<HTMLElement, CompoundButtonProps>((props, ref) => {
const state = useCompoundButton(props, ref);

const receivedChildren = !!state.children?.children;
const receivedIcon = !!state.icon?.children;

const styleSelectors: CompoundButtonStyleSelectors = {
disabled: state.disabled,
iconOnly: receivedIcon && !receivedChildren,
iconOnly: state.iconOnly,
primary: state.primary,
size: state.size,
subtle: state.subtle,
Expand Down
Loading