Skip to content

Commit

Permalink
Slots: Refactor and add options structure for more rendering options. (
Browse files Browse the repository at this point in the history
…#8754)

* Refactor slots to provide more options for rendering content.

* Add Button slots customization example.

* PR feedback.

* Resolve todos.

* Change files.

* PR feedback.
  • Loading branch information
JasonGore committed Apr 24, 2019
1 parent e63e2f8 commit 14b1d77
Show file tree
Hide file tree
Showing 52 changed files with 976 additions and 504 deletions.
2 changes: 1 addition & 1 deletion apps/fabric-website/src/components/Nav/Nav.tsx
Expand Up @@ -121,7 +121,7 @@ export class Nav extends React.Component<INavProps, INavState> {
return (
<li key={page.title + '-heading'} className={css(styles.category, _hasActiveChild(page) && styles.hasActiveChild)}>
<CollapsibleSection
title={{ text: page.title, styles: getTitleStyles }}
title={{ props: { text: page.title, styles: getTitleStyles } }}
styles={{ body: [{ marginLeft: '28px' }] }}
defaultCollapsed={!_hasActiveChild(page)}
>
Expand Down
@@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "@uifabric/experiments",
"comment": "Changes to support slots API refactoring.",
"type": "minor"
}
],
"packageName": "@uifabric/experiments",
"email": "jagore@microsoft.com"
}
@@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "@uifabric/fabric-website",
"comment": "Changes to support slots API refactoring",
"type": "minor"
}
],
"packageName": "@uifabric/fabric-website",
"email": "jagore@microsoft.com"
}
@@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "@uifabric/foundation",
"comment": "Slots: Refactor API and add slot options object.",
"type": "minor"
}
],
"packageName": "@uifabric/foundation",
"email": "jagore@microsoft.com"
}
@@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "office-ui-fabric-react",
"comment": "Changes to support slots API refactoring.",
"type": "minor"
}
],
"packageName": "office-ui-fabric-react",
"email": "jagore@microsoft.com"
}
10 changes: 9 additions & 1 deletion packages/experiments/src/components/Button/ActionButton.tsx
Expand Up @@ -45,5 +45,13 @@ export const ActionButtonTokens: IButtonComponent['tokens'] = (props, theme): IB
export const ActionButton: ButtonVariantsType = props => {
const { text, iconProps, ...rest } = props;

return <Button stack={{ horizontalAlign: 'start' }} content={text} icon={iconProps} tokens={ActionButtonTokens} {...rest} />;
return (
<Button
stack={{ props: { horizontalAlign: 'start' } }}
content={text}
icon={{ props: iconProps }}
tokens={ActionButtonTokens}
{...rest}
/>
);
};
2 changes: 1 addition & 1 deletion packages/experiments/src/components/Button/BaseButton.tsx
Expand Up @@ -57,5 +57,5 @@ const BaseButtonStyles: IButtonComponent['styles'] = (props, theme, tokens): IBu
export const BaseButton: ButtonVariantsType = props => {
const { text, iconProps, ...rest } = props;

return <Button content={text} icon={iconProps} tokens={BaseButtonTokens} styles={BaseButtonStyles} {...rest} />;
return <Button content={text} icon={{ props: iconProps }} tokens={BaseButtonTokens} styles={BaseButtonStyles} {...rest} />;
};
4 changes: 3 additions & 1 deletion packages/experiments/src/components/Button/Button.types.tsx
Expand Up @@ -14,11 +14,13 @@ export type IButtonStylesReturnType = ReturnType<Extract<IButtonComponent['style

export type IButtonSlot = ISlotProp<IButtonProps>;

export type IButtonRootElements = 'a' | 'button' | 'div';

export interface IButtonSlots {
/**
* Defines the root slot of the component.
*/
root?: IHTMLElementSlot<'button'>;
root?: IHTMLElementSlot<IButtonRootElements>;

/**
* Defines the horizontal stack used for specifying the inner layout of the Button.
Expand Down
4 changes: 2 additions & 2 deletions packages/experiments/src/components/Button/Button.view.tsx
Expand Up @@ -4,7 +4,7 @@ import { withSlots, getSlots } from '../../Foundation';
import { getNativeProps, buttonProperties } from '../../Utilities';
import { Icon } from '../../utilities/factoryComponents';

import { IButtonComponent, IButtonProps, IButtonSlots, IButtonViewProps } from './Button.types';
import { IButtonComponent, IButtonProps, IButtonRootElements, IButtonSlots, IButtonViewProps } from './Button.types';

export const ButtonView: IButtonComponent['view'] = props => {
const { icon, content, children, disabled, onClick, ariaLabel, buttonRef, ...rest } = props;
Expand Down Expand Up @@ -49,6 +49,6 @@ export const ButtonView: IButtonComponent['view'] = props => {
);
};

function _deriveRootType(props: IButtonViewProps): keyof JSX.IntrinsicElements {
function _deriveRootType(props: IButtonViewProps): IButtonRootElements {
return !!props.href ? 'a' : 'button';
}
5 changes: 5 additions & 0 deletions packages/experiments/src/components/Button/ButtonPage.tsx
Expand Up @@ -4,13 +4,15 @@ import { ExampleCard, IComponentDemoPageProps, ComponentPage, PageMarkdown, Prop
import { ButtonExample } from './examples/Button.Example';
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 { ButtonTokensExample } from './examples/Button.Tokens.Example';
import { ButtonVariantsExample } from './examples/Button.Variants.Example';

const ButtonExampleCode = require('!raw-loader!@uifabric/experiments/src/components/Button/examples/Button.Example.tsx') as string;
const MenuButtonExampleCode = require('!raw-loader!@uifabric/experiments/src/components/Button/MenuButton/examples/MenuButton.Example.tsx') as string;
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 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 @@ -35,6 +37,9 @@ export class ButtonPage extends React.Component<IComponentDemoPageProps, {}> {
<ExampleCard title="Button Variants Examples" code={ButtonVariantsExampleCode}>
<ButtonVariantsExample />
</ExampleCard>
<ExampleCard title="Button Slots Customization" code={ButtonSlotsExampleCode}>
<ButtonSlotsExample />
</ExampleCard>
<ExampleCard title="Button Styles" code={ButtonStylesExampleCode}>
<ButtonStylesExample />
</ExampleCard>
Expand Down
Expand Up @@ -49,5 +49,5 @@ export const CommandBarButtonTokens: IButtonComponent['tokens'] = (props, theme)
export const CommandBarButton: ButtonVariantsType = props => {
const { text, iconProps, ...rest } = props;

return <Button content={text} icon={iconProps} tokens={CommandBarButtonTokens} {...rest} />;
return <Button content={text} icon={{ props: iconProps }} tokens={CommandBarButtonTokens} {...rest} />;
};
4 changes: 2 additions & 2 deletions packages/experiments/src/components/Button/CompoundButton.tsx
Expand Up @@ -103,9 +103,9 @@ export const CompoundButton: CompoundButtonType = props => {

return (
<Button
stack={{ as: 'span', horizontal: false, horizontalAlign: 'start', tokens: stackTokens }}
stack={{ props: { as: 'span', horizontal: false, horizontalAlign: 'start', tokens: stackTokens } }}
content={text}
icon={iconProps}
icon={{ props: iconProps }}
styles={CompoundButtonStyles}
tokens={CompoundButtonTokens}
{...rest}
Expand Down
Expand Up @@ -5,5 +5,5 @@ import { ButtonVariantsType } from './ButtonVariants.types';
export const DefaultButton: ButtonVariantsType = props => {
const { text, iconProps, ...rest } = props;

return <Button content={text} icon={iconProps} {...rest} />;
return <Button content={text} icon={{ props: iconProps }} {...rest} />;
};
2 changes: 1 addition & 1 deletion packages/experiments/src/components/Button/IconButton.tsx
Expand Up @@ -42,5 +42,5 @@ export const IconButtonTokens: IButtonComponent['tokens'] = (props, theme): IBut
export const IconButton: ButtonVariantsType = props => {
const { text, iconProps, ...rest } = props;

return <Button circular icon={iconProps} tokens={IconButtonTokens} {...rest} />;
return <Button circular icon={{ props: iconProps }} tokens={IconButtonTokens} {...rest} />;
};
Expand Up @@ -6,16 +6,18 @@ import { MenuButton } from './MenuButton';
import { IMenuButtonProps } from './MenuButton.types';

const menuProps: IMenuButtonProps['menu'] = {
items: [
{
key: 'a',
name: 'Item a'
},
{
key: 'b',
name: 'Item b'
}
]
props: {
items: [
{
key: 'a',
name: 'Item a'
},
{
key: 'b',
name: 'Item b'
}
]
}
};

describe('MenuButton view', () => {
Expand Down
@@ -1,4 +1,4 @@
import { IComponent, IComponentStyles, IHTMLElementSlot, ISlotProp, IStyleableComponentProps } from '../../../Foundation';
import { IComponent, IComponentStyles, ISlotProp, IStyleableComponentProps } from '../../../Foundation';
import { IContextualMenuSlot, IIconSlot } from '../../../utilities/factoryComponents.types';
import { IBaseProps } from '../../../Utilities';
import { IButtonProps, IButtonSlot, IButtonSlots, IButtonTokens, IButtonViewProps } from '../Button.types';
Expand All @@ -14,11 +14,6 @@ export type IMenuButtonStylesReturnType = ReturnType<Extract<IMenuButtonComponen
export type IMenuButtonSlot = ISlotProp<IMenuButtonProps>;

export interface IMenuButtonSlots extends IButtonSlots {
/**
* Defines the root slot of the component.
*/
root?: IHTMLElementSlot<'div'>;

/**
* Defines the button that is going to be rendered.
*/
Expand Down
Expand Up @@ -3,16 +3,18 @@ import { MenuButton, IMenuButtonProps } from '@uifabric/experiments';
import { Stack, Text } from 'office-ui-fabric-react';

const menuProps: IMenuButtonProps['menu'] = {
items: [
{
key: 'a',
name: 'Item a'
},
{
key: 'b',
name: 'Item b'
}
]
props: {
items: [
{
key: 'a',
name: 'Item a'
},
{
key: 'b',
name: 'Item b'
}
]
}
};

const tokens = {
Expand Down
Expand Up @@ -43,5 +43,5 @@ export const MessageBarButtonTokens: IButtonComponent['tokens'] = (props, theme)
export const MessageBarButton: ButtonVariantsType = props => {
const { text, iconProps, ...rest } = props;

return <Button content={text} icon={iconProps} tokens={MessageBarButtonTokens} {...rest} />;
return <Button content={text} icon={{ props: iconProps }} tokens={MessageBarButtonTokens} {...rest} />;
};
Expand Up @@ -5,5 +5,5 @@ import { ButtonVariantsType } from './ButtonVariants.types';
export const PrimaryButton: ButtonVariantsType = props => {
const { text, iconProps, ...rest } = props;

return <Button primary content={text} icon={iconProps} {...rest} />;
return <Button primary content={text} icon={{ props: iconProps }} {...rest} />;
};
Expand Up @@ -5,16 +5,18 @@ import { SplitButton } from './SplitButton';
import { ISplitButtonProps } from './SplitButton.types';

const menuProps: ISplitButtonProps['menu'] = {
items: [
{
key: 'a',
name: 'Item a'
},
{
key: 'b',
name: 'Item b'
}
]
props: {
items: [
{
key: 'a',
name: 'Item a'
},
{
key: 'b',
name: 'Item b'
}
]
}
};

describe('SplitButton view', () => {
Expand Down
Expand Up @@ -3,16 +3,18 @@ import { SplitButton, ISplitButtonProps } from '@uifabric/experiments';
import { Stack } from 'office-ui-fabric-react';

const menuProps: ISplitButtonProps['menu'] = {
items: [
{
key: 'a',
name: 'Item a'
},
{
key: 'b',
name: 'Item b'
}
]
props: {
items: [
{
key: 'a',
name: 'Item a'
},
{
key: 'b',
name: 'Item b'
}
]
}
};

const tokens = {
Expand Down
Expand Up @@ -30,38 +30,36 @@ export class ButtonExample extends React.Component<{}, {}> {
return (
<Stack tokens={tokens.sectionStack}>
<Stack tokens={tokens.headingStack} padding={8}>
<div>
<Stack tokens={tokens.buttonStack}>
<ButtonStack>
<Button content="Default button" onClick={alertClicked} />
<Button disabled content="Disabled default button" onClick={alertClicked} />
<Button primary content="Primary button" onClick={alertClicked} />
<Button primary disabled content="Disabled primary button" onClick={alertClicked} />
</ButtonStack>
<ButtonStack>
<Button icon="PeopleAdd" circular />
<Button icon="Phone" circular disabled />
<Button icon="FontSize" circular primary />
<Button icon="Attach" circular primary disabled />
</ButtonStack>
<ButtonStack>
<Button icon="Upload" content="Button with string icon" />
<Button icon={{ iconName: 'Share' }} content="Button with iconProps" />
<Button icon={() => <Icon iconName="Download" />} content="Button with icon render function" />
</ButtonStack>
<ButtonStack>
<Button>
<Icon iconName="Upload" />
<Text>With custom text/icon</Text>
</Button>
<Button primary>
<Text>With custom text/icon right aligned</Text>
<Icon iconName="Upload" />
</Button>
</ButtonStack>
<CommandBar items={[{ key: '0', text: 'Button 1', iconProps: { iconName: 'Upload' } }]} />
</Stack>
</div>
<Stack tokens={tokens.buttonStack}>
<ButtonStack>
<Button content="Default button" onClick={alertClicked} />
<Button disabled content="Disabled default button" onClick={alertClicked} />
<Button primary content="Primary button" onClick={alertClicked} />
<Button primary disabled content="Disabled primary button" onClick={alertClicked} />
</ButtonStack>
<ButtonStack>
<Button icon="PeopleAdd" circular />
<Button icon="Phone" circular disabled />
<Button icon="FontSize" circular primary />
<Button icon="Attach" circular primary disabled />
</ButtonStack>
<ButtonStack>
<Button icon="Upload" content="Button with string icon" />
<Button icon={{ props: { iconName: 'Share' } }} content="Button with iconProps" />
<Button icon={{ render: () => <Icon iconName="Download" /> }} content="Button with icon render function" />
</ButtonStack>
<ButtonStack>
<Button>
<Icon iconName="Upload" />
<Text>With custom text/icon</Text>
</Button>
<Button primary>
<Text>With custom text/icon right aligned</Text>
<Icon iconName="Upload" />
</Button>
</ButtonStack>
<CommandBar items={[{ key: '0', text: 'Button 1', iconProps: { iconName: 'Upload' } }]} />
</Stack>
</Stack>
</Stack>
);
Expand Down

0 comments on commit 14b1d77

Please sign in to comment.