Skip to content

Commit

Permalink
Button: Adding toggle/checked functionality to Button (#9016)
Browse files Browse the repository at this point in the history
* Button: Adding toggle/checked functionality to Button.

* Adding change file.

* Propagating checked prop to MenuButtons and SplitButtons.
  • Loading branch information
khmakoto authored and dzearing committed May 9, 2019
1 parent 5f4051f commit 65d3dec
Show file tree
Hide file tree
Showing 8 changed files with 167 additions and 2 deletions.
@@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "@uifabric/experiments",
"comment": "Button: Adding toggle/checked functionality to Button.",
"type": "minor"
}
],
"packageName": "@uifabric/experiments",
"email": "Humberto.Morimoto@microsoft.com"
}
36 changes: 36 additions & 0 deletions packages/experiments/src/components/Button/Button.styles.ts
Expand Up @@ -136,12 +136,48 @@ const primaryEnabledTokens: IButtonComponent['tokens'] = (props, theme): IButton
};
};

const checkedTokens: IButtonComponent['tokens'] = (props, theme): IButtonTokenReturnType => {
const { semanticColors } = theme;
return {
backgroundColor: semanticColors.buttonBackgroundChecked,
backgroundColorHovered: semanticColors.buttonBackgroundCheckedHovered,
backgroundColorPressed: semanticColors.buttonBackgroundPressed,

color: semanticColors.buttonTextChecked,
colorHovered: semanticColors.buttonTextCheckedHovered,
colorPressed: semanticColors.buttonTextPressed,

iconColor: semanticColors.buttonTextChecked,
iconColorHovered: semanticColors.buttonTextCheckedHovered,
iconColorPressed: semanticColors.buttonTextPressed
};
};

const primaryCheckedTokens: IButtonComponent['tokens'] = (props, theme): IButtonTokenReturnType => {
const { semanticColors } = theme;
return {
backgroundColor: semanticColors.primaryButtonBackgroundPressed,
backgroundColorHovered: semanticColors.primaryButtonBackgroundHovered,
backgroundColorPressed: semanticColors.primaryButtonBackgroundPressed,

color: semanticColors.primaryButtonTextPressed,
colorHovered: semanticColors.primaryButtonTextHovered,
colorPressed: semanticColors.primaryButtonTextPressed,

iconColor: semanticColors.primaryButtonTextPressed,
iconColorHovered: semanticColors.primaryButtonTextHovered,
iconColorPressed: semanticColors.primaryButtonTextPressed
};
};

export const ButtonTokens: IButtonComponent['tokens'] = (props, theme): IButtonTokenReturnType => [
baseTokens,
!!props.href && hrefTokens,
!props.disabled && enabledTokens,
props.primary && primaryEnabledTokens,
props.circular && circularTokens,
props.checked && checkedTokens,
props.checked && props.primary && primaryCheckedTokens,
props.disabled && disabledTokens
];

Expand Down
24 changes: 24 additions & 0 deletions packages/experiments/src/components/Button/Button.test.tsx
Expand Up @@ -75,4 +75,28 @@ describe('Button view', () => {
const tree = component.toJSON();
expect(tree).toMatchSnapshot;
});

it('renders a default checked Button correctly', () => {
const component = renderer.create(<Button checked content="Button" />);
const tree = component.toJSON();
expect(tree).toMatchSnapshot;
});

it('renders a primary checked Button correctly', () => {
const component = renderer.create(<Button primary checked content="Button" />);
const tree = component.toJSON();
expect(tree).toMatchSnapshot;
});

it('renders a default circular checked Button correctly', () => {
const component = renderer.create(<Button checked circular icon="Volume3" />);
const tree = component.toJSON();
expect(tree).toMatchSnapshot;
});

it('renders a primary circular checked Button correctly', () => {
const component = renderer.create(<Button primary checked circular icon="Volume3" />);
const tree = component.toJSON();
expect(tree).toMatchSnapshot;
});
});
5 changes: 5 additions & 0 deletions packages/experiments/src/components/Button/Button.types.tsx
Expand Up @@ -102,6 +102,11 @@ export interface IButtonProps
*/
onClick?: (ev: React.MouseEvent<HTMLElement>) => void;

/**
* Defines whether the Button is in a checked state (for toggle buttons).
*/
checked?: boolean;

/**
* Defines whether disabled buttons should be tabbable via keyboard navigation or not.
* @defaultvalue false
Expand Down
5 changes: 5 additions & 0 deletions packages/experiments/src/components/Button/ButtonPage.tsx
Expand Up @@ -6,6 +6,7 @@ import { MenuButtonExample } from './MenuButton/examples/MenuButton.Example';
import { SplitButtonExample } from './SplitButton/examples/SplitButton.Example';
import { ButtonSlotsExample } from './examples/Button.Slots.Example';
import { ButtonStylesExample } from './examples/Button.Styles.Example';
import { ButtonToggleExample } from './examples/Button.Toggle.Example';
import { ButtonTokensExample } from './examples/Button.Tokens.Example';
import { ButtonVariantsExample } from './examples/Button.Variants.Example';

Expand All @@ -14,6 +15,7 @@ const MenuButtonExampleCode = require('!raw-loader!@uifabric/experiments/src/com
const SplitButtonExampleCode = require('!raw-loader!@uifabric/experiments/src/components/Button/SplitButton/examples/SplitButton.Example.tsx') as string;
const ButtonSlotsExampleCode = require('!raw-loader!@uifabric/experiments/src/components/Button/examples/Button.Slots.Example.tsx') as string;
const ButtonStylesExampleCode = require('!raw-loader!@uifabric/experiments/src/components/Button/examples/Button.Styles.Example.tsx') as string;
const ButtonToggleExampleCode = require('!raw-loader!@uifabric/experiments/src/components/Button/examples/Button.Toggle.Example.tsx') as string;
const ButtonTokensExampleCode = require('!raw-loader!@uifabric/experiments/src/components/Button/examples/Button.Tokens.Example.tsx') as string;
const ButtonVariantsExampleCode = require('!raw-loader!@uifabric/experiments/src/components/Button/examples/Button.Tokens.Example.tsx') as string;

Expand All @@ -37,6 +39,9 @@ export class ButtonPage extends React.Component<IComponentDemoPageProps, {}> {
<ExampleCard title="Button Variants Examples" code={ButtonVariantsExampleCode}>
<ButtonVariantsExample />
</ExampleCard>
<ExampleCard title="Toggle Buttons" code={ButtonToggleExampleCode}>
<ButtonToggleExample />
</ExampleCard>
<ExampleCard title="Button Slots Customization" code={ButtonSlotsExampleCode}>
<ButtonSlotsExample />
</ExampleCard>
Expand Down
Expand Up @@ -60,7 +60,7 @@ export interface IMenuButton {
*/
export interface IMenuButtonProps
extends IMenuButtonSlots,
Pick<IButtonProps, 'href' | 'primary' | 'disabled' | 'onClick' | 'allowDisabledFocus' | 'ariaLabel'>,
Pick<IButtonProps, 'href' | 'primary' | 'disabled' | 'onClick' | 'checked' | 'allowDisabledFocus' | 'ariaLabel'>,
IStyleableComponentProps<IMenuButtonProps, IMenuButtonTokens, IMenuButtonStyles>,
IBaseProps<IMenuButton> {
/**
Expand Down
Expand Up @@ -69,7 +69,16 @@ export interface ISplitButtonProps
extends ISlottableProps<ISplitButtonSlots>,
Pick<
IMenuButtonProps,
'href' | 'primary' | 'disabled' | 'onClick' | 'allowDisabledFocus' | 'ariaLabel' | 'defaultExpanded' | 'expanded' | 'onKeyDown'
| 'href'
| 'primary'
| 'disabled'
| 'onClick'
| 'checked'
| 'allowDisabledFocus'
| 'ariaLabel'
| 'defaultExpanded'
| 'expanded'
| 'onKeyDown'
>,
IStyleableComponentProps<ISplitButtonProps, ISplitButtonTokens, ISplitButtonStyles>,
IBaseProps<ISplitButton> {
Expand Down
@@ -0,0 +1,75 @@
import * as React from 'react';
import { Button } from '../index';
import { Stack, IStackTokens } from 'office-ui-fabric-react';

export interface IButtonToggleExampleState {
defaultButtonToggled?: boolean;
primaryButtonToggled?: boolean;
defaultCircularButtonToggled?: boolean;
primaryCircularButtonToggled?: boolean;
}

// tslint:disable:jsx-no-lambda
export class ButtonToggleExample extends React.Component<{}, IButtonToggleExampleState> {
constructor(props: {}) {
super(props);

this.state = {
defaultButtonToggled: false,
primaryButtonToggled: false,
defaultCircularButtonToggled: false,
primaryCircularButtonToggled: false
};
}

public render(): JSX.Element {
const { defaultButtonToggled, primaryButtonToggled, defaultCircularButtonToggled, primaryCircularButtonToggled } = this.state;

const buttonStackTokens: IStackTokens = { childrenGap: 12 };

return (
<Stack horizontal disableShrink tokens={buttonStackTokens}>
<Button
content={defaultButtonToggled ? 'Muted' : 'Unmuted'}
checked={defaultButtonToggled}
onClick={this._onDefaultButtonClicked}
/>
<Button
primary
content={primaryButtonToggled ? 'Muted' : 'Unmuted'}
checked={primaryButtonToggled}
onClick={this._onPrimaryButtonClicked}
/>
<Button
circular
icon={defaultCircularButtonToggled ? 'VolumeDisabled' : 'Volume3'}
checked={defaultCircularButtonToggled}
onClick={this._onDefaultCircularButtonClicked}
/>
<Button
circular
primary
icon={primaryCircularButtonToggled ? 'VolumeDisabled' : 'Volume3'}
checked={primaryCircularButtonToggled}
onClick={this._onPrimaryCircularButtonClicked}
/>
</Stack>
);
}

private _onDefaultButtonClicked = () => {
this.setState({ defaultButtonToggled: !this.state.defaultButtonToggled });
};

private _onPrimaryButtonClicked = () => {
this.setState({ primaryButtonToggled: !this.state.primaryButtonToggled });
};

private _onDefaultCircularButtonClicked = () => {
this.setState({ defaultCircularButtonToggled: !this.state.defaultCircularButtonToggled });
};

private _onPrimaryCircularButtonClicked = () => {
this.setState({ primaryCircularButtonToggled: !this.state.primaryCircularButtonToggled });
};
}

0 comments on commit 65d3dec

Please sign in to comment.