Skip to content

Commit

Permalink
add compound button as new v3 component (#27407)
Browse files Browse the repository at this point in the history
* add compound button as a new web component

* change files

* update locc css

* remove icon ref in stories

* remove icon attr in stories and address vertical alignment of buttons

* fix disabled primary styles
  • Loading branch information
chrisdholt committed Apr 11, 2023
1 parent b3e8544 commit 37195a3
Show file tree
Hide file tree
Showing 12 changed files with 514 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "feat(compound-button): add compound button as new web component",
"packageName": "@fluentui/web-components",
"email": "chhol@microsoft.com",
"dependentChangeType": "patch"
}
4 changes: 4 additions & 0 deletions packages/web-components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@
"types": "./dist/esm/button/define.d.ts",
"default": "./dist/esm/button/define.js"
},
"./compound-button": {
"types": "./dist/esm/compound-button/define.d.ts",
"default": "./dist/esm/compound-button/define.js"
},
"./counter-badge": {
"types": "./dist/esm/counter-badge/define.d.ts",
"default": "./dist/esm/counter-badge/define.js"
Expand Down
1 change: 1 addition & 0 deletions packages/web-components/src/button/button.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export const styles = css`
:host {
--icon-spacing: ${spacingHorizontalSNudge};
contain: layout style;
vertical-align: middle;
}
:host .control {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { FluentDesignSystem } from '../fluent-design-system.js';
import { CompoundButton } from './compound-button.js';
import { styles } from './compound-button.styles.js';
import { template } from './compound-button.template.js';

/**
* The Fluent Compound Button Element. Implements {@link @microsoft/fast-foundation#Button },
* {@link @microsoft/fast-foundation#buttonTemplate}
*
* @public
* @remarks
* HTML Element: \<fluent-comopund-button\>
*/
export const definition = CompoundButton.compose({
name: `${FluentDesignSystem.prefix}-compound-button`,
template,
styles,
shadowOptions: {
delegatesFocus: true,
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { ButtonOptions, ValuesOf } from '@microsoft/fast-foundation';
import { ButtonAppearance, ButtonShape, ButtonSize } from '../button/button.options.js';

/**
* Compound Button Appearance constants
* @public
*/
export const CompoundButtonAppearance = ButtonAppearance;

/**
* A Compound Button can be secondary, primary, outline, subtle, transparent
* @public
*/
export type CompoundButtonAppearance = ValuesOf<typeof CompoundButtonAppearance>;

/**
* A Compound Button can be square, circular or rounded.
* @public
*/
export const CompoundButtonShape = ButtonShape;

/**
* A Compound Button can be square, circular or rounded
* @public
*/
export type CompoundButtonShape = ValuesOf<typeof CompoundButtonShape>;

/**
* A Compound Button can be a size of small, medium or large.
* @public
*/
export const CompoundButtonSize = ButtonSize;

/**
* A Compound Button can be on of several preset sizes.
* @public
*/
export type CompoundButtonSize = ValuesOf<typeof CompoundButtonSize>;

export { ButtonOptions as CompoundButtonOptions };
239 changes: 239 additions & 0 deletions packages/web-components/src/compound-button/compound-button.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
import { html } from '@microsoft/fast-element';
import type { Args, Meta } from '@storybook/html';
import { renderComponent } from '../helpers.stories.js';
import type { CompoundButton as FluentCompoundButton } from './compound-button.js';
import { CompoundButtonAppearance, CompoundButtonShape, CompoundButtonSize } from './compound-button.options.js';
import './define.js';

type CompoundButtonStoryArgs = Args & FluentCompoundButton;
type CompoundButtonStoryMeta = Meta<CompoundButtonStoryArgs>;

const storyTemplate = html<CompoundButtonStoryArgs>`
<fluent-compound-button
appearance="${x => x.appearance}"
shape="${x => x.shape}"
size="${x => x.size}"
?disabled="${x => x.disabled}"
?disabled-focusable="${x => x.disabledFocusable}"
?icon-only="${x => x.iconOnly}"
>
${x => x.content}
<span slot="description">${x => x.description}</span>
</fluent-compound-button>
`;

export default {
title: 'Components/Button/Compound Button',
args: {
content: 'Button',
description: 'Secondary content',
disabled: false,
disabledFocusable: false,
},
argTypes: {
appearance: {
options: Object.values(CompoundButtonAppearance),
control: {
type: 'select',
},
},
shape: {
options: Object.values(CompoundButtonShape),
control: {
type: 'select',
},
},
size: {
options: Object.values(CompoundButtonSize),
control: {
type: 'select',
},
},
disabled: {
control: 'boolean',
table: {
type: {
summary: 'Sets the disabled state of the component',
},
defaultValue: {
summary: 'false',
},
},
},
disabledFocusable: {
control: 'boolean',
table: {
type: {
summary: 'The component is disabled but still focusable',
},
defaultValue: {
summary: 'false',
},
},
},
content: {
control: 'Button text',
},
},
} as CompoundButtonStoryMeta;

export const Button = renderComponent(storyTemplate).bind({});

export const Appearance = renderComponent(html<CompoundButtonStoryArgs>`
<fluent-compound-button>Default<span slot="description">Description content</span></fluent-compound-button>
<fluent-compound-button appearance="primary"
>Primary<span slot="description">Description content</span></fluent-compound-button
>
<fluent-compound-button appearance="outline"
>Outline<span slot="description">Description content</span></fluent-compound-button
>
<fluent-compound-button appearance="subtle"
>Subtle<span slot="description">Description content</span></fluent-compound-button
>
<fluent-compound-button appearance="transparent"
>Transparent<span slot="description">Description content</span></fluent-compound-button
>
`);

export const Shape = renderComponent(html<CompoundButtonStoryArgs>`
<fluent-compound-button shape="rounded"
>Rounded<span slot="description">Description content</span></fluent-compound-button
>
<fluent-compound-button shape="circular"
>Circular<span slot="description">Description content</span></fluent-compound-button
>
<fluent-compound-button shape="square"
>Square<span slot="description">Description content</span></fluent-compound-button
>
`);

export const Size = renderComponent(html<CompoundButtonStoryArgs>`
<fluent-compound-button size="small">Small<span slot="description">Description content</span></fluent-compound-button>
<fluent-compound-button size="small"
><svg
fill="currentColor"
slot="start"
aria-hidden="true"
width="1em"
height="1em"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M14.5 3A2.5 2.5 0 0117 5.5v9a2.5 2.5 0 01-2.5 2.5h-9A2.5 2.5 0 013 14.5v-9A2.5 2.5 0 015.5 3h9zm0 1h-9C4.67 4 4 4.67 4 5.5v9c0 .83.67 1.5 1.5 1.5h9c.83 0 1.5-.67 1.5-1.5v-9c0-.83-.67-1.5-1.5-1.5zM7 11a1 1 0 110 2 1 1 0 010-2zm3 0a1 1 0 110 2 1 1 0 010-2zM7 7a1 1 0 110 2 1 1 0 010-2zm3 0a1 1 0 110 2 1 1 0 010-2zm3 0a1 1 0 110 2 1 1 0 010-2z"
fill="currentColor"
></path></svg
>Small with calendar icon<span slot="description">Description content</span></fluent-compound-button
>
<fluent-compound-button size="small" icon-only aria-label="Small icon only button"
><svg
fill="currentColor"
aria-hidden="true"
width="1em"
height="1em"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M14.5 3A2.5 2.5 0 0117 5.5v9a2.5 2.5 0 01-2.5 2.5h-9A2.5 2.5 0 013 14.5v-9A2.5 2.5 0 015.5 3h9zm0 1h-9C4.67 4 4 4.67 4 5.5v9c0 .83.67 1.5 1.5 1.5h9c.83 0 1.5-.67 1.5-1.5v-9c0-.83-.67-1.5-1.5-1.5zM7 11a1 1 0 110 2 1 1 0 010-2zm3 0a1 1 0 110 2 1 1 0 010-2zM7 7a1 1 0 110 2 1 1 0 010-2zm3 0a1 1 0 110 2 1 1 0 010-2zm3 0a1 1 0 110 2 1 1 0 010-2z"
fill="currentColor"
></path></svg
></fluent-compound-button>
<fluent-compound-button size="medium"
>Medium<span slot="description">Description content</span></fluent-compound-button
>
<fluent-compound-button size="medium"
><svg
fill="currentColor"
slot="start"
aria-hidden="true"
width="1em"
height="1em"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M14.5 3A2.5 2.5 0 0117 5.5v9a2.5 2.5 0 01-2.5 2.5h-9A2.5 2.5 0 013 14.5v-9A2.5 2.5 0 015.5 3h9zm0 1h-9C4.67 4 4 4.67 4 5.5v9c0 .83.67 1.5 1.5 1.5h9c.83 0 1.5-.67 1.5-1.5v-9c0-.83-.67-1.5-1.5-1.5zM7 11a1 1 0 110 2 1 1 0 010-2zm3 0a1 1 0 110 2 1 1 0 010-2zM7 7a1 1 0 110 2 1 1 0 010-2zm3 0a1 1 0 110 2 1 1 0 010-2zm3 0a1 1 0 110 2 1 1 0 010-2z"
fill="currentColor"
></path></svg
>Medium with calendar icon</fluent-compound-button
>
<fluent-compound-button size="medium" icon-only aria-label="Medium icon only button"
><svg
fill="currentColor"
aria-hidden="true"
width="1em"
height="1em"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M14.5 3A2.5 2.5 0 0117 5.5v9a2.5 2.5 0 01-2.5 2.5h-9A2.5 2.5 0 013 14.5v-9A2.5 2.5 0 015.5 3h9zm0 1h-9C4.67 4 4 4.67 4 5.5v9c0 .83.67 1.5 1.5 1.5h9c.83 0 1.5-.67 1.5-1.5v-9c0-.83-.67-1.5-1.5-1.5zM7 11a1 1 0 110 2 1 1 0 010-2zm3 0a1 1 0 110 2 1 1 0 010-2zM7 7a1 1 0 110 2 1 1 0 010-2zm3 0a1 1 0 110 2 1 1 0 010-2zm3 0a1 1 0 110 2 1 1 0 010-2z"
fill="currentColor"
></path></svg
></fluent-compound-button>
<fluent-compound-button size="large">Large<span slot="description">Description content</span></fluent-compound-button>
<fluent-compound-button size="large"
><svg
fill="currentColor"
slot="start"
aria-hidden="true"
width="1em"
height="1em"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M14.5 3A2.5 2.5 0 0117 5.5v9a2.5 2.5 0 01-2.5 2.5h-9A2.5 2.5 0 013 14.5v-9A2.5 2.5 0 015.5 3h9zm0 1h-9C4.67 4 4 4.67 4 5.5v9c0 .83.67 1.5 1.5 1.5h9c.83 0 1.5-.67 1.5-1.5v-9c0-.83-.67-1.5-1.5-1.5zM7 11a1 1 0 110 2 1 1 0 010-2zm3 0a1 1 0 110 2 1 1 0 010-2zM7 7a1 1 0 110 2 1 1 0 010-2zm3 0a1 1 0 110 2 1 1 0 010-2zm3 0a1 1 0 110 2 1 1 0 010-2z"
fill="currentColor"
></path></svg
>Large with calendar icon<span slot="description">Description content</span></fluent-compound-button
>
<fluent-compound-button size="large" icon-only aria-label="Large icon only button"
><svg
fill="currentColor"
aria-hidden="true"
width="1em"
height="1em"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M14.5 3A2.5 2.5 0 0117 5.5v9a2.5 2.5 0 01-2.5 2.5h-9A2.5 2.5 0 013 14.5v-9A2.5 2.5 0 015.5 3h9zm0 1h-9C4.67 4 4 4.67 4 5.5v9c0 .83.67 1.5 1.5 1.5h9c.83 0 1.5-.67 1.5-1.5v-9c0-.83-.67-1.5-1.5-1.5zM7 11a1 1 0 110 2 1 1 0 010-2zm3 0a1 1 0 110 2 1 1 0 010-2zM7 7a1 1 0 110 2 1 1 0 010-2zm3 0a1 1 0 110 2 1 1 0 010-2zm3 0a1 1 0 110 2 1 1 0 010-2z"
fill="currentColor"
></path></svg
></fluent-compound-button>
`);

export const Disabled = renderComponent(html<CompoundButtonStoryArgs>`
<fluent-compound-button>Enabled state<span slot="description">Description content</span></fluent-compound-button>
<fluent-compound-button disabled
>Disabled state<span slot="description">Description content</span></fluent-compound-button
>
<fluent-compound-button disabled-focusable
>Disabled focusable state<span slot="description">Description content</span></fluent-compound-button
>
<fluent-compound-button appearance="primary"
>Enabled state<span slot="description">Description content</span></fluent-compound-button
>
<fluent-compound-button appearance="primary" disabled
>Disabled state<span slot="description">Description content</span></fluent-compound-button
>
<fluent-compound-button appearance="primary" disabled-focusable
>Disabled focusable state<span slot="description">Description content</span></fluent-compound-button
>
`);

export const WithLongText = renderComponent(html<CompoundButtonStoryArgs>`
<style>
.max-width {
width: 280px;
}
</style>
<fluent-compound-button>Short text<span slot="description">Description content</span></fluent-compound-button>
<fluent-compound-button class="max-width"
>Long text wraps after it hits the max width of the component<span slot="description"
>Description content</span
></fluent-compound-button
>
`);
Loading

0 comments on commit 37195a3

Please sign in to comment.